如何在Vibium中无需扩展程序解决验证码(reCAPTCHA、Turnstile、AWS WAF)

当 AI 代理自动化浏览器完成现实世界任务时,CAPTCHAs 是最大的障碍。受保护的页面会阻止代理,表单无法提交,整个工作流程会因等待人工干预而停滞。
Vibium 是一种下一代浏览器自动化工具,专为 AI 代理和人类用户设计。它基于 WebDriver BiDi 协议,由 Selenium 和 Appium 的开发者创建,为代理提供了一种快速、基于标准的方式控制浏览器。但像任何自动化工具一样,它也会被 CAPTCHAs 阻止。
这里有个问题:Vibium 在其 Go 启动器中硬编码了 --disable-extensions。 你无法传递自定义的 Chrome 标志。这意味着 Playwright 和 Puppeteer 等工具使用的 Chrome 扩展方法在此处不起作用。
CapSolver 通过不同的策略解决了这个问题。它不依赖浏览器扩展,而是直接调用 CapSolver REST API 来解决 CAPTCHA,然后使用 Vibium 的 JavaScript 评估功能将生成的令牌注入页面。这种基于 API 的方法提供了完全的控制,并与 Vibium 的架构完美兼容。
什么是 Vibium?
Vibium 是一个专为 AI 代理和人工操作员设计的浏览器自动化平台。它作为一个单独的 Go 二进制文件提供,安装时无需配置,并使用现代的 WebDriver BiDi 协议与浏览器进行快速、双向通信。
关键功能
- WebDriver BiDi 协议:基于标准的双向浏览器通信(非 CDP)
- MCP 服务器:内置的模型上下文协议服务器,使 AI 代理可以原生控制浏览器
- 语义元素查找:通过语义定位元素,而不仅仅是 CSS 选择器
- 多语言 SDK:支持 JavaScript/TypeScript、Python 和 Java 的客户端库
- 单个 Go 二进制文件:零依赖、零配置,只需下载并运行
- 由 Selenium/Appium 开发者创建:在浏览器自动化标准方面具有深厚的专业知识
AI 代理使用场景
Vibium 的 MCP 服务器允许 AI 代理通过标准化协议发出浏览器命令。代理可以:
- 导航到 URL 并与页面交互
- 通过语义定位元素(“登录按钮”而不是
#btn-login) - 通过
browser_evaluate在页面上评估任意 JavaScript - 填写表单、点击按钮、提取内容
- 管理多个浏览器会话
可以将其视为给你的 AI 代理一个它可以用自然语言交谈的浏览器。
什么是 CapSolver?
CapSolver 是一个领先的 CAPTCHA 解决服务,提供 AI 驱动的解决方案来绕过各种 CAPTCHA 挑战。它支持多种 CAPTCHA 类型,并具有快速的响应时间,可无缝集成到自动化工作流中。
支持的 CAPTCHA 类型
- reCAPTCHA v2(基于图像和隐形)
- reCAPTCHA v3 & v3 Enterprise
- Cloudflare Turnstile
- Cloudflare 5 秒挑战
- AWS WAF CAPTCHA
- 其他广泛使用的 CAPTCHA 和反机器人机制
为什么这个集成不同
大多数浏览器自动化工具(Playwright、Puppeteer、OpenClaw、NanoClaw)通过直接在浏览器中加载 CapSolver Chrome 扩展来解决 CAPTCHAs。扩展会自动检测 CAPTCHAs,在后台解决它们,并无形地注入令牌。
Vibium 不能使用这种方法。 Go 启动器在启动 Chrome 时硬编码了 --disable-extensions。没有配置选项或变通方法来加载扩展。
相反,集成直接使用 CapSolver REST API:
| 扩展方法(Playwright 等) | API 方法(Vibium) | |
|---|---|---|
| 工作原理 | 扩展自动检测并无声解决 CAPTCHAs | 你的代码调用 API,获取令牌,注入它 |
| 需要扩展 | 是(通过 --load-extension 加载 Chrome 扩展) |
否(纯 HTTP API 调用) |
| 代理意识 | 代理不需要知道 CAPTCHAs | 代理(或脚本)主动管理解决流程 |
| Chrome 标志 | 需要 --load-extension 支持 |
与任何 Chrome 标志兼容,包括 --disable-extensions |
| 控制 | 自动,不透明 | 明确,对每个步骤有完全控制 |
| 灵活性 | 仅限于扩展支持的内容 | 可自定义检测、重试逻辑、按站点注入令牌 |
| 最适合 | 允许自定义 Chrome 参数的工具 | 像 Vibium 这样限制 Chrome 参数的工具 |
关键洞察:API 方法实际上更强大。你控制何时检测、何时解决,以及如何精确注入令牌。它与任何浏览器自动化工具兼容,无论其 Chrome 标志限制如何。
前提条件
在设置集成之前,请确保您已:
- 安装 Vibium (从 GitHub 下载)
- 拥有 CapSolver 账户和 API 密钥 (在此注册)
- 任选其一:Node.js 18+ / Python 3.8+ / Java 17+
安装 Vibium
# macOS / Linux — 单个二进制文件,零依赖
curl -fsSL https://vibium.dev/install.sh | bash
# 或直接从 GitHub 发布页面下载
# https://github.com/VibiumDev/vibium/releases
验证安装:
vibium --version
测试无需 Chrome
Vibium 管理自己的浏览器生命周期。你不需要安装 Chrome for Testing、Playwright 的内置 Chromium 或任何特殊浏览器变体。Vibium 内部处理浏览器的下载和管理。
分步设置
第 1 步:获取 CapSolver API 密钥
- 在 capsolver.com 注册
- 导航到你的仪表板
- 复制你的 API 密钥(以
CAP-开头)
将其设置为环境变量:
export CAPSOLVER_API_KEY="CAP-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
第 2 步:安装 Vibium SDK 和 HTTP 客户端
JavaScript:
npm install vibium
Python:
pip install vibium requests
Java (Gradle):
implementation 'com.vibium:vibium:26.3.18'
第 3 步:创建 CAPTCHA 检测辅助工具
在解决 CAPTCHA 之前,你需要知道它的类型并提取站点密钥。使用 Vibium 的 browser_evaluate 检查页面。
检测 JavaScript 在所有三种语言中都相同——只有主机调用不同:
JavaScript:
const { browser } = require('vibium/sync')
function detectCaptcha(page) {
return page.evaluate(`(() => {
const v2 = document.querySelector('.g-recaptcha');
if (v2) return { type: 'recaptcha-v2', siteKey: v2.getAttribute('data-sitekey') };
for (const s of document.querySelectorAll('script[src*="recaptcha/api.js"]')) {
const m = s.src.match(/render=([^&]+)/);
if (m && m[1] !== 'explicit') return { type: 'recaptcha-v3', siteKey: m[1] };
}
const t = document.querySelector('.cf-turnstile');
if (t) return { type: 'turnstile', siteKey: t.getAttribute('data-sitekey') };
return { type: 'none', siteKey: null };
})()`)
}
Python:
from vibium import browser
def detect_captcha(page) -> dict:
return page.evaluate("""(() => {
const v2 = document.querySelector('.g-recaptcha');
if (v2) return { type: 'recaptcha-v2', siteKey: v2.getAttribute('data-sitekey') };
for (const s of document.querySelectorAll('script[src*="recaptcha/api.js"]')) {
const m = s.src.match(/render=([^&]+)/);
if (m && m[1] !== 'explicit') return { type: 'recaptcha-v3', siteKey: m[1] };
}
const t = document.querySelector('.cf-turnstile');
if (t) return { type: 'turnstile', siteKey: t.getAttribute('data-sitekey') };
return { type: 'none', siteKey: null };
})()""")
Java:
var result = page.evaluate("""
(() => {
const v2 = document.querySelector('.g-recaptcha');
if (v2) return { type: 'recaptcha-v2', siteKey: v2.getAttribute('data-sitekey') };
for (const s of document.querySelectorAll('script[src*="recaptcha/api.js"]')) {
const m = s.src.match(/render=([^&]+)/);
if (m && m[1] !== 'explicit') return { type: 'recaptcha-v3', siteKey: m[1] };
}
const t = document.querySelector('.cf-turnstile');
if (t) return { type: 'turnstile', siteKey: t.getAttribute('data-sitekey') };
return { type: 'none', siteKey: null };
})()
""");
String captchaType = (String) ((Map) result).get("type");
String siteKey = (String) ((Map) result).get("siteKey");
第 4 步:创建 CAPTCHA 解决函数
调用 CapSolver API 创建任务,然后轮询结果。
JavaScript:
const CAPSOLVER_API = 'https://api.capsolver.com'
const API_KEY = process.env.CAPSOLVER_API_KEY
async function createTask(taskData) {
const res = await fetch(`${CAPSOLVER_API}/createTask`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientKey: API_KEY, task: taskData }),
})
const data = await res.json()
if (data.errorId !== 0) throw new Error(`CapSolver: ${data.errorDescription}`)
return data.taskId
}
async function getTaskResult(taskId, maxAttempts = 60) {
for (let i = 0; i < maxAttempts; i++) {
await new Promise(r => setTimeout(r, 2000))
const res = await fetch(`${CAPSOLVER_API}/getTaskResult`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientKey: API_KEY, taskId }),
})
const data = await res.json()
if (data.status === 'ready') return data
if (data.status === 'failed') throw new Error(`Failed: ${data.errorDescription}`)
}
throw new Error('Timeout')
}
async function solveCaptcha(captchaInfo, pageUrl) {
const taskTypes = {
'recaptcha-v2': { type: 'ReCaptchaV2TaskProxyLess', websiteURL: pageUrl, websiteKey: captchaInfo.siteKey },
'recaptcha-v3': { type: 'ReCaptchaV3TaskProxyLess', websiteURL: pageUrl, websiteKey: captchaInfo.siteKey, pageAction: 'submit' },
'turnstile': { type: 'AntiTurnstileTaskProxyLess', websiteURL: pageUrl, websiteKey: captchaInfo.siteKey },
}
const taskData = taskTypes[captchaInfo.type]
if (!taskData) throw new Error(`Unsupported: ${captchaInfo.type}`)
const taskId = await createTask(taskData)
const result = await getTaskResult(taskId)
return result.solution.gRecaptchaResponse || result.solution.token || ''
}
Python:
import os, time, requests
CAPSOLVER_API = "https://api.capsolver.com"
API_KEY = os.environ["CAPSOLVER_API_KEY"]
def create_task(task_data: dict) -> str:
data = requests.post(f"{CAPSOLVER_API}/createTask",
json={"clientKey": API_KEY, "task": task_data}).json()
if data.get("errorId", 0) != 0:
raise Exception(f"CapSolver: {data.get('errorDescription')}")
return data["taskId"]
def get_task_result(task_id: str, max_attempts: int = 60) -> dict:
for _ in range(max_attempts):
time.sleep(2)
data = requests.post(f"{CAPSOLVER_API}/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id}).json()
if data["status"] == "ready":
return data
if data["status"] == "failed":
raise Exception(f"Failed: {data.get('errorDescription')}")
raise Exception("Timeout")
def solve_captcha(captcha_info: dict, page_url: str) -> str:
task_types = {
"recaptcha-v2": {"type": "ReCaptchaV2TaskProxyLess", "websiteURL": page_url, "websiteKey": captcha_info["siteKey"]},
"recaptcha-v3": {"type": "ReCaptchaV3TaskProxyLess", "websiteURL": page_url, "websiteKey": captcha_info["siteKey"], "pageAction": "submit"},
"turnstile": {"type": "AntiTurnstileTaskProxyLess", "websiteURL": page_url, "websiteKey": captcha_info["siteKey"]},
}
task_data = task_types.get(captcha_info["type"])
if not task_data:
raise Exception(f"Unsupported: {captcha_info['type']}")
result = get_task_result(create_task(task_data))
solution = result.get("solution", {})
return solution.get("gRecaptchaResponse") or solution.get("token", "")
Java:
import java.net.http.*;
import java.net.URI;
import org.json.*;
String CAPSOLVER_API = "https://api.capsolver.com";
String API_KEY = System.getenv("CAPSOLVER_API_KEY");
HttpClient http = HttpClient.newHttpClient();
String createTask(JSONObject taskData) throws Exception {
var body = new JSONObject()
.put("clientKey", API_KEY)
.put("task", taskData);
var req = HttpRequest.newBuilder(URI.create(CAPSOLVER_API + "/createTask"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.build();
var data = new JSONObject(http.send(req, HttpResponse.BodyHandlers.ofString()).body());
if (data.getInt("errorId") != 0) throw new Exception("CapSolver: " + data.getString("errorDescription"));
return data.getString("taskId");
}
JSONObject getTaskResult(String taskId) throws Exception {
for (int i = 0; i < 60; i++) {
Thread.sleep(2000);
var body = new JSONObject().put("clientKey", API_KEY).put("taskId", taskId);
var req = HttpRequest.newBuilder(URI.create(CAPSOLVER_API + "/getTaskResult"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.build();
var data = new JSONObject(http.send(req, HttpResponse.BodyHandlers.ofString()).body());
if ("ready".equals(data.getString("status"))) return data;
if ("failed".equals(data.getString("status"))) throw new Exception("Failed: " + data.getString("errorDescription"));
}
throw new Exception("Timeout");
}
第 5 步:通过 Vibium 的 browser_evaluate 注入已解决的令牌
一旦你有了令牌,使用 JavaScript 评估将其注入页面的隐藏表单字段中。
注入 JavaScript 在所有语言中都相同——reCAPTCHA 回调遍历确保令牌被接受:
JavaScript:
function injectToken(page, captchaType, token) {
if (captchaType === 'recaptcha-v2' || captchaType === 'recaptcha-v3') {
page.evaluate(`
document.querySelector('textarea[name="g-recaptcha-response"]').value = "${token}";
try {
const clients = ___grecaptcha_cfg.clients;
for (const id in clients) {
const find = (o) => { for (const k in o) {
if (typeof o[k]==='object' && o[k]!==null) {
if (typeof o[k].callback==='function') { o[k].callback("${token}"); return true; }
if (find(o[k])) return true;
}
} return false; };
find(clients[id]);
}
} catch(e) {}
`)
} else if (captchaType === 'turnstile') {
page.evaluate(`
document.querySelector('input[name="cf-turnstile-response"]').value = "${token}";
try { const cb = document.querySelector('.cf-turnstile')?.getAttribute('data-callback');
if (cb && typeof window[cb]==='function') window[cb]("${token}");
} catch(e) {}
`)
}
}
Python:
def inject_token(page, captcha_type: str, token: str):
if captcha_type in ("recaptcha-v2", "recaptcha-v3"):
page.evaluate(f"""
document.querySelector('textarea[name="g-recaptcha-response"]').value = "{token}";
try {{
const clients = ___grecaptcha_cfg.clients;
for (const id in clients) {{
const find = (o) => {{ for (const k in o) {{
if (typeof o[k]==='object' && o[k]!==null) {{
if (typeof o[k].callback==='function') {{ o[k].callback("{token}"); return true; }}
if (find(o[k])) return true;
}}
}} return false; }};
find(clients[id]);
}}
}} catch(e) {{}}
""")
elif captcha_type == "turnstile":
page.evaluate(f"""
document.querySelector('input[name="cf-turnstile-response"]').value = "{token}";
try {{ const cb = document.querySelector('.cf-turnstile')?.getAttribute('data-callback');
if (cb && typeof window[cb]==='function') window[cb]("{token}");
}} catch(e) {{}}
""")
Java:
void injectToken(Page page, String captchaType, String token) {
if (captchaType.equals("recaptcha-v2") || captchaType.equals("recaptcha-v3")) {
page.evaluate(String.format("""
document.querySelector('textarea[name="g-recaptcha-response"]').value = "%s";
try {
const clients = ___grecaptcha_cfg.clients;
for (const id in clients) {
const find = (o) => { for (const k in o) {
if (typeof o[k]==='object' && o[k]!==null) {
if (typeof o[k].callback==='function') { o[k].callback("%s"); return true; }
if (find(o[k])) return true;
}
} return false; };
find(clients[id]);
}
} catch(e) {}
""", token, token));
} else if (captchaType.equals("turnstile")) {
page.evaluate(String.format("""
document.querySelector('input[name="cf-turnstile-response"]').value = "%s";
try { const cb = document.querySelector('.cf-turnstile')?.getAttribute('data-callback');
if (cb && typeof window[cb]==='function') window[cb]("%s");
} catch(e) {}
""", token, token));
}
}
第6步:提交表单
注入令牌后,使用Vibium的语义元素查找或标准点击提交表单。
// JavaScript
page.find('Submit').click() // 语义查找
page.evaluate(`document.querySelector('#recaptcha-demo-submit')?.click()`) // CSS
# Python
page.find("Submit").click() # 语义查找
page.evaluate('document.querySelector("#recaptcha-demo-submit")?.click()') # CSS
// Java
page.find("Submit").click(); // 语义查找
page.evaluate("document.querySelector('#recaptcha-demo-submit')?.click()"); // CSS
提交后,将结果页面文本或URL视为成功信号。不需要监控reCAPTCHA的内部/userverify请求。
第7步:完整工作示例
以下是一个完整的示例,导航到reCAPTCHA v2演示页面,通过CapSolver API解决CAPTCHA,注入令牌并提交表单。
测试说明:使用专用的测试密钥进行自动化测试。使用目标页面作为烟雾测试或参考流程,而不是作为长期自动化测试套件的基础。
JavaScript:
const { browser } = require('vibium/sync')
// (包括createTask, getTaskResult, solveCaptcha从步骤4)
const bro = browser.start()
const page = bro.page()
// 1. 导航
const targetUrl = 'https://example.com/protected-page'
page.go(targetUrl)
// 2. 检测
const info = page.evaluate(`(() => {
const el = document.querySelector('.g-recaptcha');
return el ? { type: 'recaptcha-v2', siteKey: el.getAttribute('data-sitekey') }
: { type: 'none', siteKey: null };
})()`)
if (info.type === 'none') { console.log('未检测到CAPTCHA'); process.exit() }
console.log(`检测到${info.type} — 密钥${info.siteKey}`)
// 3. 解决
const token = await solveCaptcha(info, targetUrl)
console.log('已解决!')
// 4. 注入 + 提交
page.evaluate(`
document.querySelector('textarea[name="g-recaptcha-response"]').value = "${token}";
try { const c = ___grecaptcha_cfg.clients; for (const id in c) {
const f = (o) => { for (const k in o) { if (typeof o[k]==='object'&&o[k]!==null) {
if (typeof o[k].callback==='function'){o[k].callback("${token}");return true}
if(f(o[k]))return true}} return false}; f(c[id]) }} catch(e){}
`)
page.evaluate(`document.querySelector('#recaptcha-demo-form').submit()`)
// 5. 验证
setTimeout(() => {
console.log('结果:', page.evaluate('document.body.innerText'))
bro.stop()
}, 2000)
Python:
from vibium import browser
import os, time, requests
CAPSOLVER_API = "https://api.capsolver.com"
API_KEY = os.environ["CAPSOLVER_API_KEY"]
# (包括create_task, get_task_result, solve_captcha从步骤4)
def main():
bro = browser.start()
page = bro.page()
# 1. 导航
target_url = "https://example.com/protected-page"
page.go(target_url)
# 2. 检测
info = page.evaluate("""(() => {
const el = document.querySelector('.g-recaptcha');
return el ? { type: 'recaptcha-v2', siteKey: el.getAttribute('data-sitekey') }
: { type: 'none', siteKey: null };
})()""")
if info["type"] == "none":
print("未检测到CAPTCHA。")
return
print(f"检测到{info['type']} — 密钥{info['siteKey']}")
# 3. 解决
token = solve_captcha(info, target_url)
print("已解决!")
# 4. 注入 + 提交
page.evaluate(f"""
document.querySelector('textarea[name="g-recaptcha-response"]').value = "{token}";
try {{ const c = ___grecaptcha_cfg.clients; for (const id in c) {{
const f = (o) => {{ for (const k in o) {{ if (typeof o[k]==='object'&&o[k]!==null) {{
if (typeof o[k].callback==='function'){{o[k].callback("{token}");return true}}
if(f(o[k]))return true}}}} return false}}; f(c[id]) }}}} catch(e){{}}
""")
page.evaluate('document.querySelector("#recaptcha-demo-form").submit()')
# 5. 验证
time.sleep(2)
print("结果:", page.evaluate("document.body.innerText"))
bro.stop()
main()
Java:
import com.vibium.Vibium;
// (包括createTask, getTaskResult从步骤4)
var bro = Vibium.start();
var page = bro.page();
// 1. 导航
var targetUrl = "https://example.com/protected-page";
page.go(targetUrl);
// 2. 检测
var info = (Map) page.evaluate("""
(() => {
const el = document.querySelector('.g-recaptcha');
return el ? { type: 'recaptcha-v2', siteKey: el.getAttribute('data-sitekey') }
: { type: 'none', siteKey: null };
})()""");
if ("none".equals(info.get("type"))) { System.out.println("未检测到CAPTCHA"); return; }
System.out.printf("检测到%s — 密钥%s%n", info.get("type"), info.get("siteKey"));
// 3. 解决
var taskData = new JSONObject()
.put("type", "ReCaptchaV2TaskProxyLess")
.put("websiteURL", targetUrl)
.put("websiteKey", info.get("siteKey"));
var taskId = createTask(taskData);
var result = getTaskResult(taskId);
var token = result.getJSONObject("solution").getString("gRecaptchaResponse");
System.out.println("已解决!");
// 4. 注入 + 提交
page.evaluate(String.format("""
document.querySelector('textarea[name="g-recaptcha-response"]').value = "%s";
try { const c = ___grecaptcha_cfg.clients; for (const id in c) {
const f = (o) => { for (const k in o) { if (typeof o[k]==='object'&&o[k]!==null) {
if (typeof o[k].callback==='function'){o[k].callback("%s");return true}
if(f(o[k]))return true}} return false}; f(c[id]) }} catch(e){}
""", token, token));
page.evaluate("document.querySelector('#recaptcha-demo-form').submit()");
// 5. 验证
Thread.sleep(2000);
System.out.println("结果: " + page.evaluate("document.body.innerText"));
bro.stop();
支持的CAPTCHA任务类型
| CAPTCHA | CapSolver 任务类型 | 令牌字段 | 典型解决时间 |
|---|---|---|---|
| reCAPTCHA v2 | ReCaptchaV2TaskProxyLess |
textarea[name="g-recaptcha-response"] |
5-15 秒 |
| reCAPTCHA v2 (不可见) | ReCaptchaV2TaskProxyLess |
textarea[name="g-recaptcha-response"] |
5-15 秒 |
| reCAPTCHA v3 | ReCaptchaV3TaskProxyLess |
input[name="g-recaptcha-response"] |
3-10 秒 |
| reCAPTCHA 企业版 | ReCaptchaV2EnterpriseTaskProxyLess |
textarea[name="g-recaptcha-response"] |
10-20 秒 |
| Cloudflare Turnstile | AntiTurnstileTaskProxyLess |
input[name="cf-turnstile-response"] |
3-10 秒 |
| AWS WAF | AntiAwsWafTaskProxyLess |
自定义(因网站而异) | 5-15 秒 |
| GeeTest v3/v4 | GeeTestTaskProxyLess |
自定义(因网站而异) | 5-15 秒 |
故障排除
令牌在表单提交前过期
症状:表单提交但服务器拒绝CAPTCHA响应。
原因:CAPTCHA令牌有有限的生命周期(通常reCAPTCHA为90-120秒,Turnstile为300秒)。如果脚本在解决和提交之间花费太长时间,令牌将过期。
解决方法:在收到令牌后立即注入并提交。不要在步骤5和步骤7之间添加不必要的延迟。
页面未检测到CAPTCHA
症状:检测脚本返回{ type: 'none' },尽管你可以看到CAPTCHA。
可能原因:
- 页面未完全加载 — 导航后添加等待:
time.sleep(3) - CAPTCHA加载在iframe中 — 一些reCAPTCHA实现加载在iframe中。你可能需要检测iframe并从页面源或网络请求中提取站点密钥
- 动态加载 — CAPTCHA小部件可能异步加载。在检测前等待元素出现
CapSolver API返回错误
常见错误:
| 错误 | 原因 | 解决方法 |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
无效的API密钥 | 检查你的CAPSOLVER_API_KEY |
ERROR_ZERO_BALANCE |
余额不足 | 在capsolver.com充值 |
ERROR_WRONG_CAPTCHA_TYPE |
为该CAPTCHA使用了错误的任务类型 | 通过检测助手验证CAPTCHA类型 |
ERROR_CAPTCHA_UNSOLVABLE |
CAPTCHA无法解决 | 重试 — 有时会失败 |
调用CapSolver API时出现CORS问题
症状:从浏览器调用API时出现CORS错误。
原因:你正在从browser_evaluate(即浏览器上下文中)调用CapSolver API。CapSolver API不允许来自任意网站的跨域请求。
解决方法:始终从你的脚本(Node.js、Python或Java进程)调用CapSolver API,而不是从浏览器内部调用。仅在浏览器中使用browser_evaluate进行检测(读取DOM)和注入(设置表单值)。API调用必须在服务器端进行。
表单提交未触发
症状:令牌已注入,但表单未提交或服务器未接受它。
可能原因:
- 缺少回调触发 — 很多reCAPTCHA实现需要将回调函数与令牌一起调用,而不仅仅是设置文本区域的值。参见上面的
injectToken函数,它遍历___grecaptcha_cfg.clients以找到并调用回调 - 自定义表单验证 — 网站可能有额外的JavaScript验证。在开发者工具中检查表单的提交处理程序
- 令牌格式不匹配 — 确保从CapSolver结果中使用
gRecaptchaResponse用于reCAPTCHA和token用于Turnstile
最佳实践
1. 以合理间隔轮询
每2秒轮询/getTaskResult。更频繁的轮询会浪费API调用并可能触发速率限制。更少的轮询会增加不必要的延迟。
// JavaScript: 良好 — 2秒间隔
await new Promise(r => setTimeout(r, 2000))
# Python: 良好 — 2秒间隔
time.sleep(2)
// Java: 良好 — 2秒间隔
Thread.sleep(2000);
2. 实现带指数退避的重试逻辑
CAPTCHA解决偶尔会失败。将你的解决函数包装在重试中:
JavaScript:
async function solveWithRetry(info, url, retries = 3) {
for (let i = 0; i < retries; i++) {
try { return await solveCaptcha(info, url) }
catch (e) {
if (i === retries - 1) throw e
await new Promise(r => setTimeout(r, 2 ** i * 1000))
}
}
}
Python:
def solve_with_retry(info, url, retries=3):
for i in range(retries):
try: return solve_captcha(info, url)
except Exception:
if i == retries - 1: raise
time.sleep(2 ** i)
3. 为每个CAPTCHA使用正确的任务类型
使用错误的任务类型会导致解决失败。首先检测CAPTCHA类型,然后映射到正确的CapSolver任务:
| CAPTCHA | 任务类型 |
|---|---|
| reCAPTCHA v2 (复选框) | ReCaptchaV2TaskProxyLess |
| reCAPTCHA v2 (不可见) | ReCaptchaV2TaskProxyLess |
| reCAPTCHA v3 | ReCaptchaV3TaskProxyLess |
| reCAPTCHA v2 企业版 | ReCaptchaV2EnterpriseTaskProxyLess |
| reCAPTCHA v3 企业版 | ReCaptchaV3EnterpriseTaskProxyLess |
| Cloudflare Turnstile | AntiTurnstileTaskProxyLess |
| AWS WAF | AntiAwsWafTaskProxyLess |
4. 立即注入并提交
CAPTCHA令牌会过期。一旦从CapSolver收到令牌,立即注入并提交表单。不要在解决和提交之间添加人工延迟。
5. 在长跑前检查余额
JavaScript:
const res = await fetch(`${CAPSOLVER_API}/getBalance`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientKey: API_KEY }),
})
const { balance } = await res.json()
if (balance < 1) console.warn('低 CapSolver 余额!')
Python:
balance = requests.post(f"{CAPSOLVER_API}/getBalance",
json={"clientKey": API_KEY}).json().get("balance", 0)
if balance < 1:
print("低 CapSolver 余额!")
6. 将 API 调用保持在服务器端
永远不要在 browser_evaluate 中调用 CapSolver API。浏览器上下文的 HTTP 请求会因 CORS 而失败,并且在浏览器 JavaScript 中暴露你的 API 密钥存在安全风险。始终从你的应用程序进程(Node.js、Python 或 Java)中进行 API 调用。
结论
Vibium + CapSolver API 集成表明,你不需要浏览器扩展即可在自动化流程中解决验证码。当工具如 Vibium 限制 Chrome 标志时,API 方法为你提供了更多控制,而非更少:
- 通过
browser_evaluate检测验证码类型和站点密钥 - 通过从你的脚本调用 CapSolver REST API 解决问题
- 通过
browser_evaluate将令牌注入页面 - 提交表单
此模式适用于任何支持 JavaScript 评估的浏览器自动化工具——不仅仅是 Vibium。无论你使用 WebDriver BiDi、CDP 或任何其他协议,CapSolver API 方法都是通用的。
通过将 Vibium 的基于标准的浏览器自动化与 CapSolver 快速可靠的验证码解决 API 相结合,你可以获得一个强大的流程,可以处理 reCAPTCHA、Turnstile、AWS WAF 等——而无需使用任何浏览器扩展。
准备好了吗? 注册 CapSolver 并使用优惠码 VIBIUM 在首次充值时获得额外 6% 的奖励!
FAQ
为什么我不能在 Vibium 中使用 CapSolver Chrome 扩展?
Vibium 的 Go 启动器在启动 Chrome 时硬编码了 --disable-extensions。没有配置选项或标志覆盖来更改此行为。像 Playwright 和 OpenClaw 这样的工具使用的扩展方法在 Vibium 中不起作用。API 方法是正确的集成方式。
什么是 API 方法?
而不是依赖浏览器扩展来自动检测和解决验证码,你可以直接从你的脚本调用 CapSolver REST API。通过 JavaScript 评估在页面上检测验证码,将站点密钥和 URL 发送到 CapSolver 的 createTask 端点,轮询 getTaskResult 直到解决方案就绪,然后将令牌注入页面。
CapSolver 支持哪些验证码类型?
CapSolver 支持 reCAPTCHA v2(复选框和不可见)、reCAPTCHA v3、reCAPTCHA 企业版、Cloudflare Turnstile、AWS WAF 验证码、GeeTest、DataDome 等。请参阅完整列表。
CapSolver 的费用是多少?
CapSolver 提供基于验证码类型和数量的具有竞争力的定价。访问 capsolver.com 查看当前定价。使用优惠码 VIBIUM 在首次充值时获得额外 6% 的奖励。
Vibium 是免费的吗?
Vibium 是开源且免费的。你可以从 GitHub 下载 Go 二进制文件。对于验证码解决,你需要一个具有积分的 CapSolver 账户。
我可以将此方法与其他 BiDi 工具一起使用吗?
可以。API 方法适用于任何支持 JavaScript 评估的浏览器自动化工具,无论其使用 WebDriver BiDi、CDP 还是其他协议。唯一的要求是在页面上运行 JavaScript 以检测验证码并注入已解决的令牌。
解决验证码需要多长时间?
典型的解决时间取决于验证码类型:reCAPTCHA v2 需要 5-15 秒,reCAPTCHA v3 需要 3-10 秒,Cloudflare Turnstile 需要 3-10 秒。你的总墙时间包括轮询间隔(每次轮询 2 秒)。
验证码令牌会过期吗?
是的。reCAPTCHA 令牌通常在 90-120 秒后过期。Turnstile 令牌最多持续 300 秒。一旦收到令牌,应立即注入并提交。
提交表单后是否需要监控 /userverify?
不需要。将 /userverify 视为 reCAPTCHA 的内部网络流量,而不是主要的成功信号。提交后,检查可见的结果页面、确认文本或目标 URL。
我可以在自动化测试中使用公共演示页面吗?
仅用作烟雾测试。为自动化测试流程创建专用的测试密钥,而不是依赖任何公共演示页面。
如何找到验证码站点密钥?
站点密钥嵌入在页面 HTML 中。对于 reCAPTCHA,查找 .g-recaptcha 元素上的 data-sitekey 属性。对于 Turnstile,检查 .cf-turnstile 上的 data-sitekey 属性。本指南中的检测辅助函数会自动提取它。
我可以将此方法与 Vibium 的 MCP 服务器一起使用吗?
可以。当通过 Vibium 的 MCP 服务器使用 Vibium 时,代理可以调用 CapSolver API 作为工具,然后使用 browser_evaluate 注入令牌。无论由脚本还是 AI 代理驱动,流程都是相同的——检测、解决、注入、提交。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)