前言
在进行网络爬虫数据采集、自动化测试(如 Selenium/Playwright)或者自动化脚本编写时,验证码(CAPTCHA) 往往是开发者面临的第一道、也是最头疼的屏障。
传统应对验证码的方案通常有两种:
- 接入第三方付费打码平台:按次收费,不仅产生持续的资金成本,且存在网络延迟和接口失效风险。
- 自己训练深度学习模型(CNN+CTC):需要采集数万张标注样本,配置 PyTorch 环境进行繁琐的训练,技术门槛极高。
直到开源项目 sml2h3/ddddocr(中文名:带带弟弟 OCR)的出现,彻底改变了这一切。它是一个离线运行、完全免费、零配置的通用验证码识别 SDK。你不需要懂得任何神经网络知识,只需一行代码,就能实现极高准确率的验证码识别。
本文将带你全面了解 ddddocr,并展示如何在真实的 Python 爬虫项目中实际运用它。
一、DdddOcr 的核心特点
- 零配置,开箱即用:不需要下载额外的权重文件,也不需要复杂的特征工程,安装后直接加载即可运行。
- 支持超多验证码类型:
- 英数混合验证码:最常见的扭曲、带干扰线、噪点的字母数字验证码。
- 滑块验证码缺口检测:计算滑块背景图与缺口小图之间的精准 X 轴偏移距离。
- 点选/点击验证码:识别出图片中文字或物体的具体坐标。
- 100% 离线与高效:基于 ONNX Runtime 推理引擎,不需要联网,单张图片识别仅需 10~30 毫秒。
二、开发环境搭建与避坑指南
1. 基础安装
在命令行中直接通过 pip 安装:
2. 常见报错及解决方案
由于 ddddocr 发布时间较早,在较新的 Python 环境中可能会遇到以下兼容性问题:
⚠️ 报错一:AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
- 原因:较新版本的 Pillow 库(大于 10.0.0)移除了已经过时的
ANTIALIAS 属性。
- 解决办法:回退 Pillow 库到 9.x 版本:
1
| pip install "Pillow<10.0.0"
|
⚠️ 报错二:安装时报错,提示缺少 C++ 编译环境
三、三大验证码核心识别代码
1. 英数混合验证码(普通打码)
这是最基础的用法,直接输入验证码图片的二进制字节流(bytes),即可返回识别出来的字符串结果:
1 2 3 4 5 6 7 8 9 10 11 12
| import ddddocr
ocr = ddddocr.DdddOcr(show_ad=False)
with open("captcha.png", "rb") as f: img_bytes = f.read()
result = ocr.classification(img_bytes) print(f"验证码识别结果: {result}")
|
2. 滑块验证码(缺口距离检测)
在滑块验证码中,前端往往要求我们把滑块从左侧拖动到右侧的缺口处。要模拟这个动作,我们必须知道拖动的具体像素距离(Offset)。
ddddocr 提供了非常强大的滑块缺口计算方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import ddddocr
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
with open("target.png", "rb") as f: target_bytes = f.read()
with open("background.png", "rb") as f: background_bytes = f.read()
res = det.slide_match(target_bytes, background_bytes, simple_target=True)
offset = res['target'][0] print(f"滑块缺口的 X 轴偏移距离: {offset} 像素")
|
3. 点选/点击验证码
点选验证码通常会给出一张大图,上方提示“请依次点击:【中】【国】”。我们需要获取这些字符在大图上的坐标。
通过 ddddocr 的目标检测(Detection)模式可以完美解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import ddddocr import cv2
det = ddddocr.DdddOcr(det=True, show_ad=False)
with open("click_captcha.png", "rb") as f: img_bytes = f.read()
bboxes = det.detection(img_bytes)
print("检测到的文字/物体包围盒坐标:") for box in bboxes: x1, y1, x2, y2 = box center_x = int((x1 + x2) / 2) center_y = int((y1 + y2) / 2) print(f"目标区域: ({x1}, {y1}) -> ({x2}, {y2}) | 中心点击坐标: ({center_x}, {center_y})")
|
四、项目实战:Selenium + DdddOcr 自动破解登录验证码
接下来,我们将这些知识点融会贯通,写一个完整的爬虫实战案例:使用 Selenium 自动访问某系统登录页面,抓拍验证码图片并使用 ddddocr 识别,自动填入完成登录。
实战代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import time from io import BytesIO from PIL import Image from selenium import webdriver from selenium.webdriver.common.by import By import ddddocr
def login_with_captcha(): options = webdriver.ChromeOptions() options.add_argument("--start-maximized") driver = webdriver.Chrome(options=options)
ocr = ddddocr.DdddOcr(show_ad=False)
try: driver.get("https://example-login-site.com/login") time.sleep(2)
username_input = driver.find_element(By.ID, "username") password_input = driver.find_element(By.ID, "password") captcha_img_element = driver.find_element(By.ID, "captcha_img") captcha_input = driver.find_element(By.ID, "captcha_code") submit_btn = driver.find_element(By.ID, "login_submit")
captcha_png = captcha_img_element.screenshot_as_png image = Image.open(BytesIO(captcha_png)).convert("RGB") byte_io = BytesIO() image.save(byte_io, format="PNG") captcha_bytes = byte_io.getvalue()
captcha_text = ocr.classification(captcha_bytes) print(f"[AI Status] 验证码自动识别结果: {captcha_text}")
username_input.send_keys("admin") password_input.send_keys("MyPassword123") captcha_input.send_keys(captcha_text)
time.sleep(1) submit_btn.click() time.sleep(3)
if "dashboard" in driver.current_url.lower(): print("🎉 [Success] 登录成功!验证码识别无误。") else: print("⚠️ [Failed] 登录失败,可能是验证码识别错误,正在尝试重试...")
finally: driver.quit()
if __name__ == "__main__": login_with_captcha()
|
五、进阶篇:如何进一步提升 ddddocr 的识别精度?
虽然 ddddocr 的默认模型已经非常强悍,但在面对极个别噪点密集、对比度极低的魔鬼验证码时,仍然可能发生错判。你可以采用以下两项高级技巧来大幅提升准确率:
1. 图像预处理(二值化与去噪)
在将图片送入 ddddocr 之前,利用 Pillow 或 OpenCV 进行预处理,过滤干扰线:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| from PIL import Image import numpy as np
def preprocess_image(image_path): """ 对验证码进行降噪和二值化处理 """ img = Image.open(image_path).convert("L") threshold = 127 table = [] for i in range(256): if i < threshold: table.append(0) else: table.append(1) img = img.point(table, "1") return img
|
2. 避免重复实例化(性能优化)
在多线程爬虫或者高并发任务中,千万不要在每个函数循环里都写一遍 ocr = ddddocr.DdddOcr()。
每次实例化都会重新在内存中加载几十兆的 ONNX 模型,导致 CPU 瞬时占满、运行极慢甚至引发内存泄漏。
正确做法:将 ocr 定义为全局单例,或者通过类属性进行共享复用。
结语
ddddocr 的开源,无疑是广大爬虫与自动化测试开发者的巨大福音。它以极低的部署门槛和优秀的本地执行效率,帮助我们优雅地绕过了大多数常规字符、滑块和点选验证码。
安全提示:本文所介绍的验证码识别技术仅用于自动化测试、合规数据分析及学术研究目的。请在开发爬虫时遵守目标网站的 robots.txt 规则及相关法律法规。