上节我们了解了图形验证码的识别,简单的图形验证码我们可以直接利用 Tesserocr 来识别,但是近几年又出现了一些新型验证码,如滑动验证码,比较有代表性的就是极验验证码,它需要拖动拼合滑块才可以完成验证,相对图形验证码来说识别难度上升了几个等级,本节来讲解下极验验证码的识别过程。
http://www.geetest.com/
,它是一个专注于提供验证安全的系统,主要验证方式是拖动滑块拼合图像,若图像完全拼合,则验证成功,即可以成功提交表单,否则需要重新验证,样例如图 8-5 和 8-6 所示:
图 8-5 验证码示例
图 8-6 验证码示例 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家企业正在使用极验,每天服务响应超过四亿次,广泛应用于直播视频、金融服务、电子商务、游戏娱乐、政府企业等各大类型网站,下面是斗鱼、魅族的登录页面,可以看到其都对接了极验验证码,如图 8-7 和 8-8 所示:
图 8-7 斗鱼登录页面
图 8-8 魅族登录页面
https://account.geetest.com/login
,首先可以看到在登录按钮上方有一个极验验证按钮,如图 8-9 所示:
图 8-9 验证按钮 此按钮为智能验证按钮,点击一下即可智能验证,一般来说如果是同一个 Session,一小段时间内第二次登录便会直接通过验证,如果智能识别不通过,则会弹出滑动验证窗口,我们便需要拖动滑块来拼合图像完成二步验证,如图 8-10 所示:
图 8-10 拖动示例 验证成功后验证按钮便会变成如下状态,如图 8-11 所示:
图 8-11 验证成功结果 接下来我们便可以进行表单提交了。 所以在这里我们要识别验证需要做的有三步:
模拟点击验证按钮
识别滑动缺口的位置
模拟拖动滑块
第一步操作是最简单的,我们可以直接用 Selenium 模拟点击按钮即可。 第二步操作识别缺口的位置比较关键,需要用到图像的相关处理方法,那缺口怎么找呢?首先来观察一下缺口的样子,如图 8-12 和 8-13 所示:
图 8-12 缺口示例
图 8-13 缺口示例 可以看到缺口的四周边缘有明显的断裂边缘,而且边缘和边缘周围有明显的区别,我们可以实现一个边缘检测算法来找出缺口的位置。对于极验来说,我们可以利用和原图对比检测的方式来识别缺口的位置,因为在没有滑动滑块之前,缺口其实是没有呈现的,如图 8-14 所示:
图 8-14 初始状态 所以我们可以同时获取两张图片,设定一个对比阈值,然后遍历两张图片找出相同位置像素 RGB 差距超过此阈值的像素点位置,那么此位置就是缺口的位置。 第三步操作看似简单,但是其中的坑比较多,极验验证码增加了机器轨迹识别,匀速移动、随机速度移动等方法都是不行的,只有完全模拟人的移动轨迹才可以通过验证,而人的移动轨迹一般是先加速后减速的,这又涉及到物理学中加速度的相关问题,我们需要模拟这个过程才能成功。 有了基本的思路之后就让我们用程序来实现一下它的识别过程吧。
https://account.geetest.com/login
,也就是极验的管理后台登录页面,在这里我们首先初始化一些配置,如 Selenium 对象的初始化及一些参数的配置:
def get_position(self):
"""
获取验证码位置
:return: 验证码位置元组
"""
img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
time.sleep(2)
location = img.location
size = img.size
top, 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'):
"""
获取验证码图片
:return: 图片对象
"""
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def is_pixel_equal(self, image1, image2, x, y):
"""
判断两个像素是否相同
:param image1: 图片1
:param image2: 图片2
:param x: 位置x
:param y: 位置y
:return: 像素是否相同
"""
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 60
if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
pixel1[2] - pixel2[2]) < threshold:
return True
else:
return False
def get_gap(self, image1, image2):
"""
获取缺口偏移量
:param image1: 不带缺口图片
:param image2: 带缺口图片
:return:
"""
left = 60
for 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 = i
return left
return left
get_gap() 方法即为获取缺口位置的方法,此方法的参数为两张图片,一张为带缺口图片,另一张为不带缺口图片,在这里遍历两张图片的每个像素,然后利用 is_pixel_equal() 方法判断两张图片同一位置的像素是否相同,比对的时候比较了两张图 RGB 的绝对值是否均小于定义的阈值 threshold,如果均在阈值之内,则像素点相同,继续遍历,否则遇到不相同的像素点就是缺口的位置。 在这里比如两张对比图片如下,如图 8-15 和 8-16 所示:
图 8-15 初始状态
图 8-16 后续状态 两张图片其实有两处明显不同的地方,一个就是待拼合的滑块,一个就是缺口,但是滑块的位置会出现在左边位置,缺口会出现在与滑块同一水平线的位置,所以缺口一般会在滑块的右侧,所以要寻找缺口的话,我们直接从滑块右侧寻找即可,所以在遍历的时候我们直接设置了遍历的起始横坐标为 60,也就是在滑块的右侧开始识别,这样识别出的结果就是缺口的位置了。 到现在为止,我们就可以获取缺口的位置了,剩下最后一步模拟拖动就可以完成验证了。
https://github.com/Python3WebSpider/CrackGeetest
。
2022
2048
ADSL
API
Ajax
Bootstrap
Bug
CDN
CQC
CSS
CSS 反爬虫
CV
ChatGPT
Cookie
Django
Eclipse
Elasticsearch
FTP
Git
GitHub
HTML5
HTTP
Hexo
Hook
IP
IT
JSON
JSP
JavaScript
K8s
LOGO
Linux
Luma
MIUI
Markdown
Midjourney
MongoDB
MySQL
Mysql
NBA
Nexior
OCR
OpenCV
PHP
PPT
PS
Pathlib
PhantomJS
Playwright
Python
Python 爬虫
Python3
Python3爬虫教程
Pythonic
Python爬虫
Python爬虫书
Python爬虫教程
QQ
RabbitMQ
ReCAPTCHA
Redis
SAE
SSH
SVG
Scrapy-redis
Scrapy分布式
Selenium
Session
Shell
Suno
TKE
TXT
Terminal
Ubuntu
VS Code
Vercel
Vs Code
Vue
Web
Webpack
Web网页
Windows
Winpcap
WordPress
XPath
Youtube
acedata
aiohttp
android
ansible
api
chatgpt
cocos2d-x
dummy change
e6
fitvids
git
json
js逆向
kubernetes