滑动验证码是一种常见的安全机制,许多网站都会采用这种方式来防止自动化操作。极验和网易易盾是两个典型的滑动验证码提供商。以下是这种验证码的一般使用方式:
极验
网易易盾
用户会看到一个滑动条,旁边有提示文字“拖动滑块完成拼图”。用户需要按住滑块并将其拖拽到右侧的缺口位置。当滑块和缺口匹配时,验证成功。
自动化破解滑动验证码
要实现自动化破解滑动验证码的流程,主要有两个关键步骤:
识别滑块缺口的位置
将滑块拖动到对应位置
我们将重点介绍如何识别滑块缺口的位置。
基本原理
利用 OpenCV,可以实现滑动验证码缺口识别。输入一张带有缺口的验证码图片,输出缺口的位置(通常为缺口左侧的横坐标)。
示例图片
输入的验证码图片如下:
输出的识别结果如下:
实现步骤
通过以下几个主要步骤,我们可以用 OpenCV 进行图像处理来实现缺口识别:
高斯模糊滤波,消除部分噪声
边缘检测,识别滑块的边缘
轮廓筛选,确定缺口位置
准备工作
首先,需要安装 OpenCV 库。这里我们以 Java 语言为例,通过 OpenCV Java 绑定实现缺口识别。
安装 OpenCV
确保 OpenCV 已安装并配置好 Java 项目。可以参考 OpenCV 官方文档进行配置。
示例代码
java
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.util.List;
public class SlideCaptchaCrack {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
// 读取验证码图片
Mat imageRaw = Imgcodecs.imread("captcha.png");
int imageHeight = imageRaw.rows();
int imageWidth = imageRaw.cols();
// 高斯模糊处理
Mat imageGaussianBlur = new Mat();
Imgproc.GaussianBlur(imageRaw, imageGaussianBlur, new Size(5, 5), 0);
// 边缘检测
Mat imageCanny = new Mat();
Imgproc.Canny(imageGaussianBlur, imageCanny, 200, 450);
// 轮廓提取
List<MatOfPoint> contours = new java.util.ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(imageCanny, contours, hierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
// 轮廓筛选
double[] contourAreaThreshold = getContourAreaThreshold(imageWidth, imageHeight);
double[] arcLengthThreshold = getArcLengthThreshold(imageWidth, imageHeight);
double[] offsetThreshold = getOffsetThreshold(imageWidth);
Integer offset = null;
for (MatOfPoint contour : contours) {
Rect boundingRect = Imgproc.boundingRect(contour);
if (contourAreaThreshold[0] < Imgproc.contourArea(contour) && Imgproc.contourArea(contour) < contourAreaThreshold[1] &&
arcLengthThreshold[0] < Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true) && Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true) < arcLengthThreshold[1] &&
offsetThreshold[0] < boundingRect.x && boundingRect.x < offsetThreshold[1]) {
Imgproc.rectangle(imageRaw, new Point(boundingRect.x, boundingRect.y), new Point(boundingRect.x + boundingRect.width, boundingRect.y + boundingRect.height), new Scalar(0, 0, 255), 2);
offset = boundingRect.x;
}
}
// 保存结果图片
Imgcodecs.imwrite("image_label.png", imageRaw);
System.out.println("Offset: " + offset);
}
private static double[] getContourAreaThreshold(int imageWidth, int imageHeight) {
double contourAreaMin = (imageWidth * 0.15) * (imageHeight * 0.25) * 0.8;
double contourAreaMax = (imageWidth * 0.15) * (imageHeight * 0.25) * 1.2;
return new double[]{contourAreaMin, contourAreaMax};
}
private static double[] getArcLengthThreshold(int imageWidth, int imageHeight) {
double arcLengthMin = ((imageWidth * 0.15) + (imageHeight * 0.25)) * 2 * 0.8;
double arcLengthMax = ((imageWidth * 0.15) + (imageHeight * 0.25)) * 2 * 1.2;
return new double[]{arcLengthMin, arcLengthMax};
}
private static double[] getOffsetThreshold(int imageWidth) {
double offsetMin = 0.2 * imageWidth;
double offsetMax = 0.85 * imageWidth;
return new double[]{offsetMin, offsetMax};
}
}
代码说明
读取验证码图片:使用 Imgcodecs.imread 读取图片。
高斯模糊处理:使用 Imgproc.GaussianBlur 进行高斯模糊处理。
边缘检测:使用 Imgproc.Canny 进行边缘检测。
轮廓提取:使用 Imgproc.findContours 提取轮廓。
轮廓筛选:通过面积、周长、位置筛选目标轮廓,使用 Imgproc.boundingRect 获取外接矩形,使用 Imgproc.contourArea 计算轮廓面积,使用 Imgproc.arcLength 计算轮廓周长。
结果标注:使用 Imgproc.rectangle 标注目标轮廓,并保存结果图片。