一、案例
校验豆瓣网验证码逻辑
- 创建webdriver.Chrome对象,并请求登录的url (driver对象提升为全局变量到main方法当中)
- 页面加载等待(20)秒
- 输入账号与(错误的密码),多次登录,使其弹出验证码
- 判断验证码是否弹出
5. 如果弹出就解决
5.1 点住滑块,悬浮
5.2 找到滑块距离,找规律
5.3 点住滑块,移动滑块距离
5.4 点住滑块,到指定位置后,松开滑块
6. 判断登录后标签的状态是否改变,改变就代表登录成功
豆瓣网代码
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
def get_tracks(distance):
'''
模仿先加速后减速的过程
:param distance: 移动的距离
:return: 列表
'''
#当前速度
v = 0
#定义时间间隔
t = 0.3
tracks = []
#当前距离
current = 0
#加速和减速的分割线
mid = distance*3/5
while current < distance:
#定义加速度
if current < mid:
a = 2
else:
a = -3
#移动了
#定义初速度
v0 = v
s = v0*t+0.5*a*t*t
current += s
#保持移动的时候有效果
#0.1个像素。像素不能是小数
tracks.append(round(s))
#设置当前速度
v = v0+a*t
return tracks
def sliding_code(driver):
'''
处理滑动验证码
:param driver: 出现验证码的driver对象
:return: True-->解决了
'''
print('开始处理滑动验证码!')
# 发现验证码的部分就是一个iframe标签,切入frame
driver.switch_to.frame(0)
# 1、先找到滑块,鼠标点他,悬浮 滑块在xpath路径是滑块最外层
slider = driver.find_element_by_xpath('//*[@id="tcaptcha_drag_button"]')
# print(slider)
# 2、先找到滑动距离---任何一个问题解决思路--通过测量得到220
# ActionChains(driver):创建一个鼠标动作链---绑定driver(参数)上的
# click_and_hold:点击并保持(参数表示点谁)
# perform:悬浮
# 3、点住他,水平移动(移动一定的距离)---距离到底是多少
while True:
ActionChains(driver).click_and_hold(on_element=slider).perform()
# 滑动:先闪现100
ActionChains(driver).move_by_offset(xoffset=100, yoffset=0).perform()
# 剩余的123模拟加速后减速的过程
tracks = get_tracks(123)
# print(tracks)
for s in tracks:
ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
# 4、放开鼠标即可
ActionChains(driver).release().perform()
if driver.title != '登录豆瓣':
break
time.sleep(1)
# 点击刷新图片
driver.find_element_by_xpath('//*[@id="reload"]').click()
time.sleep(2)
# 网络恍惚了一下:滑动的太快了
# 滑动要符合人的滑动习惯:先加速,后减速
def login():
# chrome也是可以设置请求头
options = webdriver.ChromeOptions()
# 设置中文
options.add_argument('lang=zh_CN.UTF-8')
# 更换头部
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'
options.add_argument('user-agent="%s"' % ua)
# 创建driver
driver = webdriver.Chrome(chrome_options=options)
# https://www.douban.com/people/214807783/
# driver.get('https://www.douban.com/')
driver.get('https://accounts.douban.com/passport/login')
# 等待
driver.implicitly_wait(20)
# 1、点击使用密码登录
# iframe:框架标签。---他也是一个完整的html
# 便于html代码的管理和开发
# 如果遇到iframe标签记得要切入进去在获取
# 0:切入到第一个
# driver.switch_to.frame(0)
# 在页面当中找到 密码登录,并复制他的xpath路径
driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]').click()
# 2、输入用户名和密码
driver.find_element_by_xpath('//*[@id="username"]').send_keys('输入豆瓣网注册账号')
driver.find_element_by_xpath('//*[@id="password"]').send_keys('输入豆瓣网登陆密码')
# 3、点击登录
driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a').click()
time.sleep(4)
print(driver.title)
# 4、判断(是否出现滑动验证码)
if driver.title == '登录豆瓣':
#出现了验证码
if sliding_code(driver):
print('登录成功!')
else:
print('登录成功!')
if __name__ == '__main__':
login()
注意技术点:
当在处理滑块移动的时候,由于是机器移动,速度会非常的快,会出现网络恍惚的情况
因此,我们要写一个get_tracks方法,使计算机去模仿人的行为去滑动验证码。
平时我们滑动验证码的时候都是先快速拉取,即将要到指定位置的时候,速度会慢下来,直到滑动验证码块重合。
校验博客园验证码逻辑
- 创建webdriver.Chrome对象,并请求登录的url (driver对象提升为全局变量到main方法当中)
- 页面加载等待(20)秒
- 输入账号与(错误的密码),多次登录,使其弹出验证码
- 判断验证码是否弹出
- 如果弹出就解决
5.1 点住滑块,悬浮
5.2 找到滑块距离,找规律
因此,我们需要另一种处理方式,抠图
5.3 点住滑块,移动滑块距离
5.4 点住滑块,到指定位置后,松开滑块 - 判断登录后标签的状态是否改变,改变就代表登录成功
博客园代码
import time
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
def isSimilar(image1,image2,x,y):
'''
比较两种图片在(x,y)坐标点位置的像素值是否一样
:param image1:
:param image2:
:param x:
:param y:
:return: True->一样
'''
#获取图片在x,y位置的像素值
pixel1 = image1.getpixel((x,y))
pixel2 = image2.getpixel((x,y))
# print(pixel1,pixel2)
#计算要考虑误差的影响
if abs(pixel1[0]-pixel2[0]) >= 20 and abs(pixel1[1]-pixel2[1])>=20 and abs(pixel1[2]-pixel2[2])>=20:
print(pixel1,pixel2)#(49, 81, 63, 255) (80, 120, 100, 255)
return False
return True
def get_distance(image1,image2):
'''
通过对比两张一样的图片,获取不一样点的坐标
:param image1:
:param image2:
:return: (x,y)
'''
#比较是比较每个坐标点的像素值
#这两种图片是一样大小的
for i in range(198):#x轴
for j in range(154):
#(i,j)--->图片上的每个坐标点
if isSimilar(image1,image2,i,j)==False:
return (i,j)
return -1
def get_tracks(distance):
'''
模仿先加速后减速的过程
:param distance: 移动的距离
:return: 列表
'''
#当前速度
v = 0
#定义时间间隔
t = 0.3
tracks = []
#当前距离
current = 0
#加速和减速的分割线
mid = distance*3/5
while current < distance:
#定义加速度
if current < mid:
a = 2
else:
a = -3
#移动了
#定义初速度
v0 = v
s = v0*t+0.5*a*t*t
current += s
#保持移动的时候有效果
#0.1个像素。像素不能是小数
tracks.append(round(s))
#设置当前速度
v = v0+a*t
return tracks
def login_verify(driver):
'''
解决验证码
:param driver: 出现验证码的浏览器对象
:return: True--->解决了验证码
'''
print('出现滑动验证码,开始处理滑动验证码!')
#1、获取滑块
slider = driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')
# 最大化浏览器
driver.maximize_window()
yz_element = driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]')
# print(yz_element.location)#位置(左上角的坐标(x,y))
# print(yz_element.size)#元素的大小
top = yz_element.location['y']
left = yz_element.location['x']
right = left + yz_element.size['width']
bottom = top + yz_element.size['height']
while True:
#2、计算移动的距离
# (1)得到有缺口的图tu1和无缺口的图tu2
# 截图保存有缺口的图片完整图片
driver.save_screenshot('quan_quekou.png')
image_qk = Image.open('quan_quekou.png')
image1 = image_qk.crop((left+60,top+5,right,bottom))
# image2.show()
image1.save('imaeg1.png')
#该canvas画布的属性:让其出现无缺的原图
driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display: block"')
#截图
driver.save_screenshot('quan_wuque.png')
image2 = Image.open('quan_wuque.png').crop((left+60,top+5,right,bottom))
image2.save('image2.png')
#(2)比较两张图片的内容,获取距离
#不一样的坐标点(x,y)
location= get_distance(image1,image2)
print(location)
# 3、使用鼠标动作链进行点击并悬浮
ActionChains(driver).click_and_hold(on_element=slider).perform()
# 先移动一半
ActionChains(driver).move_by_offset(xoffset=(location[0] + 58) / 2, yoffset=0).perform()
# 4、鼠标拖动并保持悬浮移动--->先加速后减速的过程
# 剩下的一半:做先加速后减速的过程
tracks = get_tracks((location[0] + 58) / 2)
for s in tracks:
ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
# 5、释放鼠标--保持悬浮
ActionChains(driver).release().perform()
time.sleep(3)
if '用户登录' not in driver.title:
break
#点击刷新验证码
driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[2]/div/a[2]').click()
time.sleep(1)
return True
if __name__ == '__main__':
driver = webdriver.Chrome()
driver.get('https://account.cnblogs.com/signin?returnUrl=https%3A%2F%2Fwww.cnblogs.com%2F')
#隐式等待
driver.implicitly_wait(20)
#输入用户名和密码
driver.find_element_by_xpath('//*[@id="LoginName"]').send_keys('输入博客园账号')
driver.find_element_by_xpath('//*[@id="Password"]').send_keys('输入博客园密码')
#点击登录按钮
driver.find_element_by_xpath('//*[@id="submitBtn"]').click()
time.sleep(2)
#判断是否登录成功,不成功就解决验证码
if '学途_w' in driver.page_source:
print('登录成功')
else:
if login_verify(driver):
print('登录成功!')
注意技术点:
由于每次弹出的滑动验证码距离不同,因此我们需要算出滑块需要移动的距离,所以我们要选择抠图解析的方式。
首先我们通过driver对象去截图有缺口的验证码图,并且筛选出来滑块的大小,进行再次的裁剪。
然后我们将截取后的图1还原成无缺的原图。
最后我们要移动的距离就是 滑块的宽度+ 有缺口图1与无缺口图2的像素值。