滑块验证码

滑块验证码是生活中非常常见的一种验证方式,在爬虫过程中如果遇到改怎么解决呢?当然我们可以手动划过去再执行下面的代码,但是这样不符合我们效率至上的原则。

破解思路:

使用 selenium 模拟人为的操作,将滑块移动到指定的位置,然后松开鼠标

核心思路:

计算出移动的距离

怎么计算:

找到无缺口的图片,对比两张图片,通过求出图片中每一个点的颜色的 RGB 值,找出缺口位置

大致过程:

import selenium from webdriver

driver = webdriver.Chrome(插件位置)
# 最大化窗口,方便定位图片
driver.maxmize_window()
# 截图,获取有缺口的图片
driver.save_scerrnshot('quekou.png')
# 通过获取图片元素来准准确定位图片
ele = driver.find_element(By.XPATH,'xpath路径')
# 根据图片元素位置进行局部截图
# 目的:为了方便对比RGB值,需要将最左边的拼图块截掉,以免对后面的对比造成干扰
left = ele.location['x']
right = ele.location['x'] + ele.size['width']
top = ele.location['y']
bottom = ele.location['y'] + ele.size['height']
# 打开之前截取的整页图片
# 这里用到PIL模块
from PIL import Image
im = Image.open('quanbu.png')
im = im.crop((left * 2 + 110, top * 2 + 10, right * 2, bottom * 2))
# 注意win设备不需要*2
# 保存图片
im.save('wuque_jubu.png')

找到完整图片:

这样我们就获得了带缺口的局部截图,接下来就是要找到完整的图片,一般两个标签会离的很近

# 找出无缺口的图片
# 执行js
driver.execute_script('document.getElementsByClassName("这里输入class的值")[0].style="display:block"')
# 截图
driver.save_screenshot('wuque.png')
im = Image.open('wuque.png')
im = im.crop((left * 2 + 110, top * 2 + 10, right * 2, bottom * 2))
# 同理,Mac*2,win不需要
im.save('wuque_jubu.png')

这样我们就获得了有缺口和没有缺口的两证图片,并且两张图片大小完全一致,方便我们后面的比较

定义计算距离的函数及判断相似的函数

# 定义计算距离的函数
def get_difference(image1,image2):
  for i in range(image1.width):
    for j in range(image1.height):
      if  is_similar(image1,image2,i,j):
        return i
# 定义判断相似的函数
def is_similar(image1,image2,x,y):
  # 计算每一个点在对应图片中的rgb值,判断是否缺口
  # 计算RGB值的方法
  pixel1 = image1.getpixel((x,y))
  pixel2 = image2.getpixel((x,y))
  # 找出缺口
  # 需要设置一个容差范围,如果超出这个范围为缺口,否则不是缺口
    if abs(pixel1[0] - pixel2[0]) > 30 and abs(pixel1[1] - pixel2[1]) > 30 and abs(pixel1[2] - pixel2[2]) > 30:
      return True
    return False

接下来就调用定义好的函数来计算移动距离

计算移动距离

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

然后找到滑块按钮,开始移动滑块就好

开始移动滑块

huakuai = driver.find_element(By.XPATH,'xpath路径')
# 按住滑块并保持不动
# 这里需要导入selenium的动作链
from selenium.webdriver.common.action_chains import ActionChains

ActionChains(driver).click_and_hold(on_element=huakuai).perform()

# 滑动滑块
ActionChains(driver).move_by_offset(xoffset=(distance + 55) * 0.6, yoffset=0).perform()

# 松开鼠标
ActionChains(driver).release().perform()

但是,程序移动滑块的速度是非常快的,直接就闪现过去了,一般是成功不了的,正常网页都会有判断,速度过快时无法通过的,这里就需要用到物理的加速运动了,我们让程序来做匀加匀减速运动,本人身为一个物理黑洞,只能拿大佬定义好的来用了…….

定义计算运动轨迹的函数


def get_distance(distance):
    """
    x = v0*t + 1/2 * a * t ** 2
    v = v0 + a * t
    """
    # 定义单位时间
    t = 0.3
    # 定义初速度
    v = 0
    # 定义存放运动轨迹的容器
    distance_list = []
    # 定义匀加速和匀减速的分界线
    mid = distance * 0.8
    # 定义当前位移
    current = 0
    while current < distance:
        if current < mid:
            # 匀加速运动
            a = 2
        else:
            # 匀减速运动
            a = -3
        # 计算位移
        x = v * t + 1 / 2 * a * t ** 2
        current += x
        # 计算末速度
        v = v + a * t
        distance_list.append(round(x))
    return distance_list

然后我们需要在松开鼠标之前加入模拟先加速后减速的运动

# 利用物理加速度,模拟出先加速后减速的运动
distance_list = get_distance((distance + 55) * 0.4)
for i in distance_list:
 ActionChains(driver).move_by_offset(xoffset=i, yoffset=0).perform()

总结:

这就是本人总结的破解滑块验证码的具体思路了,但是在很多网站都会针对进行检测,成功率较低,需要不断的实验来调整程序滑动的运动轨迹来减少被检测的几率