文字点选验证码本质是目标检测或OCR+后处理任务,需通过ddddocr的detect方法获取文字bbox,再映射为页面坐标点击;须注意截图方式、坐标转换、通道格式及前端反爬限制。

文字点选验证码的本质是图像分类问题,不是“点击”而是“识别坐标”
文字点选验证码(比如“点击图中所有‘苹果’”)表面上看要模拟点击,实际开发中必须先定位文字区域——这本质上是个目标检测或OCR+后处理任务。直接用 selenium 模拟鼠标点击所有疑似位置,失败率极高,因为字体变形、背景干扰、文字粘连会让坐标偏移超过10像素,而人眼可接受的点击误差通常在5像素内。
真正可行的路径是:截图 → 裁剪验证码区域 → 用OCR提取文字及bbox(边界框)→ 匹配关键词 → 计算相对于浏览器窗口的点击坐标 → 执行点击。
- 优先用
ddddocr(支持带干扰的文字点选模型),它内置了训练好的轻量点选识别器,比通用OCR(如pytesseract)准确率高3倍以上 - 若验证码含艺术字或强扭曲,需配合
cv2做预处理:灰度化 → 高斯模糊 → 自适应二值化 → 形态学去噪 - 注意:截图时务必用
driver.get_screenshot_as_png()而非driver.save_screenshot(),后者可能因缩放导致坐标错位
用 ddddocr 直接识别点选文字并返回坐标
ddddocr 的 classification 模式只返回文字,但它的 detect 方法能输出每个字符/词的 bbox(左上x/y、右下x/y),这才是点选需要的核心数据。
示例关键代码:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
from ddddocr import DdddOcr
import cv2
<p>ocr = DdddOcr(det=True) # 启用检测模式
img_bytes = driver.find_element("id", "captcha-img").screenshot_as_png
img_array = np.frombuffer(img_bytes, np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)</p><h1>返回格式:[{"text": "苹果", "score": 0.92, "box": [x1,y1,x2,y2]}, ...]</h1><p>results = ocr.detection(img)
target_words = ["苹果", "香蕉"]
for r in results:
if r["text"] in target_words:
x = (r["box"][0] + r["box"][2]) // 2
y = (r["box"][1] + r["box"][3]) // 2</p><h1>转换为页面坐标后点击...</h1>- 返回的
box是图像内坐标,需结合元素在页面中的位置(element.location和element.size)做映射 - 如果
results为空,大概率是截图未对准——检查是否等到了图片加载完成(用WebDriverWait等待visibility_of_element_located) - 不要依赖
score过滤,某些干扰严重时score会压到0.3以下但仍正确;建议用编辑距离匹配关键词
坐标映射容易出错的三个关键环节
从图片内坐标到浏览器真实点击点,要过三道转换,任一环节出错都会点偏:
-
img是元素截图,但element.location返回的是元素左上角相对于当前视口的位置,需加上driver.execute_script("return window.scrollY")补偿滚动偏移 - 浏览器缩放(如用户设了125%)会导致
element.size返回的宽高与实际像素不符,此时应改用element.rect(返回包含缩放校正后的坐标) - OpenCV 默认BGR通道,但
ddddocr输入要求RGB,漏转会导致识别率暴跌——用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
绕过前端反爬的隐藏限制
很多网站在点选后会校验两次:一是后端比对点击坐标是否落在文字区域内,二是前端埋点验证点击事件是否由真实鼠标触发(比如检查 event.buttons 是否为1、event.isTrusted 是否为 True)。直接用 ActionChains(driver).move_to_element_with_offset().click() 会被识别为脚本操作。
- 用
driver.execute_script()注入原生MouseEvent更可靠,例如:driver.execute_script("arguments[0].dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true}));", element) - 但注意:这样点击的是整个元素,不是指定坐标。真要坐标级点击,得用
driver.execute_script("...document.elementFromPoint(x,y).click()..."),前提是x/y已精确换算到页面坐标系 - 部分站点会监听
mousedown事件里的clientX/clientY,这时必须用driver.execute_script()模拟完整事件链(mousemove→mousedown→mouseup),且时间间隔不能为0
最麻烦的其实是动态token:点选完成后,前端常生成一个加密签名(如 captcha_token)随表单提交。这个token往往依赖点击坐标的哈希、时间戳、甚至Canvas指纹——不逆向JS就无法稳定通过。这时候,自动化识别只是第一步,后面还得啃JS逻辑。

















