Utiliser le SDK Go avec chromedp
Effectuez d’abord la résolution, puis lancez Chrome avec le même proxy et l’identité de navigateur renvoyée. Insérez le jeton dans le formulaire de l’application, envoyez-le et attendez le résultat de l’application. Une tâche prête signifie que vous disposez d’une solution, pas que le site web l’a acceptée.
Sur cette page
Configurer les modules, le profil et le proxy
Installez solvethree.com/[email protected] et github.com/chromedp/[email protected] avec go get. Le SDK nécessite Go 1.22+, mais cette version de chromedp nécessite Go 1.25+ : utilisez donc cette version pour l’exemple combiné. Son API typée diffère de celle des anciens exemples chromedp.
Créez un profil de site actif pour le nom d’hôte cible dans votre espace de travail avant d’exécuter le programme. L’envoi d’un nom d’hôte et d’une action ne crée pas de profil.
TARGET_URL: l’URL HTTPS complète de la page contenant votre formulaire. La tâche utilise son nom d’hôte commeSite; Chrome accède à l’URL complète.SOLVETHREE_PROXY: une seule URL de proxy HTTP ou HTTPS. Cet exemple nécessite un proxy autorisé par liste d’adresses IP, sans identifiants dans l’URL.SOLVETHREE_API_KEY: la clé API de votre espace de travail. Conservez-la dans le processus Go, et non dans le JavaScript de la page.
L’exemple demande l’action login et utilise le mode reCAPTCHA Enterprise v3 par défaut. Remplacez l’action par la valeur attendue par votre application.
Résoudre, lancer Chrome et envoyer
Le programme attend la résolution du SDK avant de créer l’allocateur de Chrome. Il configure Chrome avec le même proxy unique et result.Solution.UserAgent, puis définit le SecChUA renvoyé comme en-tête sec-ch-ua avant la navigation. Ne substituez pas une identité de navigateur sans rapport et ne changez pas de proxy entre la résolution et l’envoi.
// go get github.com/chromedp/[email protected] (requires Go 1.25+)
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"time"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
solvethree "solvethree.com/sdk"
)
func main() { if err := run(); err != nil { log.Fatal(err) } }
func run() error {
target,err:=url.Parse(os.Getenv("TARGET_URL"));if err!=nil||target.Scheme!="https"||target.Hostname()=="" { return fmt.Errorf("set an HTTPS TARGET_URL") }
proxy,err:=url.Parse(os.Getenv("SOLVETHREE_PROXY"));if err!=nil||proxy.User!=nil { return fmt.Errorf("use an IP-allowlisted proxy without URL credentials") }
client,err:=solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"),nil);if err!=nil { return err }
ctx,cancel:=context.WithTimeout(context.Background(),180*time.Second);defer cancel()
result,err:=client.Solve(ctx,solvethree.TaskRequest{Site:target.Hostname(),Action:"login",Proxy:proxy.String()},solvethree.SolveOptions{})
if err!=nil { return err }
options:=append(chromedp.DefaultExecAllocatorOptions[:],chromedp.ProxyServer(proxy.String()),chromedp.UserAgent(result.Solution.UserAgent))
allocator,closeAllocator:=chromedp.NewExecAllocator(context.Background(),options...);defer closeAllocator()
browser,closeBrowser:=chromedp.NewContext(allocator);defer closeBrowser()
browser,stop:=context.WithTimeout(browser,60*time.Second);defer stop()
tokenJSON,err:=json.Marshal(result.Solution.Token);if err!=nil { return err }
script:=`(token => {const field=document.querySelector('[name="g-recaptcha-response"]'); field.value=token; field.dispatchEvent(new Event('input',{bubbles:true}));})(`+string(tokenJSON)+`)`
_,err=chromedp.Call(browser,network.SetExtraHTTPHeaders,network.SetExtraHTTPHeadersParams{Headers:network.Headers{"sec-ch-ua":result.Solution.SecChUA}})
if err!=nil { return err }
err=chromedp.Do(browser,
chromedp.Navigate(target.String()),chromedp.WaitReady(chromedp.CSS(`[name="g-recaptcha-response"]`)),
chromedp.Evaluate[chromedp.Void](script),chromedp.Click(chromedp.CSS(`button[type="submit"]`)),
chromedp.WaitVisible(chromedp.ID("success")))
if err!=nil { return err }
// #success is this owned demo form's outcome. Adapt its selectors, token
// parameter and success check to your application, including CSRF/session fields.
return nil
}Cet exemple utilise délibérément un seul proxy : aucun choix entre candidats n’est donc nécessaire. Si vous utilisez ensuite ProxyCandidates, obtenez le proxy ayant réussi avec SuccessfulProxy(originalTask, readyResult) et utilisez ce proxy pour Chrome.
Adapter les hypothèses du formulaire de démonstration
L’insertion du jeton utilise json.Marshal avant de construire l’expression JavaScript. Conservez cette étape d’échappement : elle transmet le jeton comme valeur de chaîne JavaScript au lieu d’interpoler du texte non échappé dans du code exécutable.
- Remplacez
[name="g-recaptcha-response"]par le champ réellement envoyé par votre application. L’exemple définit sa valeur et déclenche un événement input ; adaptez ce comportement si votre application nécessite une autre méthode d’envoi. - Remplacez
button[type="submit"]par le contrôle d’envoi voulu. Renseignez les valeurs de formulaire, les champs CSRF et l’état de session nécessaires avant de cliquer. - Remplacez
#successpar un résultat qui indique réellement l’acceptation dans votre application. Un clic effectué ou un champ de jeton renseigné ne constitue pas ce résultat.
Le SDK n’envoie pas le jeton à la cible. Si la cible rejette la requête, examinez d’abord le formulaire envoyé : vérifiez qu’il contient result.Solution.Token, et non l’ID de la tâche ou une ancienne valeur du champ, et que le proxy et l’identité du navigateur correspondent toujours.
Gérer les échéances sans créer de résolutions en double
La résolution dispose d’une échéance de contexte de 180 secondes. Chrome dispose d’une échéance distincte de 60 secondes après la résolution. La fonction run renvoie les erreurs afin que l’annulation différée de son contexte et le nettoyage du navigateur s’exécutent avant que main ne consigne une erreur.
L’annulation du contexte de résolution arrête l’attente, pas le travail distant. Le SDK effectue une seule création et ne réessaie que les interrogations ayant échoué temporairement ; il ne réessaie jamais le POST de création. Un dépassement de délai ne justifie donc pas l’envoi immédiat d’une nouvelle tâche.
- En cas d’annulation ou d’échéance atteinte, utilisez
errors.Ispour identifier l’erreur de contexte. Extrayez*solvethree.Erroravecerrors.Aset conservez sesTaskIDetRequestID. - Si vous disposez d’un ID de tâche, récupérez la tâche avec
GetTask. Sinon, retrouvez-la en renvoyant exactement les paramètres de la tâche d’origine avec le même ID de requête. Un nouvel appel sans cet ID crée une nouvelle requête logique ; modifier les paramètres tout en réutilisant cet ID provoque un conflit. - Pour
*TaskFailedError, examinezErrorCodeet récupérez la tâche en échec pour obtenir son texte d’erreur. Cette tâche est dans un état définitif : cessez de l’interroger et corrigez la cause au lieu de réessayer avec des paramètres inchangés. - Pour une erreur HTTP de l’API, extrayez le
*APIErrorimbriqué afin d’examinerStatusCodeetRetryAfter. Ne confondez pas un échec HTTP avec un échec définitif de tâche.
Sources et référence de l’API
Lancez votre première tâche.
Démarrez avec $5 de crédit dans votre espace de travail.