← 返回文章列表

深度解析:滑动验证码识别

在滑动验证码的应用中,极验和网易易盾是比较有代表性的服务商。验证码的效果如下图所示:极验网易易盾验证码通常会有一个滑动条和一个提示文字「拖动滑块完成拼图」。用户需要按住滑块并将其拖拽至右侧,当验证码左侧的滑块移动至右侧缺口并匹配成功时,验证

在滑动验证码的应用中,极验和网易易盾是比较有代表性的服务商。验证码的效果如下图所示:

极验

网易易盾

验证码通常会有一个滑动条和一个提示文字「拖动滑块完成拼图」。用户需要按住滑块并将其拖拽至右侧,当验证码左侧的滑块移动至右侧缺口并匹配成功时,验证即告通过。验证成功的效果如下图所示:

如果我们希望用爬虫自动化完成这一流程,关键步骤有两个:

识别目标缺口的位置

将滑块移动到目标位置

第二步可以通过模拟工具如 Selenium 完成,但这种方法效率较低。另一种方法是逆向分析验证码的 JavaScript 逻辑,将缺口信息传给 JavaScript 代码以获取“密钥”,并用这些“密钥”进行后续操作。出于安全考虑,本节只介绍如何识别目标缺口位置。

基本原理

我们将介绍利用 OpenCV 进行缺口识别的方法。输入一张带有缺口的验证码图片,输出缺口的位置(通常为缺口左侧的横坐标)。

示例图片

输入的验证码图片如下:

输出的识别结果如下:

实现步骤

利用 OpenCV 进行图像处理的主要步骤包括:

高斯模糊滤波处理,消除部分噪声干扰  更多内容联系1436423940

边缘检测算法识别滑块边缘

对轮廓信息进行筛选,确定缺口位置

准备工作

请确保已安装 python-opencv 库:

bash

pip3 install python-opencv

准备一张滑动验证码图片。样例图片下载地址:验证码图片。

基础知识

高斯滤波

高斯滤波用于去除图像中的噪声,使图像模糊化,为边缘检测做好准备。

OpenCV 提供了 GaussianBlur 方法:

python

def GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)

src:待处理的图像。

ksize:高斯内核大小。

sigmaX:高斯核函数在 X 方向的标准偏差。

示例:

python

image_gaussian_blur = cv2.GaussianBlur(image, (5, 5), 0)

边缘检测

边缘检测常用 Canny 算法,OpenCV 提供了 Canny 方法:

python

def Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None)

image:待处理的图像。

threshold1、threshold2:两个阈值。

示例:

python

image_canny = cv2.Canny(image_gaussian_blur, 200, 450)

轮廓提取

使用 findContours 方法提取轮廓:

python

def findContours(image, mode, method, contours=None, hierarchy=None, offset=None)

image:待处理的图像。

mode:轮廓检索模式。

method:轮廓近似方法。

示例:

python

contours, _ = cv2.findContours(image_canny, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

外接矩形

计算轮廓的外接矩形,使用 boundingRect 方法:

python

def boundingRect(array)

示例:

python

x, y, w, h = cv2.boundingRect(contour)

轮廓面积和周长

计算轮廓面积使用 contourArea 方法:

python

def contourArea(contour, oriented=None)

计算轮廓周长使用 arcLength 方法:

python

def arcLength(curve, closed)

缺口识别

定义处理方法

python

import cv2

GAUSSIAN_BLUR_KERNEL_SIZE = (5, 5)

GAUSSIAN_BLUR_SIGMA_X = 0

CANNY_THRESHOLD1 = 200

CANNY_THRESHOLD2 = 450

def get_gaussian_blur_image(image):

return cv2.GaussianBlur(image, GAUSSIAN_BLUR_KERNEL_SIZE, GAUSSIAN_BLUR_SIGMA_X)

def get_canny_image(image):

return cv2.Canny(image, CANNY_THRESHOLD1, CANNY_THRESHOLD2)

def get_contours(image):

contours, _ = cv2.findContours(image, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

return contours

处理验证码图片

python

image_raw = cv2.imread('captcha.png')

image_height, image_width, _ = image_raw.shape

image_gaussian_blur = get_gaussian_blur_image(image_raw)

image_canny = get_canny_image(image_gaussian_blur)

contours = get_contours(image_canny)

轮廓筛选条件

python

def get_contour_area_threshold(image_width, image_height):

contour_area_min = (image_width * 0.15) * (image_height * 0.25) * 0.8

contour_area_max = (image_width * 0.15) * (image_height * 0.25) * 1.2

return contour_area_min, contour_area_max

def get_arc_length_threshold(image_width, image_height):

arc_length_min = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 0.8

arc_length_max = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 1.2

return arc_length_min, arc_length_max

def get_offset_threshold(image_width):

offset_min = 0.2 * image_width

offset_max = 0.85 * image_width

return offset_min, offset_max

轮廓筛选和结果标注

python

contour_area_min, contour_area_max = get_contour_area_threshold(image_width, image_height)

arc_length_min, arc_length_max = get_arc_length_threshold(image_width, image_height)

offset_min, offset_max = get_offset_threshold(image_width)

offset = None

for contour in contours:

x, y, w, h = cv2.boundingRect(contour)

if contour_area_min < cv2.contourArea(contour) < contour_area_max and \

arc_length_min < cv2.arcLength(contour, True) < arc_length_max and \

offset_min < x < offset_max:

cv2.rectangle(image_raw, (x, y), (x + w, y + h), (0, 0, 255), 2)

offset = x

cv2.imwrite('image_label.png', image_raw)

print('offset', offset)