什么是 reCAPTCHA v2,以及它为何在 2026 年仍然重要
reCAPTCHA v2 是 Google 开发的一种机器人检测挑战。它会向用户呈现以下其中一种形式:
- 复选框(“我不是机器人”) —— 用户单击一次即可触发后台行为分析;如果风险评分较低,就不会出现图片挑战。
- Invisible reCAPTCHA v2 —— 完全在后台运行,只有在风险评分较高时才会显示挑战。
- reCAPTCHA Enterprise —— 一种单独的付费 Google Cloud 产品,会给出数值化风险评分(0.0–1.0),提供原因代码,并支持可配置阈值以及 Account Defender 和 MFA(多因素身份验证)等功能。
尽管像 reCAPTCHA v3 这样的新版本以及 Cloudflare Turnstile 这类替代方案正逐步普及,但 v2 仍被广泛部署,因为它更为人熟悉,而且免费额度较为宽松(每个站点每月最多 10,000 次评估)。开发者通常不会迁移,除非有明确理由,因此这种复选框挑战短期内不会消失。
reCAPTCHA v2 的工作原理(底层机制)
理解其工作机制有助于你更可靠地解决 reCAPTCHA v2。整个流程包含三个关键组成部分:
- Sitekey —— 嵌入在页面 HTML 中的公钥,用于向 Google 服务器标识网站。你可以在 reCAPTCHA 小部件 <div> 的 data-sitekey 属性中找到它。
- 挑战 + 用户交互 —— Google 会评估浏览器信号(鼠标移动、Cookie、IP、浏览器指纹),并可选择呈现图片网格(例如“选择所有交通信号灯”)。
- g-recaptcha-response token —— 成功完成挑战后,Google 会签发一个短时有效的 token;该 token 有效期为两分钟,并且只能验证一次。小部件会将其注入隐藏的 <textarea id="g-recaptcha-response"> 中,表单会连同其他字段一起提交它。服务器随后使用 secret key 通过 Google 的 siteverify API 验证该 token。
自动化中的关键洞察:你并不需要模拟像素级精确的鼠标移动。你真正需要的是一个有效的 g-recaptcha-response token。基于 API 的求解服务负责处理挑战并返回该 token——而你唯一需要做的,就是在提交表单前将它注入进去。
解决 reCAPTCHA v2 的现代方法——概览
在深入介绍每种方法之前,下面是一个快速对比,帮助你选择合适的方案:
| 方法 | 速度 | 所需代码 | 最适合 | 成本 |
| API 求解器(CapMonster Cloud) | 通常 1–30 秒 | 很少(API 调用) | 自动化、抓取、CI/CD | 每 1,000 个 token 收费 $0.60,每 1,000 张图片收费 $0.04(当前价格请参见定价页面) |
| Python + Selenium + API 求解器* | 通常 1–30 秒 | 中等(Python) | 脚本化浏览器自动化 | 与上相同** |
| Node.js + Playwright + API 求解器* | 通常 1–30 秒 | 中等(JS/TS) | 基于 Node 的流水线 | 与上相同** |
| 浏览器扩展 | 通常 1–30 秒 | 无 | 手动测试、一次性任务 | 与上相同*** |
| 人工服务 | 通常 25–60 秒 | 无 / 极少 | 低量级使用 | 因服务商和使用量而异 |
* 你可以按自己的需要自由组合编程语言(Python、JS、C#)和自动化框架(Playwright、Selenium、Puppeteer)。这里仅是这类技术栈的示例。
** 如果在该技术栈中使用 CapMonster Cloud 作为 API 求解器,则适用。
*** 如果使用的是 CapMonster Cloud Browser Extensions,则适用。
方法 1 —— 使用 CapMonster Cloud 进行基于 API 的求解
CapMonster Cloud 是一项基于 AI 的 CAPTCHA 求解服务,提供简单的 REST API。它支持 reCAPTCHA v2(标准版、Invisible 版和 Enterprise 版),并返回可直接使用的 g-recaptcha-response token。
工作原理:
- 你向 CapMonster Cloud API 发送一个任务,其中包含 sitekey 和 CAPTCHA 页面 URL。
- CapMonster Cloud 的求解器处理该挑战。
- 你轮询结果端点并接收 token。
- 你将 token 注入页面并提交表单。
步骤 1 —— 创建任务
POST https://api.capmonster.cloud/createTask
Content-Type: application/json
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "RecaptchaV2Task",
"websiteURL": "https://example.com/login",
"websiteKey": "YOUR_SITEKEY"
}
}
可用的任务类型(当前的 CapMonster Cloud 命名):
- RecaptchaV2Task —— 无代理(CapMonster Cloud 使用其自有代理),或使用你自己的代理(HTTP/HTTPS/SOCKS4/SOCKS5)
- RecaptchaV2EnterpriseTask —— 用于 Enterprise 变体
响应:
{
"errorId": 0,
"taskId": 7654321
}
步骤 2 —— 轮询结果
POST https://api.capmonster.cloud/getTaskResult
Content-Type: application/json
{
"clientKey": "YOUR_API_KEY",
"taskId": 7654321
}
响应(准备就绪时):
{
"errorId": 0,
"status": "ready",
"solution": {
"gRecaptchaResponse": "03AGdBq24PBCbwiDRaS_MJ..."
}
}
步骤 3 —— 注入 Token
一旦你收到 token,
可以在 HTTP 请求中发送它:
POST /api/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123",
"g-recaptcha-response": "03AGdBq24PBC..."
}
或者将其注入页面:
// Browser console, Selenium execute_script, or Playwright evaluate
const token = '03AGdBq24PBCbwiDRaS_MJ...';
const ta = document.getElementById('g-recaptcha-response');
ta.value = token; // canonical for <textarea>
ta.innerHTML = token; // equivalent fallback some integrations rely on
document.querySelector('#login-form')?.requestSubmit();
有关更详细的注入示例,请参见下一节。
试用 CapMonster Cloud reCAPTCHA v2 求解器 →
方法 2 —— 在 Python 中解决 reCAPTCHA v2(Selenium + CapMonster Cloud)
这种方法非常适合 reCAPTCHA v2 Python 自动化工作流:你通过 Selenium 控制真实浏览器,并需要在会话中途解决挑战。
先决条件
在你的控制台/终端中运行以下命令:
pip install selenium capmonstercloudclient python-dotenv
创建一个 .env 文件,并填入你当前的数据:
API_KEY=your_capmonster_cloud_api_key
WEBSITE_URL=https://example.com/login
WEBSITE_KEY=website_key_of_the_page_with_captcha
完整 Python 示例
import asyncio
import os
from dotenv import load_dotenv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from capmonstercloudclient import CapMonsterClient, ClientOptions
from capmonstercloudclient.requests import RecaptchaV2Request
load_dotenv()
API_KEY = os.getenv("API_KEY")
WEBSITE_URL = os.getenv("WEBSITE_URL")
WEBSITE_KEY = os.getenv("WEBSITE_KEY") # sitekey from the page
client_options = ClientOptions(api_key=API_KEY)
cap_monster_client = CapMonsterClient(options=client_options)
async def solve_captcha() -> str:
recaptcha_request = RecaptchaV2Request(
websiteUrl=WEBSITE_URL,
websiteKey=WEBSITE_KEY,
)
result = await cap_monster_client.solve_captcha(recaptcha_request)
return result["gRecaptchaResponse"]
async def main():
browser = None
try:
options = webdriver.ChromeOptions()
# 可选:隐藏“Chrome is being controlled by automated software”信息栏
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
browser = webdriver.Chrome(options=options)
browser.get(WEBSITE_URL)
print("Page opened, waiting for reCAPTCHA widget...")
# 等待小部件容器出现
WebDriverWait(browser, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".g-recaptcha"))
)
print("reCAPTCHA widget found.")
# 通过 CapMonster Cloud 解决 CAPTCHA
token = await solve_captcha()
print("Token received:", token[:40] + "...")
# 1) 让 textarea 可见(某些页面会通过内联样式隐藏它)
# 并注入 token 值
browser.execute_script(
"""
const ta = document.getElementById('g-recaptcha-response');
if (ta) {
ta.style.display = 'block';
ta.style.visibility = 'visible';
ta.value = arguments;
ta.innerHTML = arguments;
}
""",
token,
)
# 2) 如果在 data-callback 属性中定义了 reCAPTCHA 回调,则触发它
browser.execute_script(
"""
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget ? widget.getAttribute('data-callback') : null;
if (callbackName && typeof window[callbackName] === 'function') {
window[callbackName](arguments);
}
""",
token,
)
print("Token injected and callback triggered.")
# 3) 定位提交按钮——尝试多个可能的选择器,或者设置当前页面实际存在的选择器
submit_selectors = [
(By.CSS_SELECTOR, "input[type='submit']"),
(By.CSS_SELECTOR, "button[type='submit']"),
(By.CSS_SELECTOR, "form button"),
(By.XPATH, "//input[@type='submit']"),
(
By.XPATH,
"//button[contains(text(),'Submit') or contains(text(),'Check')]",
),
]
submit_btn = None
for by, selector in submit_selectors:
try:
submit_btn = WebDriverWait(browser, 3).until(
EC.element_to_be_clickable((by, selector))
)
print(f"Submit button found via: {selector}")
break
except Exception:
continue
if submit_btn is None:
raise RuntimeError(
"Submit button not found! Check the page structure manually."
)
submit_btn.click()
print("Form submitted.")
# 等待页面响应
await asyncio.sleep(3)
# 输出提交后的 URL(成功时可能会发生重定向)
print("Current URL after submit:", browser.current_url)
# 在页面中查找成功消息
try:
success = browser.find_element(
By.XPATH,
"//*[contains(text(),'success') or contains(text(),'Success') or contains(text(),'correct')]",
)
print("Success message found:", success.text)
except Exception:
print("No explicit success message found on page.")
except Exception as e:
print("Error:", e)
finally:
if browser is not None:
input("Press ENTER to close browser...") # 暂停以便手动检查
browser.quit()
if __name__ == "__main__":
asyncio.run(main())
关键点说明:
- RecaptchaV2Request(不带代理字段)是无代理流程的标准导入方式。如果你需要通过自己的 IP 路由求解请求,请创建一个 ProxyInfo 对象(包含 proxyType、proxyAddress 等),并通过 RecaptchaV2Request 中的 proxy 参数传入(更多细节参见文档)。
- solve_captcha() 会向 CapMonster Cloud 发送异步任务,并从 result["gRecaptchaResponse"] 返回已求解的 token 字符串。
- 该 token 通过 arguments 传递给 execute_script,这种方式比使用 f-string 构造 JS 字面量更安全。
- 隐藏的 textarea 同时通过 .value 和 .innerHTML 进行更新——同时设置这两个值可以最大程度兼容不同版本的 reCAPTCHA 小部件。
- WebDriverWait 替代了简单粗暴的 sleep,使脚本在页面加载较慢时也更稳健。
- browser 在 try 外部被初始化为 None,因此即使 webdriver.Chrome() 本身失败,finally 代码块也不会因为 NameError 而报错。
⚠️ Token 过期时间:token 自签发起仅在两分钟内有效,且只能验证一次。请在提交表单前立即请求 token,并且不要在注入与提交之间拖延。