reCAPTCHA v2 仍然是登录、注册、下单与表单提交流程中最常见的验证码之一。如果你的自动化任务遇到了 reCAPTCHA v2 的复选框或图块挑战,可以通过 API 用四步搞定:从页面提取 sitekey 与 pageurl、把它们提交到 CaptchaAI 的 reCAPTCHA v2 求解器、轮询结果、把返回的token 提交到目标流程中。
本指南给出可以直接运行的 Python 与 Node.js 代码,面向真正需要把集成跑起来的开发者,而不是做理论概览。
不确定页面用的是 reCAPTCHA 哪个版本? 先看 如何识别 reCAPTCHA 版本。
开始之前你需要准备
| 必备项 | 说明 |
|---|---|
| CaptchaAI API Key | 在 captchaai.com/api.php 获取,是一段 32 位字符串 |
| 目标页面 URL | 加载 reCAPTCHA v2 控件的完整 URL,含协议头 |
| reCAPTCHA v2 sitekey | 与该页面控件实例绑定的公开站点密钥 |
| 运行时环境 | Python 3.7+(依赖 requests)或 Node.js 18+(自带 fetch) |
| 令牌提交方式 | 浏览器自动化工具(Selenium/Puppeteer/Playwright)或可发起 HTTP 请求的代码路径 |
如何提取 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
如果 reCAPTCHA 控件加载在另一个子域名的 iframe 里,pageurl 应该是该 iframe 的 URL,而不是父页面的 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
- 提交 —— 向
https://ocr.captchaai.com/in.php发起POST,参数包含method=userrecaptcha、key(你的 API Key)、googlekey(sitekey)、pageurl。返回一个 captcha id。 - 等待 —— 暂停 15–20 秒。reCAPTCHA v2 的求解一般在 60 秒内完成,成功率超过 99.5%。
- 轮询 —— 向
https://ocr.captchaai.com/res.php发起GET,参数action=get、id=<captcha id>。如果返回CAPCHA_NOT_READY,等 5 秒再试。 - 接收 —— 求解成功时,API 返回一段较长的 reCAPTCHA 响应令牌。
- 注入 —— 把令牌写入页面上的
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。 - 求解完成后返回令牌字符串,可直接用于注入。
- 设置 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 提交到页面
拿到令牌后,必须告诉页面 reCAPTCHA 已经通过。三种常见做法:
方式一 —— 直接写入 textarea:
document.getElementById("g-recaptcha-response").innerHTML = token;
方式二 —— 调用 reCAPTCHA 回调函数:
// 如果页面在 grecaptcha.render() 时设置了 callback
window.onCaptchaSolved(token);
方式三 —— 把令牌作为表单字段提交:
session.post(
"https://staging.example.com/qa-login",
data={
"username": "...",
"password": "...",
"g-recaptcha-response": token,
},
)
常见错误与排查
| 错误 | 含义 | 解决办法 |
|---|---|---|
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 秒,可减少无效请求。
- 5 秒一次轮询,再频繁也不会更快拿到结果。
- 并发取决于你的套餐线程数:BASIC 5 路、STANDARD 15 路、ADVANCE 50 路。
- 超时熔断:建议给整个求解流程加 120 秒上限,避免线程长时间占用。
接下来
立即在 captchaai.com/api.php 获取 API Key,按上面的代码片段就能跑通你的第一个 reCAPTCHA v2 求解。