Решение reCAPTCHA Enterprise с Go
Установите solvethree.com/sdk и вызовите Solve, указав целевое имя хоста, действие и прокси. SDK создаёт задачу один раз и опрашивает её до получения результата. Затем ваше приложение отправляет токен целевому приложению.
На этой странице
Установите и настройте SDK
Используйте Go 1.22+. В своём модуле Go выполните:
go get solvethree.com/sdk@v0.1.0- Задайте для
SOLVETHREE_API_KEYAPI-ключ вашего рабочего пространства, а дляSOLVETHREE_PROXY— URL вашего HTTP(S)-прокси. Храните оба значения в конфигурации сервера. - Создайте в своём рабочем пространстве активный профиль для целевого имени хоста. См. настройку профиля сайта.
- Замените
accounts.example.comиloginна имя хоста и действие, используемые целевым приложением. ПолеSiteпринимает имя хоста без схемы и пути.
Решите одну задачу
Сохраните этот код в файл 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 незаданными.
Отправьте токен целевому приложению
Передайте result.Solution.Token в поле CAPTCHA приложения. Выводимое значение result.ID идентифицирует задачу; это не токен.
Используйте result.Solution.UserAgent в качестве User-Agent, а result.Solution.SecChUA — в качестве sec-ch-ua. Направьте запрос к целевому приложению через прокси, на котором решение было успешно получено, выбрав его с помощью solvethree.SuccessfulProxy(input, result).
Добавьте остальные поля формы приложения, файлы cookie и значение CSRF, затем проверьте его ответ. SDK возвращает решение; он не отправляет запрос к приложению за вас.
Сохраните идентификаторы на случай прерывания ожидания
Отмена контекста останавливает локальное ожидание, но не удалённую работу. *solvethree.Error предоставляет RequestID и TaskID. Получите известную задачу через GetTask; если неизвестно, была ли она создана, повторно отправьте в точности исходные данные с тем же RequestID.
Для восстановления после перезапуска процесса задайте и сохраните RequestID вместе с входными данными задачи до её создания. Ошибка *TaskFailedError означает окончательный неудачный результат: проверьте её ErrorCode и получите задачу, чтобы прочитать текст ошибки. Устраните причину, прежде чем запускать новое решение.
Альтернатива: вызов REST API через стандартную библиотеку
Если вы предпочитаете самостоятельно управлять HTTP-вызовами, этот вариант использует net/http напрямую. Выберите либо его, либо пример с SDK выше; запуск обоих создаст две задачи. Структуры ответов здесь относятся к этому отдельному примеру, поэтому имена их полей отличаются от типов 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 на балансе рабочего пространства.