Use o SDK de Go com chromedp

Por solvethree4 min de leitura

Primeiro resolva, depois inicie o Chrome com o mesmo proxy e a identidade do navegador retornada. Insira o token no formulário da aplicação, envie-o e aguarde o resultado da aplicação. Uma tarefa pronta significa que você tem uma solução — não que o site a aceitou.

Nesta página

Configure os módulos, o perfil e o proxy

Instale solvethree.com/[email protected] e github.com/chromedp/[email protected] com go get. O SDK exige Go 1.22+, mas esta versão do chromedp exige Go 1.25+, então use essa versão para o exemplo combinado. Sua API tipada difere dos exemplos mais antigos do chromedp.

Crie um perfil de site ativo para o hostname de destino no seu espaço de trabalho antes de executar o programa. Enviar um hostname e uma ação não cria um perfil.

  • TARGET_URL: a URL HTTPS completa da página que contém seu formulário. A tarefa usa o hostname dela como Site; o Chrome navega até a URL completa.
  • SOLVETHREE_PROXY: uma única URL de proxy HTTP ou HTTPS. Este exemplo exige um proxy com autorização por IP, sem credenciais na URL.
  • SOLVETHREE_API_KEY: a chave de API do seu espaço de trabalho. Mantenha-a no processo Go, não no JavaScript da página.

O exemplo solicita a ação login e usa o modo padrão reCAPTCHA Enterprise v3. Altere a ação para o valor esperado pela sua aplicação.

Resolva, inicie o Chrome e envie

O programa aguarda a resolução pelo SDK antes de criar o alocador do Chrome. Ele configura o Chrome com o mesmo proxy único e result.Solution.UserAgent, depois define o SecChUA retornado como o cabeçalho sec-ch-ua antes da navegação. Não substitua por uma identidade de navegador sem relação com a solução nem troque de proxy entre a resolução e o envio.

chromedp · enviar por um proxy autorizado por IP
// 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
}

Este exemplo usa deliberadamente um único proxy, então não há seleção de candidatos a determinar. Se você passar a usar ProxyCandidates, obtenha o proxy bem-sucedido com SuccessfulProxy(originalTask, readyResult) e use esse proxy no Chrome.

Substitua as premissas do formulário de demonstração

A inserção do token usa json.Marshal antes de construir a expressão JavaScript. Mantenha essa etapa de escape: ela passa o token como um valor de string JavaScript em vez de interpolar texto sem escape em código executável.

  • Substitua [name="g-recaptcha-response"] pelo campo que sua aplicação realmente envia. O exemplo define seu valor e dispara um evento de entrada; adapte isso se sua aplicação precisar de outro fluxo de envio.
  • Substitua button[type="submit"] pelo controle de envio desejado. Inclua todos os valores obrigatórios do formulário, campos CSRF e estado da sessão antes de clicar.
  • Substitua #success por um resultado que realmente indique aceitação na sua aplicação. Um clique concluído ou um campo de token preenchido não representa esse resultado.

O SDK não envia o token ao destino. Se o destino rejeitar a requisição, inspecione primeiro o formulário enviado: confirme que ele contém result.Solution.Token, não o ID da tarefa nem um valor anterior do campo, e verifique se o proxy e a identidade do navegador continuam correspondendo.

Trate os prazos sem criar resoluções duplicadas

A resolução tem um prazo de contexto de 180 segundos. O Chrome recebe um prazo separado de 60 segundos após a resolução. A função run retorna erros para que o cancelamento adiado do contexto e a limpeza do navegador sejam executados antes de main registrar um erro.

Cancelar o contexto da resolução interrompe a espera, não o trabalho remoto. O SDK cria a tarefa uma única vez e repete apenas consultas com falhas temporárias; ele nunca repete o POST de criação. Portanto, um tempo limite excedido não é motivo para enviar uma nova tarefa imediatamente.

  • Em caso de cancelamento ou prazo excedido, use errors.Is para identificar o erro de contexto. Extraia *solvethree.Error com errors.As e guarde seu TaskID e RequestID.
  • Se você tiver um ID de tarefa, recupere-a com GetTask. Caso contrário, recupere-a reenviando exatamente as entradas originais da tarefa com o mesmo ID de requisição. Chamar novamente sem esse ID cria uma nova requisição lógica; alterar as entradas reutilizando o ID gera um conflito.
  • Para *TaskFailedError, inspecione ErrorCode e recupere a tarefa com falha para obter o texto do erro. Essa tarefa está em estado terminal: pare de consultá-la e corrija a causa em vez de tentar novamente com as mesmas entradas.
  • Para um erro HTTP da API, extraia o *APIError aninhado para inspecionar StatusCode e RetryAfter. Não confunda uma falha HTTP com uma falha terminal da tarefa.

Execute sua primeira tarefa.

Comece com $5 em créditos no espaço de trabalho.

Criar um espaço de trabalho
Use o SDK de Go com chromedp · solvethree