Resuelve reCAPTCHA Enterprise con Go
Instala solvethree.com/sdk y llama a Solve con el nombre de host de destino, la acción y el proxy. El SDK crea la tarea una sola vez y consulta el resultado periódicamente. Después, tu aplicación envía el token al destino.
En esta página
Instala y configura el SDK
Usa Go 1.22+. En tu módulo de Go, ejecuta:
go get solvethree.com/sdk@v0.1.0- Establece
SOLVETHREE_API_KEYcon la clave de API de tu espacio de trabajo ySOLVETHREE_PROXYcon la URL de tu proxy HTTP(S). Mantén ambos en la configuración del servidor. - Crea un perfil activo para el nombre de host de destino en tu espacio de trabajo. Consulta la configuración de perfiles de sitio.
- Sustituye
accounts.example.comyloginpor el nombre de host y la acción que utiliza tu destino.Siteacepta un nombre de host, sin esquema ni ruta.
Resuelve una tarea
Guarda esto como main.go y ejecuta 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.
}El contexto limita la espera local a 180 segundos. Solve devuelve un TaskResult listo o un error; no necesitas añadir otro bucle de consultas periódicas. Esta solicitud usa el modo Enterprise v3 predeterminado. Para v3 estándar, establece RecaptchaType: "v3". Deja Type y URL sin establecer para reCAPTCHA.
Envía el token a tu destino
Envía result.Solution.Token en el campo CAPTCHA de la aplicación. El valor impreso de result.ID identifica la tarea; no es el token.
Usa result.Solution.UserAgent como User-Agent y result.Solution.SecChUA como sec-ch-ua. Envía la solicitud de destino a través del proxy que funcionó en la resolución, seleccionado con solvethree.SuccessfulProxy(input, result).
Incluye los demás campos del formulario, las cookies y el valor CSRF de la aplicación y, después, comprueba su respuesta. El SDK devuelve una solución; no envía la solicitud a la aplicación por ti.
Conserva los ID si se interrumpe la espera
Cancelar el contexto detiene la espera local, no el trabajo remoto. *solvethree.Error expone RequestID y TaskID. Recupera una tarea conocida con GetTask; si no sabes si se creó, vuelve a enviar exactamente los datos de entrada originales con el mismo RequestID.
Para poder recuperar la tarea tras reiniciar el proceso, asigna y guarda RequestID junto con los datos de entrada antes de crearla. Un *TaskFailedError es definitivo: examina su ErrorCode y recupera la tarea para obtener el texto del error. Corrige la causa antes de iniciar otra resolución.
Alternativa: llama a REST con la biblioteca estándar
Si prefieres gestionar las llamadas HTTP, esta versión usa net/http directamente. Elige esta opción o el ejemplo del SDK anterior; ejecutar ambos crea dos tareas. Las estructuras de respuesta de este ejemplo independiente son propias, por lo que sus nombres de campo difieren de los de los tipos del 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)
}Fuentes y referencia de la API
Ejecuta tu primera tarea.
Empieza con $5 de crédito en tu espacio de trabajo.