使用Python + Selenium破解滑块验证码

发表于:2018-3-20 11:00

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:aneasystone    来源:aneasystone\\\'s blog

  四、模拟滑块拖动
  在得到拖动偏移量后,我们就可以通过 Selenium 提供的方法来拖动滑块了:
  def drag_and_drop(browser, offset):
  knob = browser.find_element_by_class_name("gt_slider_knob")
  ActionChains(browser).drag_and_drop_by_offset(knob, offset, 0).perform()
  Selenium 将一系列连续的动作封装在 ActionChains 类 中,其中 drag_and_drop() 方法可以将一个元素拖到另一个元素上,drag_and_drop_by_offset() 方法可以指定拖动的偏移,正是我们这里所需要的。
  到这里,我们已经看到希望了,胜利就在前方。不过,还不能高兴得太早,上面的方法虽然成功将滑块拖到缺口位置了,但是并没有验证通过,页面提示拼图被怪物吃掉了。。。
  
  很显然,这种方法很容易被检测出来是机器所为,因为人不可能拖那么快。于是我稍微调整了下程序,改成每次拖 10px,然后等待 1s 再拖 10px,依次循环,不过可惜的是,这种拖法拼图依然被怪物吃掉了,想想也是,人怎么可能拖的这么有规律呢?
  于是继续调整我的程序,在中间加入了随机数的成分,改成每次拖 1~20px(随机),然后等待 0~2s(随机),本想着这种方式应该能成功了,但是事与愿违,还是被怪物吃掉,不过,在测试的时候,10 次里面竟然也成功了一次。
  看来极验对拖动轨迹的验证还是很厉害的,它是如何识别出是机器拖动的还是人拖动的呢?人在拖动的时候,又有什么样的规律呢?为了搞清楚这一点,我在网上找了一款用于记录鼠标位置的小工具 MouseController,运行之后按 F9 就可以开始或停止记录,并可以将鼠标轨迹保存到一个 mcd 文件中。使用这个工具我将手工拖动滑块的轨迹记录下来,并写了一个脚本(脚本代码参见这里)画出手工拖动滑块的轨迹图,如下:
 
  看到这个轨迹图,我们应该能想出手工拖动的规律了:先快速向右拖动,快到缺口位置时,再减速慢调。接下来的问题就是如何通过算法来生成这样的轨迹了。
  模拟滑块拖动的算法网上也有很多,有的直接根据手工拖动的轨迹按比例生成程序要拖动的轨迹,有的根据物理学中的加速度减速度来模拟轨迹,还有根据正切函数图像来模拟轨迹的,可说各有千秋。不过它们的成功率都不能达到很满意,我在这里介绍一种与众不同的方法,而且成功率可以高达 99%。
  我看到上面这个轨迹图的时候,第一反应不是上述任何一种算法,而是 jquery.easing,可能是由于最近刚用 jquery.easing 实现了几个动画效果吧。我们知道,jQuery 可以实现很多不同的动画效果,譬如淡入淡出移动等等,为了让动画有好的过渡变化过程,官方提供了一个 easing 属性,但是官方没有给出很多过渡效果。于是就有了 jquery.easing 这个插件,这个插件增加了很多种过渡效果,引入之后可以让动画过渡过程更加多样化。Easing 有时又叫做 缓动函数,用于指定动画效果在执行时的速度,使其看起来更加真实。这里有一份缓动函数速查表,你可以在这里找到常见的缓动函数(还可以体验各种缓动函数的效果):
  
  和上面的轨迹图做个对比就可以发现,轨迹图明显和 easeOut 类 的缓动函数很类似,如:easeOutQuad、easeOutQuart、easeOutExpo 等等。那么我们能不能写个 Python 版的 easing 函数呢?说干就干,我们参考 jquery.easing 的源码 实现了三种 easeOut 函数如下:
import numpy as np
import math
def ease_out_quad(x):
return 1 - (1 - x) * (1 - x)
def ease_out_quart(x):
return 1 - pow(1 - x, 4)
def ease_out_expo(x):
if x == 1:
return 1
else:
return 1 - pow(2, -10 * x)
def get_tracks(distance, seconds, ease_func):
tracks = [0]
offsets = [0]
for t in np.arange(0.0, seconds, 0.1):
ease = globals()[ease_func]
offset = round(ease(t/seconds) * distance)
tracks.append(offset - offsets[-1])
offsets.append(offset)
return offsets, tracks
  其中 get_tracks() 方法可以根据滑块的偏移,需要的时间(相对时间,并不是准确时间),以及要采用的缓动函数生成拖动轨迹。然后就可以通过下面的方法,实现出想要的拖动效果了:
def drag_and_drop(browser, offset):
knob = browser.find_element_by_class_name("gt_slider_knob")
offsets, tracks = easing.get_tracks(offset, 12, 'ease_out_expo')
ActionChains(browser).click_and_hold(knob).perform()
for x in tracks:
ActionChains(browser).move_by_offset(x, 0).perform()
ActionChains(browser).pause(0.5).release().perform()
  如果你感兴趣,还可以模拟出更多的效果,我们甚至可以实现出 easeOutBounce 这种类似小球落地时的弹跳效果。而且更有意思的是,用这种方法来拖动滑块,竟然也可以通过验证。(极验的验证算法还真是让人摸不清啊)
def ease_out_bounce(x):
n1 = 7.5625
d1 = 2.75
if x < 1 / d1 :
return n1 * x * x
elif x < 2 / d1:
x -= 1.5 / d1
return n1 * x*x + 0.75
elif x < 2.5 / d1:
x -= 2.25 / d1
return n1 * x*x + 0.9375
else:
x -= 2.625 / d1
return n1 * x*x + 0.984375
  总结
  通过本文可以看出,破解滑块验证码,浏览器爬虫要比传统爬虫简单的多。不仅仅是破解滑块验证码,在遇到传统爬虫很难解决的问题时,浏览器爬虫都可以提供一种更方便的解决方案。但是俗话说得好,针无双头利,蔗无两头甜,凡事有利必有弊,并没有万能的解决方案,还是需要根据需求来取舍,譬如你的生产环境没有浏览器,那么你不得不使用传统爬虫。但是在正常情况下,我还是推荐最简单的那个选择。

相关文章:
使用Python + Selenium打造浏览器爬虫
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号