【验证码的识别】—— 极验验证码的识别
前言
(结尾有彩蛋欧)
目前,许多网站采取各种各样的措施来反爬虫,其中一个措施便是使用验证码。随着技术的发展,验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码,后来加入了英文字母和混淆曲线。有的网站还可能看到中文字符的验证码,这使得识别愈发困难。
后来 12306 验证码的出现使得行为验证码开始发展起来,用过 12306 的用户肯定多少为它的验证码头疼过。我们需要识别文字,点击与文字描述相符的图片,验证码完全正确,验证才能通过。现在这种交互式验证码越来越多,如极验滑动验证码需要滑动拼合滑块才可以完成验证,点触验证码需要完全点击正确结果才可以完成验证,另外还有滑动宫格验证码、计算题验证码等。
验证码变得越来越复杂,爬虫的工作也变得愈发艰难。有时候我们必须通过验证码的验证才可以访问页面。本章就专门针对验证码的识别做统一讲解。
接下来会涉及的验证码有普通图形验证码、极验滑动验证码、点触验证码、微博宫格验证码,这些验证码识别的方式和思路各有不同。了解这几个验证码的识别方式之后,我们可以举一反三,用类似的方法识别其他类型验证码。
环境使用
- python 3.9
- pycharm
上节回顾
上节我们了解了可以直接利用 tesserocr 来识别简单的图形验证码。近几年出现了一些新型验证码,其中比较有代表性的 就是极验验证码,它需要拖动拼合滑块才可以完成验证,相对图形验证码来说识别难度上升了几个等级。本节将讲解极验验证 码的识别过程。
本节目标
我们的目标是用程序来识别并通过极验验证码的验证,包括分析识别思路、识别缺口位置、生成滑块拖动路径、模拟实现滑块 拼合通过验证等步骤。
准备工作
本次我们使用的 Python 库是 Selenium,浏览器为 Chrome。请确保已经正确安装 Selenium 库、Chrome 浏览器, 并配置 ChromeDriver,相关流程可以参考我写的其他博文说明。
了解极验验证码
现在极验验证码已经更新到 3.0 版本。全球有 16 万家企业使用极验,每天服务响应超过 4 亿次。极验验证码广泛应用于直播视频、金融服务、电子商务、游戏娱乐、政府企业等各大类型网站。下面图中是斗鱼、魅族的登录页面,它们都对接了极验验证码。
极验验证码的特点
极验验证码相较于图形验证码来说识别难度更大。对于极验验证码 3.0 版本,我们首先点击按钮进行智能验证。如果验证不通过,则会弹出滑动验证的窗口,拖动滑块拼合图像进行验证。之后三个加密参数会生成,通过表单提交到后台,后台还会进行一次验证。
极验验证码还增加了机器学习的方法来识别拖动轨迹。官方网站的安全防护有如下几点说明。
- 三角防护之防模拟
恶意程序模仿人类行为轨迹对验证码进行识别。针对模拟,极验拥有超过 4000 万人机行为样本的海量数据。利用机器学习和神经网络构建线上线下的多重静态、动态防御模型。识别模拟轨迹,界定人机边界。
- 三角防护之防伪造
恶意程序通过伪造设备浏览器环境对验证码进行识别。针对伪造,极验利用设备基因技术。深度分析浏览器的实际性能来辨识伪造信息。同时根据伪造事件不断更新黑名单,大幅提高防伪造能力。
- 三角防护之防暴力
恶意程序短时间内进行密集的攻击,对验证码进行暴力识别 针对暴力,极验拥有多种验证形态,每一种验证形态都有利用神经网络生成的海量图库储备,每一张图片都是独一无二的,且图库不断更新,极大程度提高了暴力识别的成本。
5. 识别思路
对于应用了极验验证码的网站,如果我们直接模拟表单提交,加密参数的构造是个问题,需要分析其加密和校验逻辑,相对烦琐。所以我们采用直接模拟浏览器动作的方式来完成验证。在 Python 中,我们可以使用 Selenium 来完全模拟人的行为的方式来完成验证,此验证成本相比直接去识别加密算法少很多。
首先我们找到一个带有极验验证的网站,最合适的当然为极验官方后台了。此按钮为智能验证按钮。一般来说,如果是同一个会话,一段时间内第二次点击会直接通过验证。如果智能识别不通过,则会弹出滑动验证窗口,我们要拖动滑块拼合图像完成二步验证,验证成功后,验证按钮变成如图所示的状态。
接下来,我们便可以提交表单了。
所以,识别验证需要完成如下三步。
-
模拟点击验证按钮
-
识别滑动缺口的位置
-
模拟拖动滑块
拟点击验证按钮
第一步操作是最简单的,我们可以直接用 Selenium 模拟点击按钮即可。
识别滑动缺口的位置
第二步操作识别缺口的位置比较关键,这里需要用到图像的相关处理方法。首先观察缺口的样子,缺口的四周边缘有明显的断裂边缘,边缘和边缘周围有明显的区别。我们可以实现一个边缘检测算法来找出缺口的位置。对于极验验证码来说,我们可以利用和原图对比检测的方式来识别缺口的位置,因为在没有滑动滑块之前,缺口并没有呈现。
我们可以同时获取两张图片。设定一个对比阈值,然后遍历两张图片,找出相同位置像素 RGB 差距超过此阈值的像素点,那么此像素点的位置就是缺口的位置。
模拟拖动滑块
第3步操作看似简单,但其中的坑比较多。极验验证码增加了机器轨迹识别,匀速移动、随机速度移动等方法都不能通过验证,只有完全模拟人的移动轨迹才可以通过验证。人的移动轨迹一般是先加速后减速,我们需要模拟这个过程才能成功。
有了基本的思路之后,我们就用程序来实现极验验证码的识别过程吧。
模拟点击
首先,我们先模拟登录,其中 admin 和 PASSWORD 就是登录极验需要的用户名和密码,如果没有的话可以先注册一下。
admin = '[账号]'
PASSWORD = '[密码]'class CrackGeetest():def __init__(self):self.url = 'https://account.geetest.com/login'self.browser = webdriver.Chrome()self.wait = WebDriverWait(self.browser, 20)self.email = EMAILself.password = PASSWORD
实现第一步的操作,也就是模拟点击初始的验证按钮。我们定义一个方法来获取这个按钮,利用显式等待的方法来实现,如下所示:
def get_geetest_button(self):"""获取初始验证按钮:return: 按钮对象"""button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip')))return button# 点击验证按钮
button = self.get_geetest_button()
button.click()
识别缺口
接下来识别缺口的位置。首先获取前后两张比对图片,二者不一致的地方即为缺口。获取不带缺口的图片,利用 Selenium 选取图片元素,得到其所在位置和宽高,然后获取整个网页的截图,图片裁切出来即可,代码实现如下:
def get_position(self):img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))time.sleep(2)location = img.locationsize = img.sizetop, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size['width']return (top, bottom, left, right)def get_geetest_image(self, name='captcha.png'):top, bottom, left, right = self.get_position()print(' 验证码位置 ', top, bottom, left, right)screenshot = self.get_screenshot()captcha = screenshot.crop((left, top, right, bottom))return captcha
这里 get_position() 函数首先获取图片对象,获取它的位置和宽高,随后返回其左上角和右下角的坐标。get_geetest_image() 方法获取网页截图,调用了 crop() 方法将图片裁切出来,返回的是 Image 对象。
接下来我们需要获取第二张图片,也就是带缺口的图片。要使得图片出现缺口,只需要点击下方的滑块即可。这个动作触发之后,图片中的缺口就会显现,如下所示:
def get_slider(self):slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))return slider
slider = self.get_slider()
slider.click()
调用 get_geetest_image() 方法将第二张图片获取下来即可。
现在我们已经得到两张图片对象,分别赋值给变量 image1 和 image2。接下来对比图片获取缺口。我们在这里遍历图片的每个坐标点,获取两张图片对应像素点的 RGB 数据。如果二者的 RGB 数据差距在一定范围内,那就代表两个像素相同,继续比对下一个像素点。如果差距超过一定范围,则代表像素点不同,当前位置即为缺口位置,代码实现如下:
def is_pixel_equal(self, image1, image2, x, y):pixel1 = image1.load()[x, y]pixel2 = image2.load()[x, y]threshold = 60if abs(pixel1[0] - pixel2[0]) <threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] - pixel2[2]) < threshold:return Trueelse:return Falsedef get_gap(self, image1, image2):left = 60for i in range(left, image1.size[0]):for j in range(image1.size[1]):if not self.is_pixel_equal(image1, image2, i, j):left = ireturn leftreturn left
get_gap() 方法即获取缺口位置的方法。此方法的参数是两张图片,一张为带缺口图片,另一张为不带缺口图片。这里遍历两张图片的每个像素,利用 is_pixel_equal() 方法判断两张图片同一位置的像素是否相同。比较两张图 RGB 的绝对值是否均小于定义的阈值 threshold。如果绝对值均在阈值之内,则代表像素点相同,继续遍历。否则代表不相同的像素点,即缺口的位置。
两张图片有两处明显不同的地方:一个就是待拼合的滑块,一个就是缺口。滑块的位置会出现在左边位置,缺口会出现在与滑块同一水平线的位置,所以缺口一般会在滑块的右侧。如果要寻找缺口,直接从滑块右侧寻找即可。我们直接设置遍历的起始横坐标为 60,也就是从滑块的右侧开始识别,这样识别出的结果就是缺口的位置。
现在,我们获取了缺口的位置。完成验证还剩下最后一步 —— 模拟拖动。
模拟拖动
到这里,会有一个小问题。如果是匀速拖动,极验必然会识别出它是程序的操作,因为人无法做到完全匀速拖动。极验验证码利用机器学习模型,筛选此类数据为机器操作,验证码识别失败。我们尝试分段模拟,将拖动过程划分几段,每段设置一个平均速度,速度围绕该平均速度小幅度随机抖动,这样也无法完成验证。那怎么办呢?
我们可以完全模拟加速减速的过程通过了验证。即前段滑块做匀加速运动,后段滑块做匀减速运动,利用物理学的加速度公式即可完成验证。接下来我们就可以构造轨迹移动算法,计算出先加速后减速的运动轨迹,最后按照该运动轨迹拖动滑块即可,方法实现如下所示:
def move_to_gap(self, slider, tracks):ActionChains(self.browser).click_and_hold(slider).perform()for x in tracks:ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.5)ActionChains(self.browser).release().perform()
最后经过测试,验证通过,识别完成。
哈喽大家好,为了回馈粉丝长久以来的支持,博主决定开始给大家送福利了。在爬虫时,网上的免费代理IP不好用,怎么办?不要慌[鬼脸]我给大家争取到了一个福利,点击下面链接即可免费领取七天测试
http://suo.nz/2zmKBG
白嫖不要不要的
相关文章:

【验证码的识别】—— 极验验证码的识别
前言 (结尾有彩蛋欧) 目前,许多网站采取各种各样的措施来反爬虫,其中一个措施便是使用验证码。随着技术的发展,验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码,后来加入了英文字母和混…...
华为OD机试 -旋转骰子(Python) | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 卡片组成的最大数字(Python) | 机试题算法思路 华为OD机试 - 网上商城优惠活动(一)(Python) | 机试题算法思路 华为OD机试 - 统计匹配的二元组个数(Python) | 机试题算法思路 华为OD机试 - 找到它(Python) | 机试题算法思路 华为OD机试…...

C生万物 | 模拟实现库函数strcpy之梅开n度
文章目录【梅开一度】:观察库函数strcpy()的实现【梅开二度】:模仿实现strcpy()【梅开三度】:优化简练代码【梅开四度】:assert()断言拦截【梅开五度】:const修饰常量指针【梅开六度】:还可以有返回值哦&am…...

家庭理财,轻松记账修改收支记录这样操作
我们在记账的时候难免会出现记错或者想修改的地方,又或者是想将之前太久没有用的记账记录删除掉,今天,小编就教大家如何修改收支记录,一起接着往下看吧! 第一步,运行【晨曦记账本】在软件主界面中ÿ…...

河南工程学院2.17蓝桥杯培训
乘法口诀数列:https://www.acwing.com/problem/content/3466/ 剪绳子:https://www.acwing.com/problem/content/68Sin SinSine之舞:http://lx.lanqiao.cn/problem.page?gpidD5272 数列:https://www.acwing.com/problem/content/…...

【JavaSE】数据类型与变量
JAVA之父:詹姆斯高斯林 (James Gosling) 前言: 大家好,我是程序猿爱打拳。今天我给大家讲解的是Java基础中的数据类型。主要讲解的是各个类型的应用场景以及注意事项。 目录 1.数据类型 2.常量与变量 2.1常量 2.2变…...

生成模型技术发展过程
生成模型生成模型和判别模型的差异生成模型的目标是在给定了数据集D,并且假设这个数据集的底层分布(underlying distribution)是Pdata,我们希望够近似出这个数据分布。如果我们能够学习到一个好的生成模型,我们就能用这个生成模型为下游任务做…...

计算机网络第2章(物理层)学习笔记
❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得关注、点赞、收藏、…...
4564: 保留尾部*
描述规定输入的字符串中只包含字母和*号,除了尾部的*号之外,请将字符串中其他*号全部删除。输入输入数据包括一串字符串,只包含字母和*,总长度不超过80。输出输出按要求删除*后的字符串。样例输入*******A*BC*DEF*G****样例输出AB…...

安卓项目搭建grpc环境
本篇文章使用的IDE是Android Studio。这里先吐槽一句,安卓项目搭建grpc环境,不管是引入插件还是引入第三方库,对于版本的要求都极为苛刻,一旦版本不匹配就会报错,所以对于版本的搭配一定要注意。 下面介绍的这个版本搭…...

Flink01: 基本介绍
一、什么是Flink 1. Flink是一个开源的分布式,高性能,高可用,准确的流处理框架 (1)分布式:表示flink程序可以运行在很多台机器上, (2)高性能:表示Flink处理性…...
设计模式之单例模式
文章の目录一、什么是单例模式二、如何实现单例模式1、利用JavaScript中的全局对象2、静态成员改造参考写在最后一、什么是单例模式 单例模式也称为单体模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。 举个栗子:一个班级只有一…...

[oeasy]python0086_ASCII_出现背景_1963年_DEC_PDP系列主机_VT系列终端
编码进化 回忆上次内容 上次 回顾了 字符编码的新陈代谢 ibm 曾经的EBCDIC 由于 字符不连续导致 后续 出现无数问题 随着 网络的发展 数据交换的 需要原来的小隐患现在 产生了 巨大问题 Bemer 联合各方巨头 想要推出 字符连续的编码集 这新编码集 具体长什么样 呢࿱…...

基于FFmpeg实现的无声音屏幕录制
UI自动化测试时,有时需要进行录屏操作,这时我们是不需要声音的,我们可以通过FFmpeg进行简单的录制工作。 以下是在windows10环境下,基于FFmpeg实现的简单录制: Ffmpeg简介: 功能:有非常强大的…...

【项目精选】基于JSP物流信息网(论文+源码+视频)
点击下载源码 近年来,随着时代的进步,社会随之不断发展,经济也快速发展起来了,人民的消费水平在不断地提高,平常的实体店消费已经不能满足人们的需求;在者,互联网技术的不断发展也为电子商务的兴…...

linux异步IO编程实例分析
在Direct IO模式下,异步是非常有必要的(因为绕过了pagecache,直接和磁盘交互)。linux Native AIO正是基于这种场景设计的,具体的介绍见:KernelAsynchronousI/O (AIO)SupportforLinux。下面我们就来分析一下…...
日常英语口语练习-情景交际场景25(三)
登山踏青m: hey Carol, what are you doing this weekend?o: im going hiking /haikiŋ/登山with my husband and our hiking clubm: you have a hiking culb?o: yes, we do, we have 30 to 40 people of all ages and skill levelsm: thats great, do you gus do…...

Qt 工程师进阶技术23种设计模式
Qt 工程师进阶技术23种设计模式【1】23种设计模式【1】23种设计模式 设计模式是解决特定问题的一系列套路,这套方案提高代码可复用性、可读性、稳健性、可维护性及安全性。 23种设计模式可分为三类:结构型模式(侧重类与对象之间的组合)、行为型模式(侧重…...

Redis 强化
(Redis入门使用查看)https://blog.csdn.net/weixin_73849581/article/details/128390152?spm1001.2014.3001.5501缓存使用原则什么时候,什么样的数据能够保存在Redis中?1.数据量不能太大2.使用越频繁,Redis保存这个数据越值得3.保存在Redis中的数据一般不会是数据库中频繁修改…...
华为OD机试题 - 众数和中位数(JavaScript)
最近更新的博客 华为OD机试题 - 任务总执行时长(JavaScript) 华为OD机试题 - 开放日活动(JavaScript) 华为OD机试 - 最近的点 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试题 - 最小步骤数(JavaScript) 华为OD机试题 - 任务混部(JavaScript) 华为OD机试题 - N 进…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...
Android多媒体——音/视频数据播放(十八)
在媒体数据完成解码并准备好之后,播放流程便进入了最终的呈现阶段。为了确保音视频内容能够顺利输出,系统需要首先对相应的播放设备进行初始化。只有在设备初始化成功后,才能真正开始音视频的同步渲染与播放。这一过程不仅影响播放的启动速度,也直接关系到播放的稳定性和用…...