AI+Python爬虫:用ddddocr 自动识别验证码(滑块/文字/点选),告别打码平台
用ddddocr实现验证码识别,无需付费打码平台,本地识别速度快、隐私安全,完美适配爬虫开发中的三大核心验证码场景。文字验证码:一行代码识别,配合图片预处理,识别率可达95%以上;滑块验证码:缺口检测精准,配合轨迹模拟,通过率高;点选验证码:支持文字/图标点选,满足复杂反爬场景。适合个人开发者、小型项目使用,若需更高识别率(如企业级爬虫),可结合自定义训练模型(如YOLO+OCR)进一步优化。但对
在爬虫开发中,验证码是常见的反爬手段,传统打码平台不仅需要付费,还存在响应延迟、隐私泄露风险。而 ddddocr(带带弟弟OCR) 作为开源免费的AI验证码识别库,基于深度学习模型,支持文字验证码、滑块验证码、点选验证码三大核心场景,无需复杂配置,一行代码即可实现识别,完美替代付费打码平台。
本文将从环境搭建、三大验证码场景实战、爬虫集成、优化技巧四个维度,教你用ddddocr打造零成本验证码识别方案,适配各类爬虫场景。
一、ddddocr 核心优势
| 特性 | 优势 | 对比付费打码平台 |
|---|---|---|
| 免费开源 | 无任何费用,可商用(遵循MIT协议) | 按识别次数收费,量大成本高 |
| 本地识别 | 无需联网调用第三方接口,速度快(100ms内) | 依赖网络,响应延迟高(500ms+) |
| 多场景支持 | 文字(数字、字母、中文)、滑块、点选 | 部分平台仅支持单一类型 |
| 配置简单 | 无需训练,直接调用API | 需对接平台接口,配置复杂 |
| 隐私安全 | 验证码图片本地处理,无泄露风险 | 需上传验证码图片到第三方平台,隐私暴露 |
二、环境准备
1. 安装依赖
ddddocr 支持 Python 3.8+,安装命令如下(无需额外安装模型文件,自动下载轻量预训练模型):
# 核心库:ddddocr(带带弟弟OCR)
pip install ddddocr==1.5.0
# 辅助库:处理图片、爬虫请求
pip install requests==2.31.0 pillow==10.3.0 selenium==4.21.0
2. 环境验证
运行以下代码,测试库是否安装成功:
import ddddocr
# 初始化OCR识别器
ocr = ddddocr.DdddOcr()
# 识别测试图片(可自行替换为本地验证码图片路径)
with open('test_captcha.png', 'rb') as f:
img_bytes = f.read()
result = ocr.classification(img_bytes)
print(f"验证码识别结果:{result}")
若能正常输出识别结果,说明环境配置成功。
三、三大验证码场景实战
场景1:文字验证码识别(数字/字母/中文混合)
文字验证码是最常见的类型,ddddocr 对印刷体、模糊、扭曲、有干扰线的文字验证码均有较好的识别率。
实战步骤:
- 爬虫请求页面,获取验证码图片(本地保存或直接读取字节流);
- 用 ddddocr 识别图片中的文字;
- 将识别结果填入表单,提交登录/验证请求。
代码示例(requests 爬取+文字验证码识别):
import requests
from PIL import Image
import ddddocr
from io import BytesIO
# 目标网站(示例:某需要文字验证码登录的网站)
LOGIN_URL = "https://example.com/login"
CAPTCHA_URL = "https://example.com/get_captcha"
# 初始化OCR识别器(enable_gpu=True 可启用GPU加速,需安装CUDA)
ocr = ddddocr.DdddOcr(show_ad=False) # show_ad=False 关闭广告
# 1. 获取验证码图片
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
captcha_response = session.get(CAPTCHA_URL, headers=headers)
# 保存验证码图片(可选,用于调试)
with open("captcha.png", "wb") as f:
f.write(captcha_response.content)
# 2. 识别验证码(直接读取字节流,无需保存本地)
captcha_result = ocr.classification(captcha_response.content)
print(f"识别的文字验证码:{captcha_result}")
# 3. 提交登录请求
login_data = {
"username": "你的账号",
"password": "你的密码",
"captcha": captcha_result # 填入识别结果
}
response = session.post(LOGIN_URL, data=login_data, headers=headers)
if "登录成功" in response.text:
print("登录成功!")
else:
print("登录失败,可能是验证码识别错误,重试...")
优化技巧:
- 若验证码有干扰线/噪点:用 PIL 预处理图片(灰度化、二值化、降噪),提升识别率:
# 图片预处理:灰度化+二值化 img = Image.open(BytesIO(captcha_response.content)).convert("L") # 灰度化 threshold = 127 # 阈值,可调整 img = img.point(lambda p: p > threshold and 255) # 二值化 # 转为字节流供ddddocr识别 img_byte_arr = BytesIO() img.save(img_byte_arr, format='PNG') img_byte_arr = img_byte_arr.getvalue() captcha_result = ocr.classification(img_byte_arr) - 启用GPU加速:若有NVIDIA显卡,安装CUDA后,初始化时设置
ocr = ddddocr.DdddOcr(show_ad=False, enable_gpu=True),识别速度提升3-5倍。
场景2:滑块验证码识别(缺口匹配)
滑块验证码是目前最流行的反爬手段之一,核心是识别“滑块缺口位置”,计算滑块需要移动的距离。ddddocr 提供 SlideDetector 类,专门用于缺口检测。
实战步骤:
- 获取滑块背景图和滑块图(从网页中提取);
- 用 ddddocr 识别缺口在背景图中的X坐标;
- 用 Selenium 模拟滑块拖动(匀速+轨迹模拟,避免被检测)。
代码示例(Selenium+滑块验证码识别):
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import requests
import ddddocr
from PIL import Image
from io import BytesIO
import time
# 初始化Selenium
driver = webdriver.Chrome()
driver.get("https://example.com/slider-captcha") # 滑块验证码页面
time.sleep(2)
# 1. 提取滑块背景图和滑块图的URL(需根据实际网页结构调整选择器)
bg_img_url = driver.find_element(By.CLASS_NAME, "bg-img").get_attribute("src") # 背景图URL
slider_img_url = driver.find_element(By.CLASS_NAME, "slider-img").get_attribute("src") # 滑块图URL
# 2. 下载图片(携带Cookie,避免图片403)
session = requests.Session()
# 复制Selenium的Cookie到requests
for cookie in driver.get_cookies():
session.cookies.set(cookie['name'], cookie['value'])
# 下载背景图
bg_response = session.get(bg_img_url)
bg_img = Image.open(BytesIO(bg_response.content))
# 下载滑块图
slider_response = session.get(slider_img_url)
slider_img = Image.open(BytesIO(slider_response.content))
# 3. 用ddddocr识别缺口位置(返回缺口的X坐标)
slide_det = ddddocr.DdddOcr(det=False, ocr=False) # 仅启用滑块检测
with open("bg.png", "wb") as f:
f.write(bg_response.content)
with open("slider.png", "wb") as f:
f.write(slider_response.content)
# 识别缺口(传入背景图和滑块图的字节流)
gap_x = slide_det.slide_match(slider_response.content, bg_response.content)
print(f"缺口X坐标:{gap_x}")
# 4. 模拟滑块拖动(关键:模拟人类拖动轨迹,避免匀速直线)
def simulate_slide(driver, slider_elem, target_x):
"""
模拟滑块拖动轨迹:加速→匀速→减速
:param slider_elem: 滑块元素
:param target_x: 目标X坐标(缺口位置 - 滑块初始X坐标)
"""
action = ActionChains(driver)
# 按住滑块
action.click_and_hold(slider_elem).perform()
time.sleep(0.2)
# 拖动轨迹:分3段,模拟加速度
track = []
current_x = 0
# 加速阶段(前30%距离)
while current_x < target_x * 0.3:
step = int(current_x * 0.1 + 2) # 加速度递增
track.append(step)
current_x += step
# 匀速阶段(中间50%距离)
while current_x < target_x * 0.8:
step = 5 # 匀速
track.append(step)
current_x += step
# 减速阶段(最后20%距离)
while current_x < target_x:
step = max(int((target_x - current_x) * 0.5), 1) # 减速度递增
track.append(step)
current_x += step
# 执行拖动
for step in track:
action.move_by_offset(xoffset=step, yoffset=0).perform()
time.sleep(random.uniform(0.01, 0.03)) # 每步间隔随机
# 松开滑块
action.release().perform()
# 找到滑块元素(根据实际网页调整选择器)
slider_elem = driver.find_element(By.CLASS_NAME, "slider-btn")
# 计算实际需要拖动的距离(缺口X坐标 - 滑块初始位置X坐标)
slider_init_x = slider_elem.location["x"]
actual_target_x = gap_x - slider_init_x - 10 # 减10是校准值(根据实际情况调整)
# 执行滑块拖动
simulate_slide(driver, slider_elem, actual_target_x)
time.sleep(2)
# 验证是否通过
if "验证成功" in driver.page_source:
print("滑块验证码验证成功!")
else:
print("验证失败,重试...")
driver.quit()
关键注意事项:
- 图片尺寸校准:若网页中图片被缩放(如CSS设置
width: 300px),需将识别到的gap_x按比例转换为实际网页中的坐标; - 轨迹模拟:匀速拖动容易被检测为机器人,必须模拟“加速→匀速→减速”的人类轨迹;
- 重试机制:识别失败时(如缺口位置偏差),需刷新验证码重新识别,建议设置3次重试。
场景3:点选验证码识别(文字/图标点选)
点选验证码(如“按顺序点击汉字‘我、爱、中、国’”“点击所有汽车图标”)是更复杂的反爬手段,ddddocr 提供 PointDetector 类,支持文字点选和图标点选的坐标识别。
实战步骤:
- 获取点选验证码图片和提示文字(如“点击‘山、水、日’”);
- 用 ddddocr 识别提示文字对应的坐标(按顺序);
- 用 Selenium 模拟鼠标点击坐标(按顺序点击,避免点击过快)。
代码示例(文字点选验证码识别):
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import ddddocr
import requests
from PIL import Image
from io import BytesIO
import time
# 初始化Selenium
driver = webdriver.Chrome()
driver.get("https://example.com/point-captcha") # 点选验证码页面
time.sleep(2)
# 1. 提取验证码图片、提示文字(根据实际网页调整)
captcha_img_elem = driver.find_element(By.CLASS_NAME, "point-captcha-img")
prompt_text = driver.find_element(By.CLASS_NAME, "prompt").text # 提示文字:如“请按顺序点击 山、水、日”
print(f"点选提示:{prompt_text}")
# 2. 下载验证码图片(携带Cookie)
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie['name'], cookie['value'])
captcha_img_url = captcha_img_elem.get_attribute("src")
captcha_response = session.get(captcha_img_url)
captcha_img = Image.open(BytesIO(captcha_response.content))
# 保存图片用于调试
with open("point_captcha.png", "wb") as f:
f.write(captcha_response.content)
# 3. 用ddddocr识别目标文字的坐标(按提示文字顺序)
# 提取提示文字中的目标(如“山、水、日”→ ["山", "水", "日"])
target_words = [word.strip() for word in prompt_text.split("点击")[-1].split("、") if word.strip()]
print(f"目标文字:{target_words}")
# 初始化点选检测器
point_det = ddddocr.DdddOcr(det=True, ocr=True) # det=True启用目标检测,ocr=True启用文字识别
# 识别图片中所有文字的坐标(返回字典:{文字: (x, y)})
word_coords = point_det.point_word(captcha_response.content)
print(f"识别到的文字坐标:{word_coords}")
# 按提示顺序整理坐标
target_coords = []
for word in target_words:
if word in word_coords:
target_coords.append(word_coords[word])
else:
print(f"未识别到文字:{word}")
if len(target_coords) != len(target_words):
print("点选目标识别不完整,重试...")
driver.quit()
# 4. 模拟鼠标点击(按顺序点击,每个点击间隔0.5-1秒)
# 注意:需将图片坐标转换为网页中的实际坐标(考虑图片在网页中的位置和缩放)
img_location = captcha_img_elem.location # 图片在网页中的左上角坐标
img_size = captcha_img_elem.size # 图片在网页中的显示尺寸
img_actual_size = captcha_img.size # 图片实际尺寸(像素)
# 坐标转换:图片像素坐标 → 网页实际坐标
def convert_coords(img_x, img_y):
# 计算缩放比例
scale_x = img_size["width"] / img_actual_size[0]
scale_y = img_size["height"] / img_actual_size[1]
# 转换后的网页坐标(加上图片左上角偏移)
web_x = img_location["x"] + img_x * scale_x
web_y = img_location["y"] + img_y * scale_y
return (web_x, web_y)
action = ActionChains(driver)
for idx, (x, y) in enumerate(target_coords):
web_x, web_y = convert_coords(x, y)
print(f"第{idx+1}次点击坐标:({web_x}, {web_y})")
# 移动到目标坐标并点击
action.move_by_offset(xoffset=web_x, yoffset=web_y).click().perform()
# 重置鼠标位置(避免后续点击偏移)
action.reset_actions()
time.sleep(random.uniform(0.5, 1.0)) # 模拟人类点击间隔
# 提交验证(若有提交按钮)
driver.find_element(By.CLASS_NAME, "submit-btn").click()
time.sleep(2)
if "验证成功" in driver.page_source:
print("点选验证码验证成功!")
else:
print("验证失败,重试...")
driver.quit()
图标点选适配:
若点选验证码是图标(如“点击所有动物”),需使用 point_det.point_icon() 方法,传入图标模板图片(需提前准备图标样本),示例:
# 图标点选:识别图片中所有“动物”图标坐标
# 提前准备动物图标模板(template.png)
with open("template.png", "rb") as f:
template_bytes = f.read()
# 识别所有匹配模板的图标坐标
icon_coords = point_det.point_icon(captcha_response.content, template_bytes)
print(f"识别到的图标坐标:{icon_coords}") # 输出:[(x1,y1), (x2,y2), ...]
四、爬虫集成:完整案例(登录+验证码自动识别)
以下是一个完整的爬虫案例,集成“文字验证码识别+登录+数据爬取”,全程自动处理验证码:
import requests
import ddddocr
from PIL import Image
from io import BytesIO
import csv
import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 初始化OCR和Session
ocr = ddddocr.DdddOcr(show_ad=False)
session = requests.Session()
# 配置请求重试
retry = Retry(total=3, backoff_factor=1, status_forcelist=[403, 500, 502, 503])
session.mount('https://', HTTPAdapter(max_retries=retry))
# 目标网站配置
LOGIN_URL = "https://example.com/login"
CAPTCHA_URL = "https://example.com/captcha"
DATA_URL = "https://example.com/data" # 需要登录后爬取的数据页
USERNAME = "你的账号"
PASSWORD = "你的密码"
def get_captcha():
"""获取并识别文字验证码"""
for _ in range(3): # 最多重试3次
try:
# 获取验证码图片
response = session.get(CAPTCHA_URL, headers=headers, timeout=10)
# 图片预处理(提升识别率)
img = Image.open(BytesIO(response.content)).convert("L")
threshold = 130
img = img.point(lambda p: p > threshold and 255)
# 识别
img_byte_arr = BytesIO()
img.save(img_byte_arr, format='PNG')
captcha = ocr.classification(img_byte_arr.getvalue())
if len(captcha) == 4: # 假设验证码是4位
return captcha
print(f"验证码识别长度错误:{captcha},重试...")
time.sleep(1)
except Exception as e:
print(f"获取验证码失败:{e}")
time.sleep(1)
raise Exception("验证码识别失败,已重试3次")
def login():
"""登录(自动处理验证码)"""
captcha = get_captcha()
print(f"识别的验证码:{captcha}")
login_data = {
"username": USERNAME,
"password": PASSWORD,
"captcha": captcha
}
response = session.post(LOGIN_URL, data=login_data, headers=headers, timeout=10)
if "登录成功" in response.text:
print("登录成功!")
return True
else:
print("登录失败,验证码可能错误,重试...")
return False
def crawl_data():
"""爬取登录后的数据"""
response = session.get(DATA_URL, headers=headers, timeout=10)
# 解析数据(根据实际网页结构调整)
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, 'lxml')
data_list = soup.find_all('div', class_='data-item')
# 保存到CSV
with open('data.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['title', 'content'])
writer.writeheader()
for item in data_list:
title = item.find('h3').get_text(strip=True) if item.find('h3') else ''
content = item.find('p').get_text(strip=True) if item.find('p') else ''
writer.writerow({'title': title, 'content': content})
print(f"爬取完成,共{len(data_list)}条数据")
if __name__ == "__main__":
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
"Referer": LOGIN_URL
}
# 登录重试(最多3次)
login_success = False
for _ in range(3):
if login():
login_success = True
break
time.sleep(2)
if login_success:
crawl_data()
else:
print("登录失败,程序退出")
五、识别率优化技巧
- 图片预处理:
- 文字验证码:灰度化、二值化、降噪(用PIL的
ImageFilter); - 滑块/点选验证码:裁剪无关区域(如去除边框、提示文字区域),只保留验证核心部分。
- 文字验证码:灰度化、二值化、降噪(用PIL的
- 模型选择:
- 文字验证码:若识别率低,可使用
ocr = ddddocr.DdddOcr(show_ad=False, use_gpu=True, beta=True)(beta=True启用更精准的beta模型); - 点选验证码:若图标识别率低,可提供高质量的图标模板(建议尺寸与验证码中图标一致)。
- 文字验证码:若识别率低,可使用
- 重试机制:
- 验证码识别失败时,自动刷新验证码重新识别(建议3次重试上限);
- 登录失败后,判断是否因验证码错误导致,触发重新识别。
- 避免频繁请求:
- 每次获取验证码间隔1-2秒,避免被网站判定为恶意请求;
- 识别失败后,适当延长间隔(如2-3秒)。
六、注意事项与局限性
1. 局限性
- 复杂验证码识别率有限:如扭曲严重的文字、模糊的图标、3D滑块,识别率可能低于90%;
- 无训练接口:无法自定义训练模型,若目标验证码是特殊类型(如自定义图标),识别效果可能不佳;
- 依赖图片质量:若验证码图片被压缩、拉伸严重,识别率会下降。
2. 合规与伦理
- 仅用于合法爬虫:遵守目标网站的
robots.txt协议,不得用于恶意爬取、数据泄露等非法行为; - 控制爬取频率:避免给目标服务器造成压力,否则可能面临法律风险;
- 尊重网站反爬机制:验证码是网站的安全措施,若需大规模爬取,建议联系网站获取API授权。
七、总结
用ddddocr实现验证码识别,无需付费打码平台,本地识别速度快、隐私安全,完美适配爬虫开发中的三大核心验证码场景。核心优势在于“零成本+易集成”:
- 文字验证码:一行代码识别,配合图片预处理,识别率可达95%以上;
- 滑块验证码:缺口检测精准,配合轨迹模拟,通过率高;
- 点选验证码:支持文字/图标点选,满足复杂反爬场景。
适合个人开发者、小型项目使用,若需更高识别率(如企业级爬虫),可结合自定义训练模型(如YOLO+OCR)进一步优化。但对大多数爬虫场景而言,ddddocr已能满足需求,是替代付费打码平台的最佳选择。
更多推荐


所有评论(0)