
Lucas Mitchell
Automation Engineer
已发表 Nov 02, 2026
已更新 Nov 02, 2026 · 最小阅读量

ErrorId;Go 错误为 nil 并不代表服务调用成功。chromedp 是一个基于 Go 的库,通过 Chrome DevTools Protocol 控制浏览器。开发者可以利用它做浏览器测试和自动化,而无需引入 Python 或 JavaScript 控制器。当被授权的浏览器任务遇到支持的 CAPTCHA 时,Go 应用可以调用求解服务,并继续操控同一页面。
CapSolver 提供了官方 Go SDK 和文档化的任务 API 用于求解步骤。本文将这两部分串联起来,但不会把浏览器库伪装成求解器。可运行检查使用本地自有浏览器 fixture 和一个带有刻意无效占位 key 的真实 API 请求。它验证的是线路和错误处理,而不是付费求解。
CAPTCHA 求解位于收集当前挑战参数和继续需要该结果的浏览器操作之间。
chromedp 官方仓库 提供浏览器控制能力。你的 Go 程序会打开被允许的页面,读取相关状态,并在需要处理受支持的挑战时做出判断。求解服务提供文档规定的输出;chromedp 仍然负责随后的页面操作。
CAPTCHA 本身并不能证明每一次浏览器阻塞都需要发起求解请求。缺失字段、导航失败或应用错误可能需要其它修复。应先识别真正的挑战,再选择任务类型。
对于自有 QA 表单,流程相对简单:打开表单,识别其 CAPTCHA 配置,在合适的时机请求解题,通过应用期望的集成路径提交结果,并检查表单确认信息。本文不会为任意网站提供通用回调或通用提交流脚本。
使用隔离的 Go 模块并固定依赖版本,以便文中的 API 调用与实际构建保持一致。
本文检查的环境使用 Go 1.27.3、github.com/chromedp/chromedp@v0.21.0 和 github.com/capsolver/capsolver-go@v0.0.0-20251204081438-e4e07af23eae。Chrome 安装在本地,并通过单独的临时浏览器上下文启动。
创建工作目录,用 go mod init captcha-browser-check 初始化模块,然后运行:
go get github.com/chromedp/chromedp@v0.21.0 github.com/capsolver/capsolver-go@v0.0.0-20251204081438-e4e07af23eae
v0.21.0 版本说明 指出支持 Go 1.25 及之后的版本。在迁移旧浏览器脚本时,请使用该版本的文档。把旧的指针输出示例和新的强类型 action API 混合使用,可能会在任何浏览器或求解请求运行之前就触发编译错误。
官方余额 API 文档 包含 Go SDK 的 Balance() 方法。余额查询有助于把账号/API 访问与特定挑战求解区分开。它不会创建 CAPTCHA 任务。
运行一个小检查,以证明 Chrome 可以读取自有页面,并且 Go SDK 能收到真实的 API 响应。
将以下代码保存为 main.go,然后在初始化好的模块中运行 go run .。本地 FIXTURE_ONLY 属性是测试数据,而不是真实的 sitekey。API key 故意无效,程序预期服务会拒绝它。
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"time"
"github.com/chromedp/chromedp"
capsolver "github.com/capsolver/capsolver-go"
)
func main() {
// 本地 fixture 用于检查浏览器线路,它不是真实 CAPTCHA。
fixture := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `<title>Owned QA fixture</title><div id="widget" data-sitekey="FIXTURE_ONLY"></div>`)
}))
defer fixture.Close()
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ctx, deadline := context.WithTimeout(ctx, 30*time.Second)
defer deadline()
if err := chromedp.Do(ctx, chromedp.Navigate(fixture.URL)); err != nil { log.Fatal(err) }
sitekey, err := chromedp.Run(ctx, chromedp.AttributeValue("#widget", "data-sitekey"))
if err != nil { log.Fatal(err) }
if !sitekey.Exists || sitekey.Value != "FIXTURE_ONLY" { log.Fatal("Fixture key not found") }; fmt.Println("Fixture key:", sitekey.Value)
// 故意使用无效凭证:检查真实 API 错误,而不是账号。
solver := capsolver.CapSolver{ApiKey: "YOUR_API_KEY"}
result, err := solver.Balance()
if err != nil { log.Fatal(err) }
fmt.Println("API error:", result.ErrorId, result.ErrorCode)
if result.ErrorId == 0 { log.Fatal("Expected the placeholder credential to be rejected") }
}
验证运行时会先打印 Fixture key: FIXTURE_ONLY,然后打印 ErrorId 为 1 且错误码为 ERROR_KEY_DOES_NOT_EXIST 的 API 错误。应把该特定错误视作对这个占位检查的观测结果,而不是对任意无效凭证的结果承诺。
这样就建立了本地浏览器访问能力和 API 的真实请求-响应路径。没有查询真实账号、没有解任何挑战,也没有执行任何表单提交。
当前的 AttributeValue 动作返回一个 AttributeResult,其中包含属性值和存在标记。
示例会在继续之前检查这两个字段。缺失的属性应阻止参数收集,而不是在付费请求中变成空的 sitekey。适用于本地 fixture 的选择器不应被视为适用于所有 CAPTCHA 集成的通用选择器。
当前检查过的 SDK 可以在不返回 Go 错误的情况下,返回一个已解析的服务响应。
这就是示例在处理完 err 之后还要检查 result.ErrorId 的原因。网络失败、JSON 解析失败,以及描述账号错误的有效响应属于不同情况。应阅读返回的完整响应,而不是假设 err == nil 就表示账号或任务成功。
兑换你的 CapSolver 奖励码
即时提升你的自动化预算!
在为 CapSolver 账号充值时使用奖励码 CAP26,每笔充值都可额外获得 5% 奖励 —— 无上限。
立刻在你的 CapSolver 控制台 中兑换。
基于你实际检查到的页面,利用选定 CAPTCHA 的当前任务文档构造求解请求。
对于 reCAPTCHA v2,官方任务文档 说明了任务家族以及 websiteURL、websiteKey 等字段。使用文档中规定的拼写和大小写。不要凭记忆构造任务名,也不要在未经检查当前约定的前提下复制旧 SDK 示例。
官方 Go SDK 为任务 map 暴露了 Solve() 方法。生产实现应以安全方式提供真实凭证,传入当前任务参数,并根据固定的 SDK 版本检查返回的结果或错误。
上面的连接检查刻意不是完整的付费求解程序。在部署求解步骤前,应使用你自己有资金的账号,对一个被允许的挑战做一次测试,并在自有应用中验证结果。由于本文没有执行该与凭证相关的步骤,因此不声明任何成功率或端到端完成度。
保持页面 URL、挑战类型、公钥以及必需的可选参数与同一个浏览器操作关联。如果导航替换了页面或重新生成了挑战,在发起下一次尝试前应重新检查输入。
以自有应用期望的方式使用解题结果,然后确认应用行为按预期发生变化。
基于 token 的结果并不是让你“点击任何可见验证按钮”的指令。有些应用通过回调处理,有些会把结果绑定到表单上,最后的服务端验证仍然很重要。应查阅应用自身的实现,而不是猜测一个 JavaScript 回调名称。
Google 的 响应验证文档 解释了 reCAPTCHA 的服务器端验证步骤。浏览器自动化在求解后继续执行某一行代码,并不等于服务器已经接受了该响应。
保持测试的成功条件足够具体。对于自有表单,应检查其确认或测试记录;对于被允许的读取流程,应检查预期内容。避免只把 widget 消失视作唯一完成信号,而忽略应用本身更可靠的结果。
先诊断出失败组件,再重新跑导航、账号检查和求解。
编译错误指向代码和依赖兼容性问题。浏览器启动失败指向可执行文件或运行环境。缺失 key 指向页面检查。服务错误指向文档化 API 响应。解题后表单仍被拒绝则指向结果应用方式和应用自身。
对于输入契约相关的失败,invalid-task-data 故障排查指南 展示了如何将实际请求与选定任务进行对比。更多的浏览器重试并不能修正请求中拼写错误的字段。
保留一个小型诊断记录,其中包含包版本、失败阶段、可用时的任务 ID,以及经脱敏的错误信息。不要记录真实账号 key 或完整解题 token。在向上汇报时,应分别说明浏览器检查和 API 检查各自已经证明了什么。
让 chromedp 负责浏览器控制,并仅在真正出现 CAPTCHA 步骤时调用有文档的求解接口。CapSolver 提供求解接口;你的应用则负责页面状态、错误决策以及最终完成检查。
问:chromedp 自带 CAPTCHA 求解能力吗?
chromedp 是浏览器控制器。本文工作流是在被允许的任务中遇到受支持挑战时,额外接入独立求解服务。
问:示例会消耗求解额度吗?
不会创建任何付费任务。示例只会使用一个刻意无效的占位 key 发送余额请求,并检查返回错误。
问:为什么 API 会在 Go 错误为 nil 时仍然拒绝请求?
因为 SDK 可能已经成功接收并解析了一个包含服务级错误的响应。应同时检查响应中的错误字段和 Go 错误。
问:我可以把 FIXTURE_ONLY 当作我的 sitekey 吗?
不可以。它只是用于验证浏览器属性读取的本地测试数据。真实求解任务需要来自被允许页面的当前公钥。
问:本文有没有测试完整的付费 CAPTCHA 求解流程?
没有。已验证的范围仅包括 chromedp 浏览器 fixture 和一次真实的 API 拒绝。付费求解及其在自有应用中的接受情况,需要你的账号和单独的端到端测试。

Lucas Mitchell
Automation Engineer
Helping browser automation recover and continue.
关于作者