滑块验证的两个子问题
滑块验证码(极验、顶象、各厂自研)的对抗拆成两个独立子问题:缺口识别(算出滑块要拖多少像素)和轨迹生成(怎么拖得像人)。本文讲第一个。
缺口识别的主流方案对比
| 方案 | 准确率 | 成本 | 适用 |
|---|---|---|---|
| 模板匹配 | 85-95% | 零成本 | 缺口是固定形状贴图 |
| 边缘检测+轮廓 | 90%+ | 零成本 | 缺口有明显边缘 |
| 深度学习(YOLO等) | 98%+ | 要训练 | 干扰多、缺口形态多变 |
| 打码平台 | 95%+ | 按次付费 | 不想维护任何代码 |
工程上先上模板匹配,准确率不够再升级——大多数滑块的缺口就是一张半透明贴图,模板匹配足够。
模板匹配:标准实现
滑块验证给两张图:背景图(有缺口)和滑块图(缺口贴图)。核心思路是在背景图上滑动滑块图,找匹配度最高的位置:
import cv2
import numpy as np
def find_gap(bg_path, slider_path):
bg = cv2.imread(bg_path)
slider = cv2.imread(slider_path)
# 1. 滑块图处理:提取缺口轮廓(滑块图通常带透明通道或纯色背景)
# 边缘检测强化轮廓
bg_edge = cv2.Canny(bg, 100, 200)
slider_edge = cv2.Canny(slider, 100, 200)
# 2. 模板匹配
result = cv2.matchTemplate(bg_edge, slider_edge, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
# max_loc[0] 就是缺口左上角 x 坐标
return max_loc[0], max_val
x, confidence = find_gap('bg.png', 'slider.png')
print(f'缺口 x=✅, 置信度={confidence}')精髓一:五个提升准确率的细节
- 先边缘检测再匹配。直接在原图上匹配会被背景纹理干扰(比如背景图里恰好有相似色块),Canny 边缘化之后匹配的是"形状",抗干扰能力强一个量级
- 滑块图要去背景。滑块贴图常带白色/透明底,直接匹配会把底色也算进去。用透明通道做 mask,或阈值化抠出滑块本体:
# 有 alpha 通道时
if slider.shape[2] == 4:
mask = slider[:, :, 3]
result = cv2.matchTemplate(bg_edge, slider_edge, cv2.TM_CCORR_NORMED, mask=mask)- 缩放对齐。页面显示的图和原图尺寸可能不同(响应式缩放),识别前确认图片实际像素与显示像素的比例,最终位移量要按比例换算
- 起始偏移。滑块初始位置不一定在 x=0(有的滑块条有左边距),最终位移 = 缺口x - 滑块初始x,别直接拿缺口 x 当拖动距离
- 置信度兜底。max_val 低于阈值(比如 0.5)说明匹配失败,触发重试(刷新验证码再来),别把错误结果提交上去浪费验证次数
精髓二:没有滑块图的变种怎么破
有些滑块只给一张背景图(缺口直接挖在背景里),没有独立滑块图。这时用缺口特征检测:
def find_gap_no_template(bg_path):
bg = cv2.imread(bg_path)
gray = cv2.cvtColor(bg, cv2.COLOR_BGR2GRAY)
edge = cv2.Canny(gray, 100, 200)
# 找轮廓,筛选"像缺口"的:面积适中、位置在右半区、长宽比接近1
contours, _ = cv2.findContours(edge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
x, y, w, h = cv2.boundingRect(c)
area = cv2.contourArea(c)
if 800 < area < 5000 and x > bg.shape[1] * 0.3 and 0.5 < w/h < 2:
return x
return None更稳的方案是双图对比:抓"无缺口的原始背景图"和"有缺口的背景图"(很多滑块服务会返回两张),像素级 diff,差异区域就是缺口:
diff = cv2.absdiff(bg_with_gap, bg_original)
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 30, 255, cv2.THRESH_BINARY)
# thresh 里最大的白色区域即缺口精髓三:识别只是入场券
把缺口识别做到 99% 准确率,提交后还是可能失败——因为滑块验证的核心校验在轨迹不在结果:
- 匀速直线拖动 = 机器,必挂
- 瞬间到位(耗时 50ms)= 机器,必挂
- 轨迹点间隔完全均匀 = 机器,必挂
识别对了只是"答案对了",轨迹要像人才能"交卷"。轨迹生成是下一个子问题(下篇详述)。
总结
- 缺口识别先上模板匹配:Canny 边缘化 + matchTemplate
- 五个细节:边缘化、去背景、缩放对齐、起始偏移、置信度兜底
- 无滑块图变种用轮廓筛选或双图 diff
- 识别只是入场券,轨迹生成才是核心校验
交流微信:run1255