API Tutorials

如何使用 Node.js 解决 reCAPTCHA v2 Enterprise

在接口层面,reCAPTCHA v2 Enterprise 和标准 v2 只差一个参数:提交任务时加上 enterprise=1。method 仍是 userrecaptcha,返回的仍是 g-recaptcha-response,现有 v2 代码可以直接复用。

小部件长得一样,差别在后端:Enterprise 走 Google 企业风控更严格地校验 token。容易踩坑的是三点:sitekey 取自 anchor URL、sa= 的 action 不能漏、token 要配响应里的 user_agent


动手前的准备

需要的东西 说明
CaptchaAI API Key CaptchaAI 控制台 注册获取
Node.js 14+ 用内置 fetch,更低版本装 node-fetch
sitekey anchor URL 里的 k= 参数
pageurl 验证码所在页面的完整 URL
action(可选) anchor URL 里的 sa= 参数

装依赖记得带国内镜像源。


第 1 步:确认这是 Enterprise v2

打开 DevTools 的 Network 面板,按 anchor 过滤:

https://www.google.com/recaptcha/enterprise/anchor?ar=1&k=6LdxxXXxAAAAAAcX...&sa=LOGIN&...

k=sitekeysa=(如果有)是 action。标准 v2 走 /recaptcha/api2/anchor,看到 api2 就别加 enterprise=1


第 2 步:向 CaptchaAI 提交任务

把 sitekey、pageurl 和 enterprise=1 一起发给 in.php,拿回任务 ID:

const API_KEY = "YOUR_API_KEY";

async function submitTask(sitekey, pageurl, action) {
  const params = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: sitekey,
    pageurl: pageurl,
    enterprise: "1",
    json: "1",
  });

  if (action) {
    params.set("action", action);
  }

  const response = await fetch(
    `https://ocr.captchaai.com/in.php?${params}`
  );
  const data = await response.json();

  if (data.status !== 1) {
    throw new Error(`Submit failed: ${data.request}`);
  }

  console.log(`Task submitted. ID: ${data.request}`);
  return data.request;
}

json=1 让接口返回 JSON;页面没有 action 就别传,也别传空字符串。


第 3 步:轮询识别结果

第一次轮询前等 20 秒,之后每 5 秒查一次 res.php

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

async function pollResult(taskId) {
  await delay(20000);

  for (let attempt = 0; attempt < 30; attempt++) {
    const params = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

    const response = await fetch(
      `https://ocr.captchaai.com/res.php?${params}`
    );
    const data = await response.json();

    if (data.status === 1) {
      console.log(`Solved. Token: ${data.request.substring(0, 60)}...`);
      return {
        token: data.request,
        userAgent: data.user_agent || "",
      };
    }

    if (data.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve failed: ${data.request}`);
    }

    console.log(`Attempt ${attempt + 1}: not ready, waiting 5s...`);
    await delay(5000);
  }

  throw new Error("Solve timed out");
}
  • CAPCHA_NOT_READY 表示还在识别中(拼写是接口原样),识别耗时一般 15–30 秒。
  • 返回其他值即任务失败,应立刻抛错,别继续轮询。

第 4 步:把 token 提交回表单

结果作为 g-recaptcha-response 随表单提交;响应带了 user_agent 就用同一个值发请求头:

async function submitForm(token, userAgent) {
  const headers = { "Content-Type": "application/x-www-form-urlencoded" };

  if (userAgent) {
    headers["User-Agent"] = userAgent;
  }

  const response = await fetch("https://example.com/api/login", {
    method: "POST",
    headers,
    body: new URLSearchParams({
      username: "user",
      password: "pass",
      "g-recaptcha-response": token,
    }),
  });

  console.log(`Response status: ${response.status}`);
  return response;
}

Puppeteer 或 Playwright 里做法一样:把 token 写进页面的 g-recaptcha-response 文本域再提交。


完整可运行脚本

const API_KEY = "YOUR_API_KEY";
const SITE_KEY = "6LdxxXXxAAAAAAcXxxXxxX91xxxxxxxx8xxOx7A";
const PAGE_URL = "https://staging.example.com/qa-login";
const ACTION = "LOGIN"; // optional — omit if not in anchor URL

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

async function solveRecaptchaV2Enterprise() {
  // Submit task
  const submitParams = new URLSearchParams({
    key: API_KEY,
    method: "userrecaptcha",
    googlekey: SITE_KEY,
    pageurl: PAGE_URL,
    enterprise: "1",
    action: ACTION,
    json: "1",
  });

  const submitRes = await fetch(
    `https://ocr.captchaai.com/in.php?${submitParams}`
  );
  const submitData = await submitRes.json();

  if (submitData.status !== 1) {
    throw new Error(`Submit error: ${submitData.request}`);
  }

  const taskId = submitData.request;
  console.log(`Task ID: ${taskId}`);

  // Poll for result
  await delay(20000);

  for (let i = 0; i < 30; i++) {
    const pollParams = new URLSearchParams({
      key: API_KEY,
      action: "get",
      id: taskId,
      json: "1",
    });

    const pollRes = await fetch(
      `https://ocr.captchaai.com/res.php?${pollParams}`
    );
    const pollData = await pollRes.json();

    if (pollData.status === 1) {
      return {
        token: pollData.request,
        userAgent: pollData.user_agent || "",
      };
    }

    if (pollData.request !== "CAPCHA_NOT_READY") {
      throw new Error(`Solve error: ${pollData.request}`);
    }

    await delay(5000);
  }

  throw new Error("Solve timed out");
}

(async () => {
  const { token, userAgent } = await solveRecaptchaV2Enterprise();
  console.log(`Token: ${token.substring(0, 60)}...`);
  if (userAgent) console.log(`User-Agent: ${userAgent}`);
})();

预期输出

Task ID: 73849562810
Token: 03AGdBq24PBCqLmOx2V4pGHJjkR2xZ1r...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...

排错对照表

错误 原因 处理方式
ERROR_WRONG_USER_KEY API Key 格式不对 确认是控制台里的 32 位字符
ERROR_KEY_DOES_NOT_EXIST 找不到这个 Key CaptchaAI 控制台 核对
ERROR_ZERO_BALANCE 余额不足 充值后重试
ERROR_BAD_TOKEN_OR_PAGEURL sitekey 或 URL 不对 从 anchor URL 重新取 k=
ERROR_CAPTCHA_UNSOLVABLE 本次未能识别 确认是 Enterprise v2 后重试
站点拒绝 token User-Agent 不一致 用响应里返回的 user_agent

出海项目的两个现实问题

国内站点多用 GeeTest(极验)、腾讯防水墙;Enterprise v2 更多出现在出海业务:海外 SaaS 后台、跨境电商商家中心。

  • 前端脚本走 Google 域名:reCAPTCHA 的脚本由 Google 域名托管,内地网络下未必稳定,小部件加载不出来常被误判成代码 bug。识别请求走 ocr.captchaai.com,是另一条链路。
  • 线程数按峰值并发估:CaptchaAI 按线程计费,套餐内识别次数不限,规划依据是“同时有多少页面在等结果”,不是每天跑多少次。BASIC($15/月,5 线程)够一个巡检脚本,多节点采集集群可选 ADVANCE($90/月,50 线程)。

采集范围请限定在自有或已获授权的站点,遵守《网络安全法》与 PIPL。


常见问题

拿到的 token 有效期多久?

大约 2 分钟,拿到就立刻提交表单,别先入库再消费。

一直返回 CAPCHA_NOT_READY 怎么办?

先确认 pageurl 是验证码真实出现的页面,再确认 sitekey 取自 Enterprise anchor URL。

识别失败会扣费吗?

不会按次扣。CaptchaAI 按线程计费,套餐内识别次数不限;失败任务只占线程时间,重试即可。


现在就跑通第一次识别

CaptchaAI 官网 注册拿 API Key,把脚本里的 sitekey、pageurl 换成自己的,几分钟就能拿到第一个 token。


相关阅读

对照着看:API 版说明Python 版教程常见错误与修复如何判断站点是否用了 Enterprise

该文章已禁用评论。