通过 Go HTTP 代理提交 CAPTCHA 令牌

作者:solvethree阅读需 1 分钟

为目标网站使用独立的 Go HTTP 客户端,并配置为使用 solvethree.SuccessfulProxy 选出的代理。使用返回的浏览器身份信息提交 Solution.Token。将此目标传输层与 SDK 客户端的 solvethree API 传输层分开。

本页内容

准备任务

  1. 1.

    设置 Go SDK 和凭据

    使用版本为 v0.1.0 的官方 solvethree.com/sdk 模块,以及 Go 1.22 或更高版本。设置详情请参阅 Go 集成参考文档。将 SOLVETHREE_API_KEY 设为工作区 API 密钥,并将其保留在服务器端。将 SOLVETHREE_PROXY 设为 HTTP 或 HTTPS 代理 URL。

  2. 2.

    求解前配置站点

    工作区中需要有目标主机名的有效配置。请先设置站点配置;提交主机名和操作不会创建配置。

  3. 3.

    替换示例目标

    更改 accounts.example.com、login 操作和应用端点,使其符合你的集成。Site 是主机名,而不是完整 URL。对于 reCAPTCHA,必须且只能提供 Proxy 或 ProxyCandidates 其中之一;不要填写任务的 Type 或 URL 字段。默认的 reCAPTCHA 类型为 Enterprise v3。

通过成功求解任务的代理提交

Go · 通过成功的代理提交
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "net/http"
    "net/url"
    "strings"
    "time"
    solvethree "solvethree.com/sdk"
)

func main() {
    client, err := solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"), nil)
    if err != nil { log.Fatal(err) }
    ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
    defer cancel()
    input := solvethree.TaskRequest{Site: "accounts.example.com", Action: "login", Proxy: os.Getenv("SOLVETHREE_PROXY")}
    result, err := client.Solve(ctx, input, solvethree.SolveOptions{})
    if err != nil { log.Fatal(err) }
    fmt.Println("Ready task:", result.ID)

    proxy, ok := solvethree.SuccessfulProxy(input, result)
    if !ok { log.Fatal("No valid successful proxy") }
    proxyURL, err := url.Parse(proxy)
    if err != nil { log.Fatal(err) }
    transport := http.DefaultTransport.(*http.Transport).Clone()
    transport.Proxy = http.ProxyURL(proxyURL)
    defer transport.CloseIdleConnections()
    targetClient := &http.Client{Transport: transport, Timeout: 30*time.Second,
        CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
    request, err := http.NewRequestWithContext(ctx, "POST", "https://accounts.example.com/login",
        strings.NewReader(url.Values{"g-recaptcha-response": {result.Solution.Token}}.Encode()))
    if err != nil { log.Fatal(err) }

    request.Header.Set("User-Agent", result.Solution.UserAgent)
    request.Header.Set("sec-ch-ua", result.Solution.SecChUA)
    request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

    response, err := targetClient.Do(request)
    if err != nil { log.Fatal(err) }
    defer response.Body.Close()
    fmt.Println("Application HTTP status:", response.StatusCode)
    // Inspect the application response to determine whether submission succeeded.

}

SDK 会求解任务,但不会向网站提交任何内容。求解后,示例会克隆 http.DefaultTransport,并通过 http.ProxyURL 设置克隆对象的 Proxy。只有独立的 targetClient 使用该传输层;SDK 客户端的 API 传输层保持不变。

将代理凭据保留在 URL 的用户信息部分。url.Parse 会为代理传输层保留这些凭据。请对用户名或密码中的保留字符进行百分号编码,不要手动拆分 URL,也不要通过发往目标站点的 Authorization 请求头发送代理凭据。

保留原始任务输入,即使目前只提供一个代理,也应使用 SuccessfulProxy。使用 ProxyCandidates 时,Solution.EgressAttempts 标识成功的候选代理,它是原始列表中从 1 开始的索引。此辅助函数可避免猜测哪个候选代理成功;如果它返回 false,请停止。候选列表最多接受十二个不同的 HTTP 或 HTTPS 代理 URL,且不得包含路径、查询参数或片段。

包含目标站点的请求头、表单字段和会话

此示例使用 url.Values,将 Solution.Token 以 g-recaptcha-response 为字段名进行表单编码,并设置匹配的内容类型。如果应用期望其他字段名,请替换该名称。添加端点要求的其他字段,例如登录输入和任何与会话绑定的防 CSRF 值;CAPTCHA 令牌并不是完整的登录请求。

像示例一样,使用返回的 UserAgent 和 SecChUA。如果解决结果还在 Headers 中提供了条目,也应将这些返回的请求头应用于目标请求——示例并未复制该集合。保持浏览器身份一致,并确保内容类型与发送的请求体相符。

此示例没有 Cookie 容器。如果目标站点需要会话,请使用 net/http/cookiejar 创建容器,在启动目标站点流程之前将其附加到 targetClient.Jar,并在页面请求和表单提交中复用该客户端。整个会话期间使用同一个成功的代理。solvethree API 客户端不是目标站点的会话客户端。

读取解决结果前,先检查求解错误。只有就绪任务才有可用的解决结果;失败任务的 errorCode 和 error 会说明失败原因。对于目标请求,先处理 Do 返回的错误,再检查 HTTP 状态,最后解析响应体。只要 Do 返回了响应且没有错误,就必须关闭 response.Body,包括 HTTP 状态表示不成功的响应。

该示例禁用自动重定向,并打印应用状态。请检查响应体和任何预期的重定向,以判断应用是否接受了提交。任务就绪或仅有成功的 HTTP 状态,都不能证明提交已被接受。

运行您的第一个任务。

使用 $5 工作区额度开始体验。

创建工作区
通过 Go HTTP 代理提交 CAPTCHA 令牌 · solvethree