点了提交按钮,页面卡住几秒,没有验证码图片,也没有勾选框——这通常是隐形 reCAPTCHA(reCAPTCHA Invisible)在后台验证。
调用方式和标准 v2 几乎一样,只多一个参数:invisible=1。漏传的话 CaptchaAI 按标准 v2 处理,token 大概率被拒绝。
真正容易踩坑的不是提交任务,而是怎么把 token 塞回页面:多数隐形实现靠 JavaScript 回调函数,不是隐藏字段 g-recaptcha-response,你得先找到并触发它。
分不清页面用的是标准 v2 还是隐形版? 看 reCAPTCHA v2 与 Invisible 的区别,几秒判断清楚。
第一步:先分清是隐形 reCAPTCHA 还是标准 v2
在源码里找这三种写法:
<!-- Option 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..." data-size="invisible" data-callback="onSubmit"></div>
<!-- Option 2: button with data-sitekey (invisible by default) -->
<button data-sitekey="6LdKlZEU..." data-callback="onSubmit">Submit</button>
<!-- Option 3: programmatic execution -->
<script>
grecaptcha.execute('6LdKlZEU...', {action: 'submit'});
</script>
看到 data-size="invisible"、按钮带 data-sitekey,或没有容器却调用 grecaptcha.execute(),基本可确定是隐形 reCAPTCHA。
验证码类型也值得确认——国内和出海产品常用的不同:
| 场景 | 常见验证码 |
|---|---|
| 国内电商、政务、金融站点 | GeeTest(极验)、网易易盾、腾讯防水墙等 |
| 出海产品、国际 SaaS | reCAPTCHA、Cloudflare Turnstile |
CaptchaAI 支持 reCAPTCHA、Turnstile、GeeTest v3,不支持网易易盾、腾讯防水墙。
准备好这四样,再往下走
准备好这四样:
- API Key——captchaai.com/api.php
- sitekey——取自
data-sitekey - 页面 URL——验证码实际运行页面
- 浏览器工具——Selenium/Puppeteer 执行回调
第二步:把参数提交给 CaptchaAI,别忘了 invisible=1
提交逻辑和标准 v2 一样,只多传 invisible: 1:
import requests
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": "6LdKlZEUAAAAAPoxm...",
"pageurl": "https://example.com/signup",
"invisible": 1,
"json": 1
})
task_id = response.json()["request"]
const params = new URLSearchParams({
key: "YOUR_API_KEY", method: "userrecaptcha",
googlekey: "6LdKlZEUAAAAAPoxm...",
pageurl: "https://example.com/signup",
invisible: 1, json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const { request: taskId } = await res.json();
提交前核对两个字段,token 被拒常出在这里:
googlekey:来自data-sitekey,别用占位符pageurl:必须是验证码实际渲染的页面,域名不匹配是最常见的失败原因
第三步:轮询拿到 token
任务提交后不会立刻出结果,每 5 秒轮询 res.php,完成前返回 CAPCHA_NOT_READY:
import time
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
break
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Error: {result['request']}")
第四步(关键):通过回调函数把 token 注入页面
这一步最容易出错:隐形 reCAPTCHA 要的是一次回调函数调用,不是把 token 塞进隐藏字段:
# Selenium example
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com/signup")
# Find the callback name
callback = driver.execute_script("""
var el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
var btn = document.querySelector('[data-sitekey]');
if (btn) return btn.getAttribute('data-callback');
return null;
""")
# Execute the callback with the token
if callback:
driver.execute_script(f"window['{callback}']('{token}');")
else:
# Fallback: fill hidden field and submit
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.querySelector('form').submit();
""")
// Puppeteer example
await page.evaluate((token) => {
const el = document.querySelector('[data-callback]') || document.querySelector('[data-sitekey]');
const callbackName = el?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
window[callbackName](token);
} else {
document.getElementById('g-recaptcha-response').innerHTML = token;
document.querySelector('form').submit();
}
}, token);
回调触发后页面没反应,按顺序排查:
- 回调函数名是否拼写正确
- 表单是否还有必填字段没有提前填好
完整可用的函数
把上面三步封装成函数,方便直接复用:
import requests
import time
def solve_invisible_recaptcha(api_key, sitekey, page_url):
submit = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key, "method": "userrecaptcha", "googlekey": sitekey,
"pageurl": page_url, "invisible": 1, "json": 1
}).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit error: {submit.get('request')}")
task_id = submit["request"]
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {result.get('request')}")
raise TimeoutError("Timed out")
token = solve_invisible_recaptcha("YOUR_API_KEY", "6LdKlZEU...", "https://example.com/signup")
拿到 token 后,按需选择回调注入或隐藏字段兜底提交。
完整可运行示例
想要包含环境配置、轮询、重试与错误处理的完整项目?
常见问题
如何快速判断页面是隐形 reCAPTCHA 还是标准 v2?
满足以下任意一条即可:
- 小部件带
data-size="invisible" - 按钮直接挂
data-sitekey - 页面没有可见勾选框
忘记在请求里加 invisible=1 会怎样?
CaptchaAI 会当标准 v2 处理,token 很可能被拒绝——隐形实现必须传这个参数。
轮询一直返回 CAPCHA_NOT_READY,是哪里出了问题?
先查 pageurl、googlekey 是否与页面一致——最常见的失败原因。
国内网络环境下测试会受影响吗?
reCAPTCHA 依赖 Google 托管脚本,国内访问可能较慢,但不影响 CaptchaAI 侧的提交、轮询流程。
现在就开始识别隐形 reCAPTCHA
获取 API Key:captchaai.com/api.php,加上 invisible=1,套用上面的回调模式即可。
相关指南
- reCAPTCHA Invisible 的工作原理
- 隐形 reCAPTCHA 常见报错排查
- reCAPTCHA v2 与 Invisible 的区别
- reCAPTCHA v2 回调模式 API 教程