Comparisons

reCAPTCHA v3 企业版与标准版比较

先给结论:对写自动化的人来说,reCAPTCHA v3 的标准版和 Enterprise 版只差一个提交参数——enterprise=1。两者都不弹窗、不出九宫格,都返回 0.0(机器人)到 1.0(真人)的分数。真正踩坑的不是识别本身,而是 Enterprise 允许站点给每个 action 单独设阈值。同一个 token 在标准版放行、在 Enterprise 被打回,原因通常就在这里。


一分钟判断站点用的是标准版 v3 还是 Enterprise

肉眼分不出来,两版都在后台静默打分,只能看两处:脚本是 enterprise.js 还是 api.js,JS 调的是 grecaptcha.enterprise.execute() 还是 grecaptcha.execute()。另外 v3 的 sitekey 在脚本 URL 的 render= 里,不在 data-sitekey 上。

一段正则就能把版本、sitekey 和 action 一起抓出来:

import requests
import re

def detect_v3_version(url):
    html = requests.get(url).text

    if "enterprise.js" in html:
        version = "enterprise"
    elif "recaptcha/api.js" in html and "render=" in html:
        version = "standard"
    else:
        return None

    # Extract sitekey
    key_match = re.search(r'render[=:]\s*["\']?([A-Za-z0-9_-]{40})', html)
    sitekey = key_match.group(1) if key_match else None

    # Extract action
    action_match = re.search(r'action["\']?\s*[:=]\s*["\'](\w+)', html)
    action = action_match.group(1) if action_match else None

    return {"version": version, "sitekey": sitekey, "action": action}

Node.js 同理:

const axios = require("axios");

async function detectV3Version(url) {
  const { data: html } = await axios.get(url);

  const version = html.includes("enterprise.js")
    ? "enterprise"
    : html.includes("recaptcha/api.js") && html.includes("render=")
      ? "standard"
      : null;

  const keyMatch = html.match(/render[=:]\s*['"]?([A-Za-z0-9_-]{40})/);
  const actionMatch = html.match(/action['"]?\s*[:=]\s*['"](\w+)/);

  return {
    version,
    sitekey: keyMatch?.[1],
    action: actionMatch?.[1],
  };
}

别把版本写死。站点切到 Enterprise 往往只换一行脚本,不会有公告;判断放进每次请求最稳。


标准版 v3 与 Enterprise 的能力对照

多出来的功能几乎都在站点方,不在你这一侧:

功能项 标准版 v3 Enterprise v3
静默运行
分数(0.0–1.0)
action 参数 必填 必填
原因代码
按 action 自定义阈值 有(Cloud Console)
密码泄露检测
Account Defender
反欺诈标签
多因素认证集成
校验接口 siteverify(免费) recaptchaenterprise.googleapis.com
每月额度 100 万次评估免费 按次计费
JS 文件 api.js?render=KEY enterprise.js?render=KEY
CaptchaAI 提交参数 version=v3 version=v3 + enterprise=1

对你直接生效的只有最后一行;其余决定站点后台怎么解读你的 token。


原因代码:站点看得到,你看不到

Enterprise 的评估响应带一组原因代码,说明分数怎么来的。它们只返回给站点后端,不出现在 CaptchaAI 的识别结果里;价值在于反推站点在看什么。

代码 含义 对自动化的提示
AUTOMATION 检测到自动化行为特征 用真实浏览器环境,别裸跑请求
UNEXPECTED_ENVIRONMENT 浏览器环境异常 排查无头浏览器的默认特征
TOO_MUCH_TRAFFIC 同一来源请求量过高 加限流,降低并发
UNEXPECTED_USAGE_PATTERNS 交互节奏不正常 操作之间留出真实间隔
LOW_CONFIDENCE_SCORE 信号太少,无法可信打分 让页面多加载一会儿再触发
SUSPECTED_CARDING 疑似盗刷信用卡 与常规自动化无关
SUSPECTED_CHARGEBACK 疑似拒付欺诈 与常规自动化无关

后两项针对支付欺诈,常规 QA 碰不到;前四项才是“分数变低”的实际来源。


阈值:Enterprise 真正变严的地方

标准版 v3 用 Google 的全局模型,站点通常只维护一个阈值,常见 0.5。Enterprise 在此之上又叠一层:

评分维度 标准版 Enterprise
基础模型 Google 全局模型 全局模型 + 站点自定义信号
阈值粒度 全站一个 每个 action 一个(登录 0.7、结算 0.9)
自适应学习 基础 基于本站流量持续学习
分数精度 0.0–1.0,两位小数 区间相同,信号更细
误判处理 人工调阈值 结合原因代码分析

所以 Enterprise 站点上 action 不再可有可无:你提交 action=verify,站点按 login 的 0.7 去卡,token 就白拿了。从 grecaptcha.enterprise.execute() 的实参里原样抠出 action 即可。

一个具体场景。 给出海电商后台做回归测试常撞上:注册页是标准版、阈值 0.5,怎么提交都过;下单页迁到 Enterprise 后单独给 checkout 设了 0.9。脚本一行没改,注册照常通过,下单却间歇性失败——同一站点两条链路两套阈值。分别提取并提交对应 action 即可。

国内站点更常见的是 GeeTest(极验)和腾讯防水墙,v3 基本只出现在出海业务上。


用 CaptchaAI 识别:两段代码的唯一差别

CaptchaAI 支持 v3 与 v3 Enterprise,方法都是 userrecaptcha,走 in.php 提交、res.php 轮询。标准版:

import requests
import time

resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "version": "v3",
    "googlekey": sitekey,
    "action": "login",
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

Enterprise 只多一个 enterprise 参数,其余不变:

import requests
import time

# Only difference: enterprise=1
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "version": "v3",
    "enterprise": 1,
    "googlekey": sitekey,
    "action": "login",
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

把判断和提交合成一个类最省事,站点换版本时代码不用动:

class V3AutoSolver:
    def __init__(self, api_key):
        self.api_key = api_key

    def solve(self, page_url, action=None):
        import re
        html = requests.get(page_url).text

        is_enterprise = "enterprise.js" in html
        key_match = re.search(r'render[=:]\s*["\']?([A-Za-z0-9_-]{40})', html)
        if not key_match:
            raise Exception("No v3 sitekey found")

        if not action:
            act_match = re.search(r'action["\']?\s*[:=]\s*["\'](\w+)', html)
            action = act_match.group(1) if act_match else "verify"

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "version": "v3",
            "googlekey": key_match.group(1),
            "action": action,
            "pageurl": page_url
        }
        if is_enterprise:
            params["enterprise"] = 1

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

        task_id = resp.text.split("|")[1]
        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key, "action": "get", "id": task_id
            })
            if result.text.startswith("OK|"):
                return result.text.split("|")[1]
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve error: {result.text}")
        raise Exception("Timed out")

计费也不按版本分账:CaptchaAI 按并发线程计费,套餐内识别次数不限,两版共用同一份线程额度。BASIC $15/月、5 线程,STANDARD $30/月、15 线程,ADVANCE $90/月、50 线程,更高并发再往上选。


常见故障对照

现象 可能原因 处理方式
token 在 Enterprise 站点被拒 漏了 enterprise=1 确认加载的是 enterprise.js,补上参数
Enterprise 站点分数偏低 action 传错 grecaptcha.enterprise.execute() 取准确 action
测试环境正常,生产失败 自适应学习认出了你的请求模式 降并发、拉开间隔,节奏更接近真实用户
ERROR_WRONG_GOOGLEKEY data-sitekey 取值了 v3 的 sitekey 在脚本 URL 的 render=
长时间 CAPCHA_NOT_READY 轮询太急或任务在排队 保持 5 秒一次,设整体超时上限

常见问题

action 传错会怎样,可以随便填一个吗?

标准版站点通常只有一个全站阈值,填错影响不大;Enterprise 按 action 分别设阈值,填错等于拿另一条链路的判定线来卡你,token 大概率被拒。原样取值,不要自己编。

Enterprise 站点上的分数为什么比标准版低?

分数未必更低,是判定线更高。Enterprise 允许按 action 分别设阈值,同一个 0.7 在一条链路上通过、在另一条上就不够用。先确认该 action 的阈值再看分数。

站点从标准版迁到 Enterprise,我要改多少代码?

提交侧只需加 enterprise=1。真正该改的是判断逻辑:版本检测放进每次请求,站点静默换版时才不会整批失败。

原因代码能在 CaptchaAI 的返回里看到吗?

看不到。原因代码由 Google 的评估接口返回给站点后端,识别服务这一侧拿不到。它的用处是反向排查:知道站点在看 AUTOMATIONTOO_MUCH_TRAFFIC 这类信号,就能判断该调并发还是该调节奏。

国内测试环境跑 v3 老是超时,是识别慢吗?

多半不是。reCAPTCHA 的脚本由 Google 域名分发,境内加载本身就不稳定,页面没渲染完就触发识别,自然拿不到结果。把这段网络耗时算进整体超时,或换一个能正常访问该站点的网络环境再测。


延伸阅读

该文章已禁用评论。