在上一篇保姆级教程《2026年最新 教你0元搭建雨云自动签到,每日自动领积分续费》中,我们已经实现了利用 GitHub Actions 每天全自动白嫖雨云积分。不少读者私信问:"脚本怎么自动过验证码的?用的是 2captcha 打码平台吗?要花钱吗?" 答案是:一分钱不花,纯本地 AI 识别。 今天这篇文章就带你深入了解 Rainyun-Qiandao 项目背后的雨云签到验证码自动破解技术,看看它为什么能在 GitHub Actions 的免费环境里稳定运行,以及到底比 2captcha 等付费方案强在哪。
雨云使用的是 腾讯 TCaptcha(防水墙) 验证码,如果你做过签到就一定见过它:一张包含多个小图案的背景图片,加上 3 个需要你按顺序点击的目标图块。
简单来说,它是一种 "文字/图案点选型" 验证码:
| 验证码类型 | 典型代表 | 破解难度 |
|---|---|---|
| 简单数字验证码 | 老式论坛 | ⭐ |
| 滑动拼图 | 早期极验、腾讯滑块 | ⭐⭐ |
| 文字/图案点选 | 腾讯 TCaptcha、极验 v4 | ⭐⭐⭐⭐ |
| reCAPTCHA v3 | Google 行为分析 | ⭐⭐⭐⭐⭐ |
腾讯 TCaptcha 的难点在于:它不像简单滑块只需要计算一个偏移量,而是需要你 从背景图中精准定位 3 个目标图案的坐标并依次点击。这意味着破解程序不仅要"看懂"目标长什么样,还得在一张花花绿绿的大图里"找到"它们。
正因为它的前端渲染机制是基于 JavaScript 动态加载的,纯 HTTP 请求根本拿不到验证码的真实图片数据。所以项目选择了用 Selenium 模拟一个真实浏览器来跑。
很多自动化教程会推荐 2captcha、Anti-Captcha 等第三方人工打码平台。它们的原理很简单:把验证码图片发到平台服务器,由真人或 AI 解答后返回结果。但对于"雨云每日签到"这个场景,这类方案有几个致命问题:
| 对比维度 | 2captcha 等付费平台 | 本方案(ddddocr 本地识别) |
|---|---|---|
| 费用 | 约 $2-3 / 1000次 | $0(完全免费) |
| 速度 | 10~60 秒(等人工) | 1~3 秒(本地推理) |
| 隐私 | 账号信息经过第三方 | 全程本地,零数据外传 |
| 依赖 | 需联网且平台随时关停 | 离线运行,GitHub Actions 内置 |
| GPU 要求 | 无(服务端处理) | 无(CPU 即可,ddddocr 极致轻量) |
换句话说,2captcha 那一套在"白嫖积分"的语境下完全没有性价比。你为了省钱才签到,结果打码费比积分还贵?
本项目的核心思路就是 "零成本、纯本地、全自动",用 AI 模型直接在运行环境里搞定一切。
这套雨云自动签到验证码版方案的技术栈可以用一句话概括:Selenium 负责"操作浏览器",ddddocr 负责"看懂文字",OpenCV 负责"找到位置"。
下面逐层拆解。
为什么要用 Selenium 而不是直接发 HTTP 请求?因为腾讯 TCaptcha 会做大量的前端检测:
navigator.webdriver 等浏览器指纹判断是否为自动化工具项目使用 Chrome 无头模式(headless) 运行 Selenium,专为服务器环境优化:
# 无头模式 + 1080p 窗口(避免元素重叠导致误点)
ops.add_argument("--headless")
ops.add_argument("--window-size=1920,1080")
ops.add_argument("--no-sandbox")
ops.add_argument("--disable-dev-shm-usage") # Docker/Actions 内存优化
为什么窗口设 1920×1080? 主要是为了模拟真实用户的浏览器环境。一个正常用户不可能用 800×600 的窗口浏览网页,设置标准分辨率有助于降低被风控系统识别为自动化工具的风险。
光跑个 headless Chrome 远远不够,Selenium 会被各种方式检测到。项目做了两层防护:
第一层:stealth.min.js 注入
这个文件不是手写的,而是从 puppeteer-extra-plugin-stealth(7.2k+ ⭐)中自动提取生成的。
stealth 插件本来是 Puppeteer 专属的,它在浏览器打开页面时会通过 page.evaluateOnNewDocument() 注入一系列反检测脚本。而 extract-stealth-evasions 这个工具做了一件很巧妙的事:把 evaluateOnNewDocument 替换成一个"窃听器",只记录脚本内容而不执行。
// 核心 trick:猴子补丁(Monkey Patch)
page.__proto__.evaluateOnNewDocument = function(func, args) {
// 不执行,只把脚本源码拼接起来
scripts += '(' + func.toString() + ')(' + JSON.stringify(args) + ');\n'
}
完整的生成流程是这样的:
evaluateOnNewDocument 和 evaluate 方法scripts 变量scripts,加上文件头stealth.min.js生成命令一行搞定:
npx extract-stealth-evasions # 在当前目录生成 stealth.min.js
这个文件包含 16 个 evasion(反检测)模块,覆盖了所有常见的自动化检测点:
| 模块 | 作用 |
|---|---|
navigator.webdriver | 删除 webdriver 属性(最基础的检测点) |
chrome.runtime | 伪装 chrome.runtime(最复杂的模块) |
chrome.app / csi / loadTimes | 补齐正常 Chrome 才有的 API |
navigator.plugins | 伪装浏览器插件列表 |
navigator.languages | 伪装语言设置 |
navigator.permissions | 伪装权限查询结果 |
navigator.hardwareConcurrency | 伪装 CPU 核心数 |
iframe.contentWindow | 修复 iframe 跨域检测 |
media.codecs | 伪装媒体编解码器支持 |
window.outerdimensions | 伪装窗口尺寸 |
user-agent-override | 伪装 UA 和平台信息 |
sourceurl | 隐藏注入脚本的来源 URL |
注入方式也很简单,通过 Chrome DevTools Protocol(CDP)在每个页面加载前自动执行:
# 读取生成好的 stealth.min.js
with open("stealth.min.js", "r") as f:
stealth_js = f.read()
# 注入到浏览器,之后打开的每个页面都会自动执行反检测脚本
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": stealth_js})
这套方案的精髓在于:stealth.min.js 本来是为 Puppeteer(Node.js)设计的,但因为它最终只是一段纯 JS 代码,所以可以通过 CDP 注入到任何浏览器中使用,包括 Selenium 驱动的 Chrome。
第二层:账号专属浏览器指纹
基于账号 ID 生成确定性的 User-Agent 和指纹参数,同一账号每次运行指纹一致(模拟"同一个人"),不同账号指纹各异(避免关联检测):
# 每个账号生成专属 User-Agent
user_agent = get_random_user_agent(account_id)
ops.add_argument(f"--user-agent={user_agent}")
# 注入确定性浏览器指纹
fingerprint_js = generate_fingerprint_script(current_user)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": fingerprint_js})
ddddocr("带带弟弟OCR")是一个国人开源的通用验证码识别库,基于 ONNX Runtime 推理引擎。项目用到了它的两个核心能力:
| 功能 | 作用 | 对应模式 |
|---|---|---|
| OCR 文字识别 | 识别图案中的汉字/数字/字母 | DdddOcr(ocr=True) |
| 目标检测 | 在大图中定位所有可能的候选区域 | DdddOcr(det=True) |
在多账号并发场景下,如果每个线程都加载一份模型,内存会瞬间炸掉。项目用了 双重检查锁定(Double-Checked Locking) 实现全局单例:
_ocr_model = None
_det_model = None
_model_lock = threading.Lock()
_inference_lock = threading.Lock() # 推理锁,防止并发推理冲突
def get_shared_ocr_models():
global _ocr_model, _det_model
if _ocr_model is None or _det_model is None:
with _model_lock:
if _ocr_model is None or _det_model is None:
import ddddocr
_ocr_model = ddddocr.DdddOcr(ocr=True, show_ad=False)
_det_model = ddddocr.DdddOcr(det=True, show_ad=False)
return _ocr_model, _det_model
即使 10 个账号同时跑,也只加载一份模型,内存占用控制在可接受范围内。
光靠 ddddocr "认字"还不够。验证码里的目标可能是汉字,也可能是不规则图形、小图标甚至数字。项目设计了一套 两阶段、多算法融合 的定位策略。
det 模式扫描大图,框出所有可能包含目标的候选区域(bounding box)评分公式示意(简化版):
if OCR识别(目标) == OCR识别(候选) 且 形状分 ≥ 阈值:
得分 = 75 + 形状分 × 25 # 语义命中,强信号
elif 形状分 ≥ 0.55:
得分 = 形状分 × 20 # 形状高度匹配
else:
得分 = SIFT内点数 # 几何特征兜底
如果阶段一的总置信分低于阈值(比如候选框截得不准,或者背景太花导致目标检测遗漏),系统会自动降级到 全图扫描模式:
cv2.connectedComponentsWithStats 提取所有暗色连通域,按面积过滤出合理大小的候选cv2.matchTemplate 做归一化互相关匹配最终,从全图搜索的候选中选出总分最高、且彼此距离足够远的 3 个点作为点击坐标。
这个两阶段设计的核心思想是:能精确就精确(快),精确不了就暴力搜索(稳)。
找到目标在原始图片中的像素坐标后,还需要转换为浏览器中的实际点击位置。因为验证码图片在 DOM 中的渲染尺寸和原始图片尺寸可能不同:
# 原始图片坐标 → DOM 渲染坐标
width_raw, height_raw = captcha.shape[1], captcha.shape[0] # 原图尺寸
width, height = float(get_width_from_style(style)), ... # DOM渲染尺寸
final_x = int(-width/2 + x / width_raw * width) # 相对于元素中心的偏移
final_y = int(-height/2 + y / height_raw * height)
# 使用 ActionChains 移动到精确位置并点击
ActionChains(driver).move_to_element_with_offset(slideBg, final_x, final_y).click().perform()
雨云签到验证码的识别率不可能 100%。原作者给出的经不严谨测试数据是约 48.3% 单次通过率。但这完全不是问题,因为项目内置了 多级自动重试:
每次验证码提交后,脚本会检查结果元素的 class 属性:
show-success → 通过,继续签到流程这个过程是递归式的,只要浏览器还活着,就会不断重试。
如果整个签到流程失败(网络超时、页面结构变化等),外层还有账号级别的重试机制:
CHECKIN_MAX_RETRIES 配置)算个账:单次通过率 48.3%,3 次验证码级重试的通过率 = 1 - (1-0.483)³ ≈ 86.2%,再叠加 3 次账号级重试,最终成功率趋近 99%+。
如果你已经搭建好了基础签到教程,以下几个进阶配置可以进一步提升稳定性:
PROXY_API_URL)如果你有多个账号,它们从同一个 GitHub Actions Runner 出发,IP 是一样的。大量签到请求从同一 IP 发出,可能触发雨云的风控。
配置 PROXY_API_URL 后,每个账号签到前会单独请求一次代理接口获取新 IP,实现 "一号一IP"。即使代理获取失败,也会自动降级用本地 IP 继续,不会因为代理问题导致签到失败。
项目利用 GitHub Actions Cache 缓存登录后的 Cookie。好处是:
Cookie 以 JSON 格式保存在 temp/cookies/ 目录,文件名基于账号哈希生成,不泄露原始账号信息。
很多人跑 headless 浏览器时会忽略窗口大小设置,导致默认窗口很小(通常 800×600)。这会引起严重的验证码识别问题:
项目强制设置 --window-size=1920,1080,确保在无头模式下也有标准的 1080p 渲染空间。
通过 SCREENSHOT_MODE 环境变量控制:
all:每次都截图,流量消耗大但方便排查failed_only(默认推荐):仅失败时截图,平时不浪费资源none:完全不截图,极致轻量此外,验证码识别失败时,脚本会自动保存一个"调试包"到 logs/captcha_debug/ 目录,里面包含原始验证码图片、目标图块、元数据 JSON 等,非常方便开发者排查问题。
是的。GitHub Actions 对公开仓库提供 无限免费额度(私有仓库才有每月 2000 分钟的限制),单次签到耗时约 3~5 分钟,完全不需要担心额度问题。ddddocr 模型推理也完全在 Runner 的 CPU 上完成,不需要任何外部 API 调用。
不能。ddddocr 擅长中文汉字、英文字母、数字的单字识别。对于复杂的不规则图形(如"点击所有帽子"),项目靠的是 OpenCV 的 SIFT 特征匹配和 Canny 边缘匹配来弥补。这也是为什么项目要设计多算法融合的原因,没有银弹,但组合拳可以打得很稳。
腾讯 TCaptcha 的底层框架相对稳定(验证码图片都在 #slideBg 元素中),只要页面结构不发生大改,脚本就能继续工作。如果遇到兼容性问题,我们会第一时间更新适配,欢迎到 GitHub 仓库 提 Issue 反馈。
在雨云签到这个场景下,完全没必要。本方案的 ddddocr 本地识别已经是雨云2captcha签到的完美替代,零成本、低延迟、无隐私风险。除非你需要破解 reCAPTCHA v3 这类纯行为分析型验证码,才需要考虑付费平台。
| 技术组件 | 角色 | 关键特性 |
|---|---|---|
| Selenium | 浏览器自动化 | 无头模式、stealth.js 反检测、账号专属指纹 |
| ddddocr | 文字/目标识别 | CPU 推理、双模型单例、线程安全推理锁 |
| OpenCV | 图像匹配定位 | SIFT+RANSAC、Canny边缘模板、连通域分析、二值形状IoU |
| 重试机制 | 容错保障 | 验证码级递归重试 + 账号级定时重试 |
| Cookie 缓存 | 减少风控 | Actions Cache 持久化、哈希命名、自动失效检测 |
这套雨云自动签到验证码版方案的精髓在于:不追求单次 100% 的识别率,而是通过多算法融合 + 多级重试,把最终成功率推到 99% 以上。
如果你还没搭建过基础的自动签到,请先参考:《2026年最新 教你0元搭建雨云自动签到,每日自动领积分续费(保姆级教程)》,3 步即可完成部署。
仓库地址:https://github.com/LeapYa/Rainyun-Qiandao
觉得有用的话,别忘了给仓库点个 Star ⭐!
🚨 法律风险提示:本文涉及的自动化签到及验证码识别技术可能违反雨云平台《用户协议》及相关服务条款,存在账号封禁、积分清零等风险。此类技术方案属于灰色地带,仅供学习 Selenium 自动化、OCR 识别及计算机视觉技术原理,请勿用于生产环境或大规模商业用途。使用即视为您已充分评估风险并自愿承担后果。