GoでreCAPTCHA Enterpriseを解く
solvethree.com/sdk をインストールし、対象のホスト名、アクション、プロキシを指定して Solve を呼び出します。SDK はタスクを 1 回作成し、結果をポーリングします。その後、アプリケーションから対象にトークンを送信します。
このページの内容
SDK のインストールと設定
Go 1.22+ を使用してください。Go モジュール内で次を実行します。
go get solvethree.com/sdk@v0.1.0SOLVETHREE_API_KEYにワークスペースの API キーを、SOLVETHREE_PROXYに HTTP(S) プロキシ URL を設定してください。どちらもサーバー設定で管理します。- ワークスペースで、対象ホスト名に対応する有効なプロファイルを作成してください。サイトプロファイルの設定を参照してください。
accounts.example.comとloginを、対象が使用するホスト名とアクションに置き換えてください。Siteには、スキームやパスを含めずにホスト名を指定します。
タスクを 1 件解決する
これを main.go として保存し、go run . を実行してください。
package main
import (
"context"
"fmt"
"log"
"os"
"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)
// Submit result.Solution.Token with its browser identity and original proxy.
}コンテキストはローカルでの待機時間を 180 秒に制限します。Solve は準備完了の TaskResult またはエラーを返すため、その外側に別のポーリングループを設ける必要はありません。このリクエストはデフォルトの Enterprise v3 モードを使用します。通常の v3 を使用するには、RecaptchaType: "v3" を設定してください。reCAPTCHA では Type と URL を設定しないでください。
対象にトークンを送信する
アプリケーションの CAPTCHA フィールドで result.Solution.Token を送信してください。出力される result.ID はタスクを識別するもので、トークンではありません。
result.Solution.UserAgent を User-Agent として、result.Solution.SecChUA を sec-ch-ua として使用してください。対象へのリクエストは、solvethree.SuccessfulProxy(input, result) で選択した、解決に成功したプロキシ経由で送信します。
アプリケーションの他のフォームフィールド、Cookie、CSRF 値も含めてから、レスポンスを確認してください。SDK は解決結果を返しますが、アプリケーションへのリクエストを代わりに送信することはありません。
待機が中断された場合に備えて ID を保存する
コンテキストをキャンセルすると、ローカルでの待機は停止しますが、リモートでの処理は停止しません。*solvethree.Error からは RequestID と TaskID を取得できます。既知のタスクは GetTask で取得してください。作成されたかどうか不明な場合は、同じ RequestID で元の入力を正確に再送信します。
プロセスの再起動後に復旧できるようにするには、作成前に RequestID を割り当て、タスク入力とともに保存してください。*TaskFailedError は終端エラーです。ErrorCode を確認し、タスクを取得してエラーの説明を確認してください。別の解決処理を開始する前に原因を修正します。
別の方法:標準ライブラリで REST を呼び出す
HTTP 呼び出しを自分で管理したい場合、このバージョンでは net/http を直接使用します。この例か上記の SDK の例のどちらかを選んでください。両方を実行すると 2 件のタスクが作成されます。ここでのレスポンス構造体は、この独立した例専用のため、フィールド名が SDK の型とは異なります。
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
type Task struct {
ID string `json:"id"`
Status string `json:"status"`
ErrorCode string `json:"errorCode"`
Error string `json:"error"`
Solution struct {
Token string `json:"token"`
UserAgent string `json:"userAgent"`
SecChUa string `json:"secChUa"`
} `json:"solution"`
}
func main() {
key, proxy := os.Getenv("SOLVETHREE_API_KEY"), os.Getenv("SOLVETHREE_PROXY")
if key == "" || proxy == "" { panic("Set SOLVETHREE_API_KEY and SOLVETHREE_PROXY") }
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
client := &http.Client{Timeout: 30*time.Second}
api := func(method, path string, body []byte) (Task, error) {
var task Task
req, err := http.NewRequestWithContext(ctx, method, "https://api.solvethree.com/v1"+path, bytes.NewReader(body))
if err != nil { return task, err }
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
response, err := client.Do(req)
if err != nil { return task, err }
defer response.Body.Close()
if response.StatusCode < 200 || response.StatusCode >= 300 { return task, fmt.Errorf("API HTTP %d", response.StatusCode) }
err = json.NewDecoder(response.Body).Decode(&task)
return task, err
}
requestID := fmt.Sprintf("go-%d", time.Now().UnixNano())
body, err := json.Marshal(map[string]string{
"site":"accounts.example.com", "action":"login", "proxy":proxy, "requestId":requestID,
})
if err != nil { panic(err) }
// Persist requestID and body before creation if this must survive a restart.
task, err := api(http.MethodPost, "/tasks?waitMs=0", body)
if err != nil { panic(fmt.Errorf("request %s: %w", requestID, err)) }
for task.Status == "pending" || task.Status == "solving" {
task, err = api(http.MethodGet, "/tasks/"+url.PathEscape(task.ID)+"?waitMs=15000", nil)
if err != nil { panic(err) }
if task.Status == "pending" || task.Status == "solving" {
select { case <-ctx.Done(): panic(ctx.Err()); case <-time.After(time.Second): }
}
}
if task.Status != "ready" { panic("Task failed: "+task.ErrorCode+": "+task.Error) }
solution := task.Solution
_ = solution // Apply token and returned browser identity using the same proxy.
fmt.Println("Ready task:", task.ID)
}参照元とAPIリファレンス
最初のタスクを実行しましょう。
$5のワークスペースクレジットで始められます。