Python(爬虫篇)--- 验证码破解【二】滑块验证码


解决滑块验证码思路:

  1. 找到滑块,按住鼠标
  2. 拖动滑块到指定位置
  3. 释放鼠标

案例:豆瓣登录

使用的技术:

(1)selenium+Chrome 浏览器完成自动登录
(2)使用 ActionChains 控制鼠标操作(鼠标按住—鼠标拖动—鼠标释放)
(3)使用物理知识(加速度)模拟人的拖动轨迹(先加速后减速)

代码实现:

步骤一:进入首页,点击密码登录
在这里插入图片描述

代码:

from selenium import webdriver

# 调用浏览器
driver = webdriver.Chrome(executable_path=r'D:\chrome\chromedriver.exe')

# 最大化窗口
driver.maximize_window()

# 请求
driver.get(url='https://www.douban.com/')

# 点击密码登录
driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()

出现问题:没有点击到密码登录,而是点击了电影

分析可能的原因:

  1. 页面没有加载完成就点击,可以通过time模块休眠排除
  2. xpath的路径指定到了电影,路径有问题,仔细检查可排除
  3. 是因为iframe标签:在主页面中嵌套一个子页面

解决问题:
经排除,是因为上述的原因3导致
切入到子页面中:switch_to.frame(0) 切入到iframe中
0代表第一个iframe标签

driver.switch_to.frame(0)
driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()

步骤二:输入信息,点击登录

代码:

# 查找并输入账号
driver.find_element_by_id('username').send_keys('18524158889')
# 查找并输入密码
driver.find_element_by_id('password').send_keys('11111111')
# 查找并点击登录
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]').click()

步骤三:出现滑块验证码,移动滑块到指定位置,完成登录
在这里插入图片描述

(一) 获取滑块

huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')
print(huakuai)

出现问题:没有找到元素

  1. 可能是程序运行太快,滑块还没有加载完就开始查找,所以,休眠一会儿
  2. id可能有问题
  3. 可能是有iframe标签

解决问题:依旧是子页面问题

# 切入到第2个iframe标签中
driver.switch_to.frame(1)
# 再查找滑块
huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')

(二) 找到滑块后,需要按住并保持不动

此时需要使用 ActionChains 动作链模块

相关方法描述
click_and_hold()点击并保持点击状态
on_element将此状态加载到哪一个元素身上
perform()执行动作
move_by_offset()移动
xoffset横向移动距离
yoffset纵向移动距离
release()释放鼠标
ActionChains(driver).click_and_hold(on_element=huakuai).perform()

(三)拖动滑块

ActionChains(driver).move_by_offset(xoffset=76,yoffset=0).perform()

(四)释放鼠标

ActionChains(driver).release().perform()

出现问题:网络恍惚了一下,请重试

原因:识别出是机器人了

解决问题:需要将连续行的移动,转换成间断性的移动,完全模拟出人类的移动操作
先匀加速,再匀减速
涉及物理知识:a(加速度)

定义获取运动轨迹函数

def get_tracks(distance):
    """
    v = v0+at
    x = v0t+1/2at**2
    """
    # 定义存放运动轨迹的列表
    tracks = []
    # 定义初速度
    v = 0
    # 定义单位时间
    t = 0.5
    # 定义匀加速运动和匀减速运动的分界线
    mid = distance * 4/5
    # 定义当前位移
    current = 0
    # 为了一直移动,定义循环
    while current < distance:
        if mid > current:
            a = 2
        else:
            a = -3
        v0 = v
        # 计算位移
        x = v0 * t + 1/2*a*t**2
        # 计算滑块当前位移
        current += x
        # 计算末速度
        v = v0+a*t
        tracks.append(round(x))
    return tracks

tracks = get_tracks(176)
print(tracks)
for track in tracks:
    ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()

time.sleep(1)

最后在释放鼠标,完成登录

# 释放鼠标
ActionChains(driver).release().perform()

更好的方式(常用)

上述方式只是我们人为的设置滑块移动距离,而实际上每一个滑块移动的距离都是不同的,差距也比较大,所以,不能够写一个固定的移动距离

思路:将移动距离计算出来

核心

  1. 找出无缺口的图片
  2. 使用有缺口的图片和无缺口的图片做对比
    目的:获取移动的距离(确定缺口位置)

步骤一:截取整个页面以获取有缺口图片

driver.save_screenshot('quekou.png')

步骤二:局部截图,截取有缺口的验证码图片

# 找到图片
element = driver.find_element_by_xpath('//div[@class="geetest_canvas_img geetest_absolute"]')

# 获取图片位置
# 计算截图范围
left = element.location['x']  # loaction:获取元素位置
right = element.location['x'] + element.size['width']  # size:获取元素大小
top = element.location['y']
bottom = element.location['y'] + element.size['height']

# 打开图片
im = Image.open('quekou.png')
# 开始局部截图
im = im.crop((left+60,top+10,right,bottom))
im.save('quekou_jubu.png')

步骤三:执行JS,获取无缺口图片

driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display:block"')

# 截取无缺口图片
driver.save_screenshot('wuque.png')

im = Image.open('wuque.png')
# 开始局部截图
im = im.crop((left+60,top+10,right,bottom))
im.save('wuque_jubu.png')

步骤四:将两张图片进行对比,计算移动距离

wuque_jubu = Image.open('wuque_jubu.png')
quekou_jubu = Image.open('quekou_jubu.png')
distance = get_difference(wuque_jubu,quekou_jubu)

# 定义计算移动距离的函数
def get_difference(image1,image2):
    """
    循环每一个点,计算出对应的像素值
    """
    # 外层循环循环长度
    for i in range(image1.width):
        # 内层循环循环宽度
        for j in range(image1.height):
            # 找出缺口
            if not is_similar(image1,image2,i,j):
                return i  # 此时的i即为缺口距离

# 定义找出缺口位置的函数
def is_similar(image1,image2,x,y):
    # 计算RGB值
    pixel1 = image1.getpixel((x,y))
    pixel2 = image2.getpixel((x,y))
    # 设置一个容差范围,设置30位容差范围
    if abs(pixel1[0] - pixel2[0]) >30 and abs(pixel1[1] - pixel2[1]) > 30 and abs(pixel1[2] - pixel2[2])>30:
        return False
    return True
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值