爬虫学习笔记(十九)—— 滑动验证码

2023-11-12

一、概念

滑动验证码也叫行为验证码,比较流行的一种验证码,通过用户的操作行为来完成验证,其中最出名的就是极验。滑动验证码的原理就是使用机器学习中的深度学习技术,根据一些特征来区分是否为正常用户。通过记录用户的滑动速度,还有每一小段时间的瞬时速度,用户鼠标点击情况,以及滑动后的匹配程度来识别。而且,不是说滑动到正确位置就是验证通过,而是根据特征识别来区分是否为真用户,滑到正确位置只是一个必要条件。


二、实现步骤

通过代码来模拟验证码滑动主要有4个步骤:

  1. 获取验证码图片,包含缺口图,滑块图,完整图
  2. 计算缺口位置,滑块位置,滑块要滑动的距离
  3. 通过算法模拟人工移动轨迹
  4. 通过selenium模拟操作

(练习网址:https://captcha1.scrape.center/


2.1、获取验证码图片

首先通过“网页调试工具“观察 缺口图,滑块图,完整图 在源码中的位置

三个canvas标签分别对应了缺口图,滑块图和完整图。接下来,我们要通过修改页面样式来获取这三个图:

  1. 让滑块隐藏,截取缺口图;
  2. 隐藏缺口图,显示滑块图,截取滑块图;
  3. 显示完整图,截取完整图。

注意: 获取完图片记得还原,避免在接下来的操作中出错


2.1.1、获取缺口图

通过修改display属性,隐藏滑块,获取缺口图

代码:

js_hide_slice = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="none"'
driver.execute_script(js_hide_slice)
#截取缺口图
gap_imgpath = './gap.png'
driver.find_element_by_class_name('geetest_canvas_bg').screenshot(gap_imgpath)

2.1.2、获取滑块图

通过修改display属性,隐藏缺口图,显示滑块图,截取滑块图

代码:

js_hide_gap = 'document.getElementsByClassName("geetest_canvas_bg")[0].style.display="none"'
js_show_slice = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="block"'
driver.execute_script(js_hide_gap+';'+js_show_slice)
#截取滑块图
slice_imgpath='./slice.png'
driver.find_element_by_class_name('geetest_canvas_slice').screenshot(slice_imgpath)

2.1.3、获取完整图

通过修改display属性,获取完整图

代码:

js_show_full = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="block"'
driver.execute_script(js_show_full)
full_imgpath = './full.png'
driver.find_element_by_class_name('geetest_canvas_fullbg').screenshot(full_imgpath)

2.1.4、完整代码

def get_captcha_img():
    "获取验证码图片"
    #1、隐藏滑块 获取缺口图
    time.sleep(3)
    js_hide_slice = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="none"'
    driver.execute_script(js_hide_slice)
        #获取缺口图
    gap_imgpath = './gap.png'
    driver.find_element_by_class_name('geetest_canvas_bg').screenshot(gap_imgpath)

    # 2、隐藏缺口图 获取滑块图
    js_hide_gap = 'document.getElementsByClassName("geetest_canvas_bg")[0].style.display="none"'
    js_show_slice = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="block"'
    driver.execute_script(js_hide_gap+';'+js_show_slice)
        #获取滑块图
    slice_imgpath='./slice.png'
    driver.find_element_by_class_name('geetest_canvas_slice').screenshot(slice_imgpath)

    # 3、获取完整图   
    js_show_full = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="block"'
    driver.execute_script(js_show_full)
    full_imgpath = './full.png'
    driver.find_element_by_class_name('geetest_canvas_fullbg').screenshot(full_imgpath)

    # 4、还原验证码图形
    js_hide_full = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="none"'
    js_show_gap = 'document.getElementsByClassName("geetest_canvas_bg")[0].style.display="block"'
    driver.execute_script(js_hide_full+';'+js_show_gap)
    return gap_imgpath,slice_imgpath,full_imgpath

2.2、计算缺口位置

通过计算缺口位置与滑块位置的差值,获得滑块要移动的距离

代码

def get_gapX(gap_imgpath,full_imgpath):
    "获取缺口的位置,缺口左边缘X坐标 "
    gap_img = Image.open(gap_imgpath)
    full_img = Image.open(full_imgpath)
    w,h = gap_img.size
    for x in range(w):
        for y in range(h):
            # 彩色图片,每一个点是一个元组
            gap_rgb = gap_img.getpixel((x,y))
            full_rgb = full_img.getpixel((x,y))
            #比较缺口图与完整图,相同的坐标上的点,求颜色差值
            #相同的颜色通道相减之后的绝对值相加;非缺口的地方差别小,缺口大的色差大
            r = gap_rgb[0]-full_rgb[0]
            g = gap_rgb[1]-full_rgb[1]
            b = gap_rgb[2]-full_rgb[2]
            value = abs(r)+abs(g)+abs(b)
            print((x,y),value)
            if value>120:
                return x

def get_sliceX(slice_imgpath):
    "获取滑块的位置,滑块左边缘X坐标"
    slice_img = Image.open(slice_imgpath)
    w,h = slice_img.size
    #滑块为彩色,其余地方为白色
    for x in range(w):
        for y in range(h):
            rgb = slice_img.getpixel((x,y))
            value = rgb[0] + rgb[1] + rgb[2]   #740
            # print((x,y),value)
            if value < 570:
                return x

def get_distance(gap_imgpath, slice_imgpath, full_imgpath):
    "计算距离"
    gapX = get_gapX(gap_imgpath,full_imgpath)
    sliceX = get_sliceX(slice_imgpath)
    return abs(gapX - sliceX)

2.3、模拟人工移动

通过算法模拟人工移动的轨迹:

  • 1、直接根据获取到的距离移动,滑块与缺口能够契合,但是不能通过
  • 2、牛顿运动定律模拟人工移动,偶尔有通过,概率低;
  • 3、增加随机性模拟人工移动轨迹,通过概率高

2.3.1、直接根据距离移动

def move_slice1(distance):
    "1、直接根据距离移动"
    elem = driver.find_element_by_class_name('geetest_slider_button')
    ActionChains(driver).click_and_hold(elem).perform()
    ActionChains(driver).move_by_offset(xoffset=distance,yoffset=0).perform()
    ActionChains(driver).release(elem).perform()

2.3.2、牛顿运动定律模拟人工移动

拖动时的速度要平滑变化,开始变快,后来变慢,最后可能拖过头然后回拖,则速度可能为负,抛物线只是一种方案,轨迹方案体现拖动滑块时速度变化的理解。

这里要稍微用一点高中的物理知识:

代码实现

def get_track(distance):
    '''
    获得移动轨迹,模仿人的滑动行为,先匀加速后匀减速匀变速运动基本公式:
    ①v=v0+at
    ②s=v0t+0.5at^2
    :param distance: 需要移动的距离
    :return: 每0.2s移动的距离
    '''
    #初速度
    v0 = 0
    #单位时间0.2s
    t = 0.2
    #轨迹列表,每个元素代表0.2s的位移
    tracks = []
    #当前的位移
    current = 0
    #达到mid开始减速
    mid = distance*5/8
    #先滑过一点,最后再反着滑动回来
    distance+=10
    while current<=distance:
    	# 增加运动随机性
    	t = random.randint(1,4)/10
        if current<mid:
            #加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细
            a = random.randint(2,7) #加速运动
        else:
            a = -random.randint(2,6) #减速运动
        #0.2s时间的位移
        s = v0*t + 0.5*a*(t**2)
        #当前位置
        current+=s
        #添加到轨迹列表
        tracks.append(round(s))
        #当前速度,作为下次的初速度
        v0 = v0+a*t
	#反着滑动到大概准确位置        
    for i in range(4):
        tracks.append(-random.randint(1,3))
    return tracks

2.4、selenium 移动滑块

def move_slice1(distance):
	"1、直接根据距离移动"
	elem = driver.find_element_by_class_name('geetest_slider_button')
	ActionChains(driver).click_and_hold(elem).perform()
	ActionChains(driver).move_by_offset(xoffset=distance,yoffset=0).perform()
	ActionChains(driver).release(elem).perform()

def move_slice2(distance):
    "2、牛顿运动定律模拟人工移动"
    elem = driver.find_element_by_class_name('geetest_slider_button')
    ActionChains(driver).click_and_hold(elem).perform()
    tracks = get_track(distance)
    for track in tracks:
        ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()
    ActionChains(driver).release(elem).perform()

移动卡顿问题

代码在运行的过程中可能会出现卡顿的问题,解决方法是修改pointer_input.py文件中的DEFAULT_MOVE_DURATION的值,把这个值改小一点,这个值的主要作用是控制花费多少毫秒来完成移动鼠标的动作。

python文件下 Lib\site-packages\selenium\webdriver\common\actions\pointer_input.py

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

爬虫学习笔记(十九)—— 滑动验证码 的相关文章

随机推荐

  • 【ffmpeg基础】视频滤波处理

    ffmpeg版本 ffmpeg version 5 1 2 Copyright c 2000 2022 the FFmpeg developers 一 视频缩放滤波器 视频的滤波器通常使用 vf video filters 来设置滤波器 也
  • GDI 绘图

    目录 GDI 绘图 画点 画线 画封闭图形 画笔 画刷 其他 DC Device Context 绘图设备 HDC 绘图设备句柄 GDI Microsoft Graphics Device Interface Win32提供的绘图API G
  • python变量与作用域

    变量从作用域分类 作用范围从小到大为 小作用域的可以调用大作用域的内容 局部 Local 闭包 Enclosing 全局 Global 内建 Build in 局部变量 局部变量是定义在函数中的 因此其作用域是在函数内部 def examp
  • Opencv2.4.2+vs2008+windowsXP(32位)安装过程

    Opencv2 4 2 vs2008 windowsXP 32位 安装过程 准备软件 opencv2 4 2 VS2008软件 1 解压opencv2 4 2到指定路径 例如 D Program Files OpenCV2 4 2 2 打开
  • Https + OPENSSL

    二 HTTPS 2 1 HTTPS介绍 先来看HTTPS的概念 我们一般的http走的是80端口 而https走的是443端口 有什么不一样的地方吗 很简单 我们拿个telnet命令来作个实验 telnet127 0 0 1 80 直接就登
  • Vue.js(四)

    Vue js 模板语法 Vue js 使用了基于 HTML 的模版语法 允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据 Vue js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统 结合响应系统 在
  • two.js插件的简单用法

    div div
  • linux 环境变量设置方法总结(PATH/LD_LIBRARY_PATH)

    PATH和LD LIBRARY PATH本质都是变量 所谓变量的意思就是由别人赋值产生的 直觉往往会让我们添加和减少这个变量本身的某些路径 实际上这是不正确的 正确的做法是我们要去修改赋予这个变量数值的那些配置文件 加一条路径或者减一条 说
  • pageoffice 骑缝章_PageOffice 页面中打开office编辑文档

    pom xml com zhuozhengsoft pageoffice 4 5 0 6 web xml poserver com zhuozhengsoft pageoffice poserver Server poserver pose
  • FDFS_Ubuntu部署fdfs测试上传文件不成功

    开启服务 sudo service fdfs trackerd start sudo service fdfs storaged start 查看服务是否开启 ps aux grep fdfs 执行完上述的操作之后 在ps 命令中完美显示开
  • 字符串相关,可变长字符串,异常

    字符串相关 String 字符串常量 本质char String str1 abc String str2 abc System out prrintln str1 str2 同时也会带来这样的问题 String a a a a b ab
  • Vue axios的使用

  • cmake知识点总结

    CMake的所有的语句都写在一个叫 CMakeLists txt 的文件中 当 CMakeLists txt 文件确定后 可以用 ccmake 命令对相关的变量值进行配置 这个命令必须指向 CMakeLists txt 所在的目录 配置完成
  • 操作系统_第四章_存储管理之 页式存储管理

    思考一个问题 是否有可能把相对地址连续的作业信息分散存放到几个不连续的主存区域中 且仍然能保证作业正确执行 若可行的话 既可充分利用主存空间又可减少移动所花费的开销 页式存储管理就是这样的管理方式 一 页式存储管理的基本原理 定义 页式存储
  • Vue3打包后无法运行

    描述 使用Vue3打包项目后 使用Live Server打开无法运行 放到服务器上也是一样 如图所示错误 分析 错误提示为js文件未找到 所以可能是路径的问题 关于Vue公共基础路径问题 https cn vitejs dev guide
  • android开发笔记(1-5)(易错点以及技术难点攻克)

    1 scrollview中嵌套有listview或者gridview 从其他页面返回到这个页面 焦点总是跑到listview或者gridview上 解决办法 重写scrollview的下边方法 Override protected int
  • 使用cloudflare搭建个人博客网站实践

    使用cloudflare搭建个人博客网站 首先配置好基本的环境 建议使用LNMP工具建立基本的环境 按照上面的教程可以基本完成采用http网站的初步建立 但是对于https的支持上面说的并不好 因此需要进一步的改进 要自己配置https其实
  • MySQL进阶 -- 视图

    MySQL进阶 视图 一 介绍 二 语法 三 检查选项 CASCADED 级联 LOCAL 本地 四 视图更新 五 视图作用 六 案例 一 介绍 视图 view 是一个虚拟表 非真实存在 其本质是根据SQL语句获取动态的数据集 并为其命名
  • 快速设计元器件原理图库和PCB封装库

    目录 1 立创商城EDA免费库 2 Altium Library Loader 3 贸泽电子ECAD模型 在设计电路的过程中经常会遇到这样的问题 无法快速找到合适的元器件原理图封装和PCB封装 Footprint 通常最基本的做法是百度找找
  • 爬虫学习笔记(十九)—— 滑动验证码

    文章目录 一 概念 二 实现步骤 2 1 获取验证码图片 2 1 1 获取缺口图 2 1 2 获取滑块图 2 1 3 获取完整图 2 1 4 完整代码 2 2 计算缺口位置 2 3 模拟人工移动 2 3 1 直接根据距离移动 2 3 2 牛