API 教程

如何使用 API 解决 reCAPTCHA v2 回调

一些网站使用 回调函数 来实现 reCAPTCHA v2,而不是标准的 g-recaptcha-response 隐藏字段。当您解决验证码并将token 提交隐藏字段时,什么也没有发生 - 页面会忽略它。这是因为该网站希望您使用令牌调用 JavaScript 函数

本指南向您展示如何检测基于回调的 reCAPTCHA v2,通过 CaptchaAI API 解决它,并正确调用回调。 API 调用与标准 reCAPTCHA v2 相同 — 只是token 提交步骤发生了变化。

reCAPTCHA v2 新手? 从如何使用API​​解决reCAPTCHA v2对于标准流程,然后返回此处了解回调变体。


开始之前您需要什么

要求 细节
CaptchaAI API 密钥 从以下位置获取一份captchaai.com/api.php。 32 个字符的字符串。
目标页面网址 reCAPTCHA v2 小部件加载的完整 URL。
reCAPTCHA v2 站点密钥 与小部件实例关联的公钥。
浏览器自动化工具 Selenium、Puppeteer 或 Playwright — 您需要执行 JavaScript 来调用回调。
回调函数名称 站点期望接收令牌的 JavaScript 函数。

如何识别回调实现

标准 reCAPTCHA v2 将解决的标记写入隐藏的 g-recaptcha-response 文本区域。回调实现会跳过这一点并直接调用 JavaScript 函数。以下是如何辨别差异的方法。

方法一:检查data-callback属性

检查页面源中的 reCAPTCHA 小部件 div:

<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
     data-callback="SubmitToken">
</div>

如果 data-callback 存在,站点将使用回调。值(SubmitToken)是您需要的函数名称。

方法2:检查grecaptcha.render()调用

在页面的 JavaScript 中搜索 grecaptcha.render

grecaptcha.render('recaptcha-container', {
  sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
  callback: userVerified
});

callback 属性命名该函数。在这种情况下,userVerified

方法 3:检查内部 reCAPTCHA 配置

在目标页面打开浏览器控制台并运行:

___grecaptcha_cfg.clients[0]

导航对象树以查找 callback 属性。确切的路径因站点而异——可能是 clients[0].aa.l.callback 或其他路径,具体取决于 reCAPTCHA 版本和缩小程度。如果页面有多个reCAPTCHA实例,请检查clients[1]clients[2]等。

快速检测脚本

在浏览器控制台中运行此命令以自动查找回调名称:

// Check data-callback attributes
document.querySelectorAll('[data-callback]').forEach(el => {
  console.log('data-callback:', el.getAttribute('data-callback'));
});

// Check internal config
if (typeof ___grecaptcha_cfg !== 'undefined') {
  Object.keys(___grecaptcha_cfg.clients).forEach(key => {
    const client = ___grecaptcha_cfg.clients[key];
    console.log(`Client ${key}:`, JSON.stringify(client, null, 2));
  });
}

回调解决与标准 v2 有何不同

对 CaptchaAI 的 API 调用相同。唯一的区别在于您收到令牌后如何处理它。

标准v2 回调 v2
1.提交至CaptchaAI method=userrecaptcha + 站点密钥 + 页面网址 相同的
2. 投票结果 action=get + 验证码 相同的
3. 接收代币 相同的令牌格式 相同的
4. 注入代币 设置 g-recaptcha-response 字段值 使用token调用回调函数
5. 提交表格 触发表单提交 通常是自动的——回调处理它

关键: 不要在基于回调的实现上设置 g-recaptcha-response。该页面忽略该字段并等待回调函数触发。设置字段而不调用回调会使验证码看起来从未被解析。


求解流程

Page → extract sitekey + pageurl + callback name
                    ↓
      POST to in.php (method=userrecaptcha)
                    ↓
           receive captcha ID
                    ↓
         wait 15–20 seconds
                    ↓
      GET res.php (action=get, id=…)
          ↓                    ↓
   CAPCHA_NOT_READY       status=1 → token
    (wait 5s, retry)            ↓
                     invoke callback(token)
                              ↓
               site processes token automatically

Python 实现(Selenium)

import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By

API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://staging.example.com/qa-login"
CALLBACK_NAME = "SubmitToken"  # The callback function name from the page

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 task and return the solved token."""

    # Step 1: Submit the captcha
    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}")

    # Step 2: Wait before first poll
    time.sleep(15)

    # Step 3: Poll for result
    for _ in range(60):
        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")


def detect_callback_name(driver):
    """Detect the reCAPTCHA callback function name from the page."""

    # Try data-callback attribute first
    callback = driver.execute_script("""
        const el = document.querySelector('[data-callback]');
        if (el) return el.getAttribute('data-callback');
        return null;
    """)
    if callback:
        return callback

    # Try internal reCAPTCHA config
    callback = driver.execute_script("""
        if (typeof ___grecaptcha_cfg === 'undefined') return null;
        const clients = ___grecaptcha_cfg.clients;
        for (const key of Object.keys(clients)) {
            const client = clients[key];
            // Walk the object tree to find a callback function
            const json = JSON.stringify(client);
            const match = json.match(/"callback":"(\\w+)"/);
            if (match) return match[1];
        }
        return null;
    """)
    return callback


# Main workflow
driver = webdriver.Chrome()
driver.get(PAGE_URL)

# Detect the callback name (or use the known name)
detected = detect_callback_name(driver)
callback_name = detected or CALLBACK_NAME
print(f"Using callback: {callback_name}")

# Solve the CAPTCHA
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")

# Invoke the callback with the token
driver.execute_script(f"{callback_name}(arguments[0]);", token)
print("Callback invoked — site should process the token automatically")

# Wait for the page to process
time.sleep(3)
driver.quit()

这有什么作用:

  1. 使用 method=userrecaptcha 将 sitekey 和 pageurl 提交到 in.php — 与标准 v2 相同。
  2. 每 5 秒轮询一次 res.php,直到令牌准备就绪。
  3. 从页面 DOM 检测回调函数名称。
  4. 使用 execute_script 使用已解析的令牌调用回调函数。
  5. 网站自己的 JavaScript 处理其余的事情——表单提交、验证或页面重定向。

Node.js 实现(Puppeteer)

const puppeteer = require("puppeteer");

const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://staging.example.com/qa-login";
const CALLBACK_NAME = "SubmitToken";

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
  // Step 1: Submit the captcha
  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;
  console.log(`Task created — captcha ID: ${captchaId}`);

  // Step 2: Wait before first poll
  await sleep(15_000);

  // Step 3: Poll for result
  for (let i = 0; i < 60; i++) {
    const resultResp = await fetch(
      `${RESULT_URL}?${new URLSearchParams({
        key: apiKey,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );

    const resultData = await resultResp.json();

    if (resultData.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (resultData.status === 1) {
      return resultData.request;
    }

    throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
  }

  throw new Error("reCAPTCHA v2 solve timed out");
}

async function detectCallbackName(page) {
  return page.evaluate(() => {
    // Try data-callback attribute
    const el = document.querySelector("[data-callback]");
    if (el) return el.getAttribute("data-callback");

    // Try internal config
    if (typeof ___grecaptcha_cfg !== "undefined") {
      const clients = ___grecaptcha_cfg.clients;
      for (const key of Object.keys(clients)) {
        const json = JSON.stringify(clients[key]);
        const match = json.match(/"callback":"(\w+)"/);
        if (match) return match[1];
      }
    }

    return null;
  });
}

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto(PAGE_URL, { waitUntil: "networkidle2" });

  // Detect callback
  const detected = await detectCallbackName(page);
  const callbackName = detected || CALLBACK_NAME;
  console.log(`Using callback: ${callbackName}`);

  // Solve the CAPTCHA
  const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
  console.log(`Solved token: ${token.slice(0, 80)}...`);

  // Invoke the callback
  await page.evaluate(
    (name, tkn) => {
      window[name](tkn);
    },
    callbackName,
    token
  );
  console.log("Callback invoked — site should process the token automatically");

  await sleep(3_000);
  await browser.close();
})();

PHP实现

API调用与PHP中相同。回调调用需要浏览器上下文,因此本示例涵盖服务器端解决方案。使用无头浏览器工具(例如 PHP WebDriver)进行注入步骤。

<?php
$apiKey  = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://staging.example.com/qa-login";

// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
    "key"       => $apiKey,
    "method"    => "userrecaptcha",
    "googlekey" => $sitekey,
    "pageurl"   => $pageurl,
    "json"      => 1,
]));

$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
    die("Submit failed: " . $submit);
}

$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";

// Step 2: Wait and poll
sleep(15);

for ($i = 0; $i < 60; $i++) {
    $result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
        "key"    => $apiKey,
        "action" => "get",
        "id"     => $captchaId,
        "json"   => 1,
    ]));

    $resultData = json_decode($result, true);

    if ($resultData["request"] === "CAPCHA_NOT_READY") {
        sleep(5);
        continue;
    }

    if ($resultData["status"] === 1) {
        $token = $resultData["request"];
        echo "Solved token: " . substr($token, 0, 80) . "...\n";
        // Pass $token to your browser automation to invoke the callback
        break;
    }

    die("Polling error: " . $result);
}

在 PHP 中获取令牌后,使用浏览器自动化工具(例如 php-webdriver)执行:

SubmitToken("TOKEN_FROM_CAPTCHAAI");

常见错误

# 错误 会发生什么 处理方式
1 设置g-recaptcha-response而不是调用回调 页面忽略令牌 - 表单永远不会提交 找到回调名称并使用令牌调用它
2 回调函数名错误 JavaScript 错误:函数未定义 重新检查 data-callbackgrecaptcha.render() 或内部配置
3 回调在不同的客户端索引上 针对多小部件页面的错误 reCAPTCHA 实例 检查 ___grecaptcha_cfg.clients[1]clients[2] 等。
4 在页面准备好之前调用回调 页面上下文中尚未定义函数 调用前等待 DOMContentLoadednetworkidle
5 使用模糊的 /minified 名称 源中的回调名称已损坏 使用运行时浏览器控制台查找实际的函数引用
6 将回调 v2 与不可见 v2 混合 一些不可见的实现也使用回调 检查 data-size="invisible" 是否存在 - 如果存在,请参见如何使用API​​解决reCAPTCHA Invisible

故障排除

令牌已解决但页面没有反应

最常见的原因:您设置了 g-recaptcha-response 而不是调用回调。检查小部件的 grecaptcha.render() 中是否有 data-callbackcallback。如果是这样,您必须调用该函数。

ReferenceError: SubmitToken is not defined

回调函数尚未加载或名称错误。尝试:

  1. 通过检查 data-callback 或内部配置来确认名称。
  2. 在调用之前等待页面完全加载。
  3. 在缩小的站点上,该函数可能会分配给一个变量 - 在控制台中检查 window.SubmitToken

令牌适用于标准 v2,但在此页面上失败

您可能面临回调实现。遵循上方的检测步骤确认后,切换到回调调用。

ERROR_BAD_TOKEN_OR_PAGEURL

sitekey/pageurl 对无效。这是一个 API 错误,与回调与标准无关。从页面中重新提取这两个值。

页面有多个 reCAPTCHA 小部件

每个小部件可能有自己的回调。检查每个 g-recaptcha div 或检查 ___grecaptcha_cfg.clients 是否有所有已注册的实例。将小部件与您要定位的表单相匹配。

ERROR_CAPTCHA_UNSOLVABLE

该挑战无法解决。使用新请求重试。这不是特定于回调的。

有关完整的错误参考,请参阅常见reCAPTCHA v2解决错误。


为什么 CaptchaAI 适用于此

因素 细节
相同的 API 调用 Submit/poll 流程与标准 reCAPTCHA v2 相同 - 不需要额外的参数
成功率 reCAPTCHA v2 为 99.5%+(回调和标准使用相同的求解器)
求解速度 60秒以下
令牌兼容性 返回的令牌适用于 g-recaptcha-response 注入和回调调用
定价 基于线程的计划起价为 15/month,可无限解决问题

无论站点如何实现 reCAPTCHA v2,返回的令牌 CaptchaAI 都是相同的。区别完全在于客户端代码 - 如何将令牌传递到页面。


完整的可运行示例

需要一个包含环境设置、轮询、重试和错误处理的完整工作项目吗?

请参阅 GitHub 上的完整可运行示例 →


常问问题

什么是 reCAPTCHA v2 回调?

回调是网站注册以接收解析的 reCAPTCHA 令牌的 JavaScript 函数。 reCAPTCHA 不将令牌写入隐藏的 g-recaptcha-response 字段,而是直接调用该函数。该函数通常会触发表单提交、验证或页面重定向。

API 调用的回调与标准 reCAPTCHA v2 有何不同?

这完全没有什么不同。您使用相同的 sitekey 和 pageurl 发送相同的 method=userrecaptcha 请求。唯一的区别是您在收到令牌后如何处理它 - 您调用回调函数而不是设置字段值。

如何找到回调函数名称?

要检查的三个位置:(1) reCAPTCHA div 上的 data-callback 属性,(2) 页面 JavaScript 中 grecaptcha.render() 调用中的 callback 属性,(3) 浏览器控制台中的 ___grecaptcha_cfg.clients[0] 对象 — 导航树以查找 callback 属性。

我可以在这两种方法中使用令牌吗?

令牌本身可以以任何方式工作。但如果站点期望回调,则设置 g-recaptcha-response 将被忽略。始终将注入方法与站点期望的方法相匹配。

我需要浏览器来调用回调吗?

是的。回调是页面上下文中的 JavaScript 函数。您需要 Selenium、Puppeteer、Playwright 或可以在目标页面上运行 JavaScript 的类似工具。


开始解决reCAPTCHA v2回调

  1. 获取您的 API 密钥captchaai.com/api.php
  2. 检测回调名称 — 检查 data-callbackgrecaptcha.render() 或内部配置
  3. 复制上面的 Python 或 Node.js 代码 — 将占位符替换为您的密钥、sitekey、pageurl 和回调名称
  4. 运行它 — 令牌在 60 秒内到达,回调触发,页面处理结果
  5. 卡住了?从以下开始常见reCAPTCHA v2解决错误或阅读全文CaptchaAI API 文档

相关文章

该文章已禁用评论。