自动化脚本卡在 reCAPTCHA v2 挑战前,最快的处理方式是调用 API:提取 sitekey 和 pageurl,提交给 CaptchaAI 的 reCAPTCHA v2 求解器,轮询拿到 token 后写回页面——全程不需要人工介入。
典型场景:
- 跨境电商自动化:海外站点比国内站点更常见 reCAPTCHA v2,国内多用 GeeTest(极验)。
- SaaS 出海测试:登录/注册回归脚本卡在验证码,CI 跑不完整条链路。
- 数据采集流水线:抓取任务被表单前的验证码拦截,需要脚本自动过关。
不确定页面用的是哪个版本的 reCAPTCHA? 先看 如何识别 reCAPTCHA 版本 再继续。
准备工作清单
| 必备项 | 说明 |
|---|---|
| CaptchaAI API Key | 在 captchaai.com/api.php 申请,32 位字符串 |
| 目标页面 URL | 加载控件的完整地址,带协议头 |
| reCAPTCHA v2 sitekey | 该控件实例对应的公开站点密钥 |
| 运行环境 | Python 3.7+(requests)或 Node.js 18+(内置 fetch) |
| token 提交方式 | Selenium/Puppeteer/Playwright 或 HTTP 请求代码路径 |
小提示: reCAPTCHA 依赖 Google 托管脚本,国内网络直接请求有时不稳定——这是网络可达性问题,不是 API 故障,测试环境建议放在海外服务器或 CI 节点。
提取 sitekey 和 pageurl 这两个必传参数
sitekey 与 pageurl 是仅有的两个必传输入,任意一个填错都是提交失败最常见的原因。
找到 sitekey 的三种方式
sitekey 是 Google 给该页面 reCAPTCHA 控件分配的公开密钥,通常出现在三处:
方式一 —— 控件容器上的 data-sitekey 属性:
<div class="g-recaptcha" data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"></div>
方式二 —— reCAPTCHA iframe 加载的 anchor URL:
https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-&...
URL 中 k 参数的值就是 sitekey。
方式三 —— 页面 JavaScript 里的 grecaptcha.render() 调用:
grecaptcha.render('captcha-container', {
sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
callback: onSuccess
});
pageurl 要填哪个地址
pageurl 必须是包含协议头的完整地址,例如:
https://staging.example.com/qa-login
- 普通情况:控件和页面同域,直接用当前页面地址。
- iframe 情况(最容易踩的坑):控件加载在另一个子域名的 iframe 里时,
pageurl要填 iframe 本身的 URL,不是父页面地址。
关键提示:
sitekey与pageurl配对错误时,CaptchaAI 会返回ERROR_BAD_TOKEN_OR_PAGEURL。排查任何其他问题之前,先确认这两个值。
四步搞定:提交 → 等待 → 轮询 → 注入
页面 → 提取 sitekey + pageurl
↓
POST in.php(method=userrecaptcha)
↓
拿到 captcha id
↓
等待 15–20 秒
↓
GET res.php(action=get, id=…)
↓ ↓
CAPCHA_NOT_READY status=1 → token
(等 5 秒重试) ↓
注入到 g-recaptcha-response
↓
触发表单提交 / callback
- 提交 ——
POST到https://ocr.captchaai.com/in.php,带method=userrecaptcha、key、googlekey(sitekey)、pageurl,返回 captcha id。 - 等待 —— 暂停 15–20 秒。reCAPTCHA v2 通常 60 秒内完成,成功率超过 99.5%。
- 轮询 ——
GEThttps://ocr.captchaai.com/res.php,参数action=get、id=<captcha id>。CAPCHA_NOT_READY是正常状态,等 5 秒再试。 - 接收 —— 求解成功后返回较长的 reCAPTCHA 响应 token。
- 注入 —— 把 token 写入
g-recaptcha-response文本域,或调用页面 callback。 - 提交 —— 触发目标页面期望的后续动作。
Python 代码:完整实现
import time
import requests
API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://staging.example.com/qa-login"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def solve_recaptcha_v2(api_key, sitekey, pageurl):
"""Submit a reCAPTCHA v2 challenge and return the solved token."""
submit_resp = requests.post(
SUBMIT_URL,
data={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
},
timeout=30,
)
submit_resp.raise_for_status()
submit_data = submit_resp.json()
if submit_data.get("status") != 1:
raise RuntimeError(f"Submit failed: {submit_data}")
captcha_id = submit_data["request"]
print(f"Task created - captcha id: {captcha_id}")
time.sleep(15)
for _ in range(60): # 最多约 5 分钟轮询
result_resp = requests.get(
RESULT_URL,
params={
"key": api_key,
"action": "get",
"id": captcha_id,
"json": 1,
},
timeout=30,
)
result_resp.raise_for_status()
result_data = result_resp.json()
if result_data.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result_data.get("status") == 1:
return result_data["request"]
raise RuntimeError(f"Polling error: {result_data}")
raise TimeoutError("reCAPTCHA v2 solve timed out")
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")
这段代码做了什么:
- 用
method=userrecaptcha提交 sitekey、pageurl 到in.php。 - 等 15 秒再轮询,之后每 5 秒查一次
res.php。 - 求解完成返回 token 字符串,可直接注入。
- 60 次轮询上限,避免死循环。
Node.js 代码:完整实现
const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://staging.example.com/qa-login";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
const submitResp = await fetch(SUBMIT_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
json: "1",
}),
});
const submitData = await submitResp.json();
if (submitData.status !== 1) {
throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
}
const captchaId = submitData.request;
await sleep(15_000);
for (let i = 0; i < 60; i++) {
const resp = await fetch(
`${RESULT_URL}?${new URLSearchParams({
key: apiKey,
action: "get",
id: captchaId,
json: "1",
})}`,
);
const data = await resp.json();
if (data.request === "CAPCHA_NOT_READY") {
await sleep(5_000);
continue;
}
if (data.status === 1) return data.request;
throw new Error(`Polling error: ${JSON.stringify(data)}`);
}
throw new Error("reCAPTCHA v2 solve timed out");
}
const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
console.log("Token:", token.slice(0, 80) + "...");
拿到 token 之后怎么提交
拿到 token 只是一半,还要让页面确认 reCAPTCHA 已通过,常见做法有三种:
方式一 —— 直接写入 textarea:
document.getElementById("g-recaptcha-response").innerHTML = token;
方式二 —— 调用 reCAPTCHA 回调函数:
// 如果页面在 grecaptcha.render() 时设置了 callback
window.onCaptchaSolved(token);
方式三 —— 把 token 作为表单字段提交:
session.post(
"https://staging.example.com/qa-login",
data={
"username": "...",
"password": "...",
"g-recaptcha-response": token,
},
)
有 data-callback 用方式二,纯表单提交用方式一或方式三。
报错排查:5 个常见错误码
| 错误 | 含义 | 解决办法 |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
API Key 无效或拼写错误 | 去 captchaai.com/api.php 核对 Key |
ERROR_ZERO_BALANCE |
账户余额不足 | 在控制台充值或升级套餐 |
ERROR_BAD_TOKEN_OR_PAGEURL |
sitekey 或 pageurl 错误 | 重新核对两者,留意 iframe 场景 |
CAPCHA_NOT_READY |
求解还在进行中 | 不是错误,等 5 秒再轮询 |
ERROR_NO_SLOT_AVAILABLE |
当前线程已经用完 | 等队列释放,或升级到线程数更高的套餐 |
更多错误见 reCAPTCHA v2 常见求解错误。
轮询节奏和并发怎么配置
| 配置项 | 建议值 | 原因 |
|---|---|---|
| 首次轮询等待 | 15 秒 | 太早查询只会拿到 CAPCHA_NOT_READY |
| 轮询间隔 | 5 秒 | 间隔更短不会更快出结果 |
| 并发上限 | 按套餐线程数:BASIC 5、STANDARD 15、ADVANCE 50 | 超出线程数的任务排队等待 |
| 超时熔断 | 120 秒 | 避免任务卡住占线程 |
常见问题
CaptchaAI 支持 reCAPTCHA v3 或 Enterprise 版本吗?
支持,同样用 method=userrecaptcha,多传 version=v3+action(v3)或 enterprise=1(Enterprise),提交 → 轮询 → 注入流程不变。
为什么一直收到 ERROR_BAD_TOKEN_OR_PAGEURL?
最常见原因是 pageurl 填成了父页面地址,而控件实际在子域名 iframe 里——换成 iframe 自身的 URL 通常就能解决。
token 能存起来重复用吗?
不能。有效期约 2 分钟,多数站点一次性校验,拿到后要立刻注入并提交。
最低多少钱能测试完整流程?
BASIC 套餐每月 $15、5 线程,足够跑通本文测试;线程数决定并发量,接入量上来了再升级 STANDARD。
接下来
| 场景 | 参考文章 |
|---|---|
| 不确定版本 | 如何识别 reCAPTCHA 版本 |
| 排查报错 | reCAPTCHA v2 常见求解错误 |
| 换类型接入 | 使用 API 解决 Cloudflare Turnstile、使用 API 解决 GeeTest v3 |
现在就去 captchaai.com/api.php 申请 API Key,跑一遍上面的代码,几分钟拿到第一个 token。