selenium模拟登录京东M站
2019-05-16 本文已影响0人
Judy警官
最近几天在研究如果模拟登录京东m站,主要难点是如何识别验证码。在现有的图像识别库的基础上做了些工作,最终能够100%识别验证码。这里有以下几点体会:
-
在做一件事之前,要研究这件事的可行性。如果做到一半才发现不可实现,那真的是浪费了生命了。具体就是看主要步骤的技术是否能实现。
-
研究一件事情的时候,真的需要多次的试验和探索,要有耐心。我在这个过程各种改数据,各种求教google老师。
-
以下用到了几个知识点:selenium、图像识别库函数PIL\cv2\aircv、Javascript、屏幕大小和网页大小的概念、异常处理
具体说明已经在源码的注释中标明:
#coding=utf-8
from seleniumimport webdriver
import time
from PILimport Image
import cv2
import aircvas ac
from selenium.webdriver.common.action_chainsimport ActionChains
#访问要自动登录的网站的登录页面
browser=webdriver.Chrome()
browser.get("https://plogin.m.jd.com/user/login.action")
browser.find_element_by_xpath('//input[@id="username"]').send_keys("yaqingirl")
browser.find_element_by_xpath('//input[@id="password"]').send_keys("123456")
browser.find_element_by_xpath('//a[@id="loginBtn"]').click()
time.sleep(3)
# 该方法作用是:在图img中,pos的位置画一个半径为circle_radius的圆,颜色为color,笔粗为line_width
def draw_circle(img, pos, circle_radius, color, line_width):
result_img = cv2.circle(img, pos, circle_radius, color, line_width)
# 这三行代码可以让result_img图片展示在屏幕上,按任意键结束展示
# cv2.imshow('objDetect', result_img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
return result_img
def Simulated_login():
#截取带验证码的登录页面,保存为im.png(本文的目标网站的登录验证码方式是在大图中点击目标小图)
browser.maximize_window()#本人是mac pro 15.4英寸,最大化chrome窗口后,截图大小为3360*1664
browser.save_screenshot(r'img/im.png')
#用PIL库操作图片
im=Image.open(r'img/im.png')
#灰度化,保存为im_grey.png
im_grey=im.convert('L')
im_grey.save(r'img/im_grey.png')
#在im.png图中截取目标小图(验证码图片):im_crop.png
#不同大小的显示器可能不同,需要自己手动算一下,计算方法就是在画图工具中看下验证码图片左上角坐标和右下角坐标。可能需要多次试验才能准确截取
im_crop=im.crop((2330,1350,2384,1410))
im_crop.save(r'img/im_crop.png')
im_crop_grey=im_crop.convert('L')#灰度化
im_crop_grey.save(r'img/im_crop_grey.png')
#以上是准备要用到图片,下面是找出验证码在网页中的坐标,并模拟点击,以通过验证码校验
#以下步骤是:在im_grey.png图中的场景图片中找出im_crop_grey.png图一样的图案(这里注意,是在im_grey.png中上半部分场景中去找),并画一个圈
#1.因为im_grey.png图的场景图片中目标图案比较大,所以要缩小im_grey.png图,保存为result.png,缩小的倍数需要手工计算一下(多试几组值,观察
# 缩小后的result.png中的目标图是否与im_crop.png长和宽相差不大即可)
#2.找出目标图im_crop_grey.png在result.png的位置,并画一个圈,保存为result_img1.png
#3.按比例计算目标图im_crop.png在im_grey原始图中的位置,并画一个圈
#4.使用3中找到的坐标在网页上进行模拟点击
#下面是步骤1、2
#我的im_grey.png原始大小是3360*1664,计算后需要缩小2.89倍
res = cv2.resize(cv2.imread(r'img/im_grey.png'), (1162,576), interpolation=cv2.INTER_CUBIC)#该方法可缩放扶贫
cv2.imwrite(r'img/result.png', res)#保存缩小后的图片
imsrc = ac.imread(r'img/result.png')
imobj = ac.imread(r'img/im_crop_grey.png')
# find the match position
try:
pos = ac.find_template(imsrc, imobj)#该方法很厉害,能够找到jmobj在imsrc中的坐标位置。如果找不到返回None
circle_center_pos = (int(pos['result'][0]),int(pos['result'][1]))
except TypeError as e:
print('没有定位到,请重试!')
#定义一些花圈的参数
circle_radius =25
color = (0, 255, 0)
line_width =3
#为方便调试打印下坐标
print(circle_center_pos)
#画圈,并保存画圈后的图片
result_img1=draw_circle(imsrc, circle_center_pos, circle_radius, color, line_width)
cv2.imwrite(r'img/result_img1.png', result_img1)
#下面是步骤3:
#以上计算的坐标是在缩小2.89倍以后的图片上,想要计算计算在原始图中的坐标需要把坐标*2.89
real_pos=(int(pos['result'][0]*2.89),int(pos['result'][1]*2.89))
print(real_pos)
result_img2=draw_circle(ac.imread(r'img/im_grey.png'), real_pos, circle_radius, color, line_width)
cv2.imwrite(r'img/result_img2.png', result_img2)
#下面是步骤4:
#im.png大小是3360*1664,浏览器最大化的大小是1680*832,刚好截图大小是网页中html大小的两倍,所以坐标需要除以2
##但是由于浏览器最大化,im.png的分辨率太大,导致定位稍微不准确就不能定位,需要优化,失败后可多次重试定位
menu = browser.find_element_by_xpath("/html")
actions = ActionChains(browser)
# actions.move_by_offset(real_pos[0],real_pos[1])
print('在浏览器中点击位置:'+str(int(real_pos[0]/2))+','+str(int(real_pos[1]/2)))
actions.move_to_element_with_offset(menu,int(real_pos[0]/2),int(real_pos[1]/2))#把坐标挪到定位好的坐标上
#执行这段js可以弹框显示鼠标点击的坐标
js='''document.onclick=function getMousePos(event) {
# var e = event || window.event;
# x=e.clientX;
# y=e.clientY;
# alert(x+','+y);
# };'''
# #调用js
# browser.execute_script(js)
#点击定位好的坐标
actions.click()
actions.perform()
# 如果成功(browser.find_element_by_xpath('//*[@id="captcha"]/div[1]')抛出异常),则结束
# 否则失败,就重试
while(1):
Simulated_login()
try:
element = browser.find_element_by_xpath('//*[@id="captcha"]/div[1]')
except Exception as e:
print("登录成功!")
break
#browser.close()