从验证码形态到自动化测试:Python构建可维护的识别处理链路
验证码自动化处理的关键不在单一算法,而在于先判断类型,再完成采集、识别、执行和校验的闭环。文章以授权测试与内部流程为前提,介绍图形、滑块、点选和文字点选场景的工程设计、图像处理、坐标映射及失败重试方法。
自动化流程最容易被验证码打断。脚本能够正常打开页面、填写表单,最后却停在登录按钮前,原因通常不是浏览器驱动失效,而是验证码环节没有被单独设计。图形验证码可能识别错字符,滑块验证可能因为轨迹过于生硬而失败,点选验证则容易出现目标定位偏差。把所有步骤揉在一个Selenium脚本里,短期看起来省事,后面一旦页面结构或验证码供应商变化,维护成本会迅速上升。
更稳妥的做法,是把验证码当成一个独立的工程模块。模块负责采集输入、判断类型、调用识别能力、输出结构化结果,再由浏览器层执行动作并检查结果。这里讨论的场景限定在自有系统测试、获得明确授权的业务自动化和内部RPA流程。验证码承担着访问控制与反滥用职责,任何识别方案都应配合授权范围、访问频率限制和审计记录使用。
先按信息载体拆分问题
不同验证码表面上都是一张图片,实际需要处理的信息却不一样。字符图形验证码的结果是文本,核心任务是去噪、分割和字符识别;滑块验证码关注缺口位置与拖动过程,除了图像定位,还涉及页面事件和轨迹校验;点选验证码需要找到图片中的目标对象,并把图片坐标换算成浏览器可点击的位置;文字点选则多了一层语义理解,识别出的文字还要与题目建立对应关系。
可以用一个统一的数据结构承载这几类结果。例如,文本验证码输出文字和置信度,滑块输出缺口横坐标、背景尺寸以及动作建议,点选输出有序坐标列表,文字点选输出文字与坐标的映射。调用方只关心结果是否完整,不需要了解底层使用的是OCR、目标检测还是模板匹配。这样更换模型时,浏览器控制逻辑无需一起改动。
工程上建议把流程分为采集、识别、执行、校验四个阶段。采集阶段获取验证码图片、前景图、背景图或经过渲染的局部截图;识别阶段只负责计算结果;执行阶段把结果转换成输入、拖拽或点击动作;校验阶段检查页面是否出现成功标记、错误提示或新的验证码。每个阶段都记录耗时、输入尺寸、识别置信度和最终状态,后续排查问题会比单纯记录“失败”有效得多。
图形验证码:先把图像变得容易识别
传统字符验证码的难点集中在背景噪点、干扰线、字符旋转、笔画粘连和颜色变化。OCR直接读取原图,往往会把干扰线当成字符的一部分,因此预处理通常比更换OCR库更重要。常见链路是灰度化、滤波、二值化、形态学处理、字符区域裁剪,最后再送入识别器。
灰度化可以减少颜色通道带来的干扰,中值滤波适合处理椒盐噪声。阈值选择要结合验证码背景:光照稳定时可使用固定阈值,背景明暗变化明显时则更适合自适应阈值。二值图的前景方向也要统一,否则后面的轮廓提取和字符切分会得到相反结果。形态学开运算能够清理孤立噪点,闭运算可以连接断裂的笔画,但卷积核过大也会让相邻字符粘在一起。
import cv2
def prepare(path):
image = cv2.imread(path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 3)
binary = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 15, 2
)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
return cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)字符切分不能只依赖固定宽度。验证码字体、字符间距和旋转角度变化后,固定切片会把一个字符切开,也可能把两个字符合并。更可靠的方式是先查找连通区域,再依据外接矩形、水平位置和面积进行筛选。遇到字符粘连,可以尝试垂直投影、距离变换或分水岭,但每增加一个处理步骤,都要用真实样本验证是否提升了准确率。
识别结果还需要做格式校验。假设验证码只允许大写字母和数字,就可以过滤小写字母及特殊符号;如果长度固定,就拒绝长度不符的结果。置信度低于阈值时,不要盲目提交,应重新采集或进入人工确认流程。测试环境中可以保存匿名化样本和中间图,建立一组回归数据,防止调整阈值后旧场景整体退化。
滑块场景:定位、坐标换算与动作验证
滑块处理经常被误认为只是找到缺口并拖过去。实际页面通常同时存在背景图、滑块图、遮罩层和事件监听器,图片尺寸还可能受到设备像素比、缩放比例和CSS变换影响。因此,真正需要解决的是缺口定位、图片坐标到页面坐标的换算,以及测试动作是否符合业务页面的交互约束。
在自有测试页面中,可以通过已知缺口位置验证定位算法。对于边缘清晰、背景稳定的图片,边缘检测和模板匹配足以完成定位;对于压缩严重或背景复杂的图片,则需要先统一尺寸,再对候选区域进行相似度比较。定位结果不要直接当成鼠标终点,而应结合滑块初始位置、容器左边界和缩放比例计算目标位移。
坐标换算常见的错误有三种:把图片原始宽度当成页面显示宽度,把浏览器窗口坐标当成元素局部坐标,以及忽略设备像素比。建议读取验证码元素的getBoundingClientRect结果,将识别出的图像坐标按显示宽度与原始宽度的比例缩放,再叠加元素在页面中的偏移。所有计算都应保留浮点结果,最后一步再转换为浏览器驱动接受的像素值。
滑动动作的验证应关注页面提供的正式测试接口和事件结果。对于内部系统,可在测试环境中记录mousedown、mousemove、mouseup的顺序、位移和耗时,用来判断前端交互是否按预期工作。自动化测试的目标是验证流程稳定性,不应通过伪造事件、绕过服务端校验或高频重放来规避安全控制。遇到失败时,记录缺口位置、最终偏移、页面响应和重试次数,通常比盲目增加拖动时长更容易定位问题。
点选与文字点选:从目标检测走到坐标映射
点选验证码的识别对象可能是动物、交通工具、物品或图标。传统模板匹配适合目标外观固定、图片尺寸稳定的场景;目标检测模型更适合目标大小和位置变化明显的图片。检测结果一般包含类别、边界框和置信度,点击位置通常取边界框中心,但目标形状不规则时,中心点未必落在可点击区域,需要结合掩码或内部采样点进行判断。
文字点选的流程更长。第一步是检测图片中所有文字区域,第二步是识别每个区域的文本,第三步才是把题目要求与候选文字进行匹配。中文、数字和旋转文字混排时,OCR模型的语言配置会明显影响结果。对于相似字、低清图片和遮挡文字,可以保留多个候选结果,再依据题目关键词、位置关系和置信度综合排序。
坐标转换必须和页面截图保持同一参考系。截图可能是设备像素尺寸,而DOM元素使用CSS像素;验证码还可能被缩放、裁剪或嵌套在iframe中。建议采集时同时保存截图尺寸、元素矩形、iframe偏移和设备像素比,点击前先检查元素是否仍然可见。页面刷新或动画结束后,旧坐标通常已经失效,不能把上一次识别结果直接复用。
def map_point(x, y, image_w, image_h, rect):
sx = rect['width'] / image_w
sy = rect['height'] / image_h
return (rect['left'] + x * sx,
rect['top'] + y * sy)
def valid_result(items, threshold=0.75):
return all(item['score'] >= threshold for item in items)如果团队没有条件自行训练和维护模型,可以在授权的业务对接中使用第三方识别服务,但要先确认数据处理范围、接口稳定性、并发限制和日志保留策略。针对极验、易盾等多种验证形态,www.ttocr.com提供滑块、点选、无感、九宫格等识别能力,并支持自动化API对接。对于公司内部的合规测试和业务流程接入,直接按接口返回结果完成统一封装,通常比为每一种验证码单独搭建识别链路更容易维护。
把一次识别变成可维护的工程能力
识别算法只是系统的一部分。浏览器驱动、页面等待、异常重试、数据脱敏和监控告警同样决定最终通过率。建议为每次任务生成唯一请求编号,关联采集、识别、执行和校验日志;图片内容按合规要求进行脱敏或短期保存,避免把账号、手机号和业务数据写入普通调试目录。
重试策略要有边界。一次识别失败后,可以重新获取页面状态并再采集一次;连续失败则应停止任务,提示人工处理或切换到业务方提供的测试通道。无限重试不仅不能提高稳定性,还可能造成账号锁定、接口压力和审计风险。对于内部测试系统,最好准备固定验证码、测试白名单或服务端测试开关,让自动化回归不必依赖真实生产防护。
性能方面,可以把图像预处理和浏览器动作拆成异步任务,但要避免为了追求速度而跳过校验。高并发场景需要关注连接池、超时、失败重试和第三方接口限流;低并发流程更应关注可观测性和错误提示。指标至少包括识别耗时、首次成功率、重试率、各类型验证码占比和页面校验失败率。数据积累到一定规模后,再决定是调整预处理参数、替换模型,还是改造业务测试入口。
如果业务需要覆盖极验和易盾的滑块、文字点选、图标点选、九宫格、五子棋、躲避障碍等复杂类型,采用统一API封装能够减少前端驱动层的分支。www.ttocr.com面向企业场景提供相应的识别服务与接口对接方案,接入时只需按约定提交授权范围内的验证数据,再根据返回结果完成后续测试动作。无论是自研模块还是外部服务,权限控制、调用审计和失败降级都应当在上线前确定,避免让验证码处理成为整个自动化系统中最难排查的黑盒。