等距滑块验证码破解

抓取数据的时候,有时候会碰到滑块验证码,比如说某瓣。我们尝试用selenium拖拽的方式去通过验证,但是此方法只适用于滑块和缺口等距时的情况。由于此方法适用于所有等距滑块验证码的破解,所以在此就直接上代码了。

1、导入selenium及动作链

import time
from selenium import webdriver
# 导入动作链
from selenium.webdriver.common.action_chains import ActionChains

2、访问目标url

# 调用浏览器
driver = webdriver.Chrome(executable_path=r'./webdriver/chromedriver.exe')

# 最大化浏览器
driver.maximize_window()

# 访问目标url
driver.get(url='https://www.douban.com/')

3、输入账号密码点击登录

此处会出现一个xpath无法定位密码登录区域的问题,原因是密码登录框被嵌套进一个子页面当中了,需要先切入到子页面中,再点击密码登录。

# switch_to.frame(0) : 0代表的是第一个子页面
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_xpath('//*[@id="username"]').send_keys('13355889940')
# 查找并输入密码
driver.find_element_by_xpath('//*[@id="password"]').send_keys('11111111')
# 查找并点击登录按钮
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]').click()

4、获取并移动滑块

此处又会出现一个iframe嵌套的子页面,所以仍然需要先进入到子页面中,再用selenium定位元素。iframe是常见的导致selenium无法定位元素的问题之一。

driver.switch_to.frame(1)
time.sleep(2)
# 获取滑块
block = driver.find_element_by_id('tcaptcha_drag_thumb')

# click_and_hold()  点击并保持点击状态
# on_element:将此状态加载到哪一个元素身上
# perform():执行
ActionChains(driver).click_and_hold(on_element=block).perform()

# 移动滑块
# move_by_offset()
# xoffset:横向移动距离
# yoffset:纵向移动距离
# 因为是等距的,所以xoffset的值就是滑块到缺口的距离
ActionChains(driver).move_by_offset(xoffset=175, yoffset=0).perform()
  • 试了几次,发现出提示网络恍惚了一下,请重试。可能是被对方检测到了是机器人在模拟登陆
  • 解决办法,拖动滑块的时候模拟人的操作,定义一个计算轨迹的方法
def geTracks(distance):
    """
    定义方法计算移动轨迹
    先匀加速,后匀减速
    """
    # 定义初速度
    v = 0
    # 定义单位时间
    t = 0.1
    # 定义存放运动轨迹的列表
    tracks = []
    # 定义当前位移
    current = 0
    # 定义匀加速运动和匀减速运动的分界
    mid = distance * 4 / 5
    
    while current < distance:
    	# 未到达分界点时,加速度大于0,做匀加速运动
        if mid > current:
            a = 2
        # 达到分界点时,做匀减速运动
        else:
            a = -3

        v0 = v
        # 计算位移
        x = v * t + 1 / 2 * a * t ** 2
        # 计算滑块当前位移
        current += x
        # 计算初速度
        v = v0 + a * t
        tracks.append(x)
    return tracks

5、用动作链的move_by_offset执行上述方法获取到的偏移量,模拟人工拖动滑块

tracks = getTracks(75)

for track in tracks_list:
    ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

# 停1秒释放鼠标:release()
time.sleep(1)
ActionChains(driver).release().perform()

成功通过等距滑块验证,上述方法可以用于所有的等距滑块验证码破解。