Use a API de CAPTCHA com Selenium em Java

Por solvethree6 min de leitura

Solicite o token primeiro e depois configure o Chrome com o mesmo proxy e os valores de userAgent e secChUa retornados antes de navegar. Coloque solution.token no campo de CAPTCHA da aplicação, envie o formulário e aguarde o estado de sucesso da aplicação — não apenas uma tarefa pronta.

Os exemplos usam um auxiliar REST em Java e o Selenium ChromeDriver. Não há detecção automática de CAPTCHA nem plugin de navegador envolvido.

Nesta página

Prepare o projeto Java e o site de destino

  1. 1.

    Configure o projeto

    Use Java 21 ou posterior. Em um projeto Maven, defina o nível de compilação Java como 21 e adicione Gson 2.15.0 e org.seleniumhq.selenium:selenium-java:4.52.0. Configure o Chrome e o ChromeDriver usando a documentação do Selenium para Chrome.

  2. 2.

    Salve os dois arquivos Java

    Salve o primeiro exemplo como src/main/java/Solve.java e o segundo como src/main/java/BrowserSolve.java. Mantenha-os no mesmo pacote; os arquivos fornecidos não têm declaração de pacote. BrowserSolve chama Solve.api, não Solve.main.

  3. 3.

    Ative o perfil do site

    Configure o hostname de destino no console do solvethree e verifique se o perfil está ativo para seu espaço de trabalho. Enviar um hostname e uma ação não cria um perfil. Consulte a configuração do perfil do site.

  4. 4.

    Configure o ambiente

    Configure as três variáveis de ambiente abaixo no processo que executará BrowserSolve. Mantenha a chave de API do espaço de trabalho no seu processo Java confiável, não na página nem no JavaScript do navegador.

Variáveis de ambiente para BrowserSolve
Variáveis de ambiente para BrowserSolve
VariávelValor
SOLVETHREE_API_KEYA chave de API do seu espaço de trabalho.
SOLVETHREE_PROXYUma URL de proxy HTTP com lista de IPs permitidos, sem nome de usuário ou senha incorporados, caminho, consulta ou fragmento.
TARGET_URLA URL completa da página da aplicação que contém o formulário.

Este exemplo exige um proxy com lista de IPs permitidos porque não oferece suporte à passagem de credenciais de proxy pela URL de proxy do Chrome. O mesmo valor de proxy é passado à API de tarefas e ao Chrome.

Adicione Solve.java para solicitações à API

Solve.api envia solicitações autenticadas para https://api.solvethree.com/v1, verifica o status HTTP antes de analisar uma resposta de sucesso e limita cada solicitação ao tempo restante do prazo local.

Java 21+ · Solve.java (dependência Gson)
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.UUID;

public class Solve {
    static final HttpClient HTTP = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(15)).build();
    static final String KEY = System.getenv("SOLVETHREE_API_KEY");

    static JsonObject api(String path, JsonObject body, long deadline) throws Exception {
        long remaining = deadline - System.nanoTime();
        if (remaining <= 0) throw new IllegalStateException("Keep the task ID and resume polling");
        var builder = HttpRequest.newBuilder(URI.create("https://api.solvethree.com/v1" + path))
            .timeout(Duration.ofNanos(Math.min(remaining, Duration.ofSeconds(30).toNanos())))
            .header("Authorization", "Bearer " + KEY)
            .header("Content-Type", "application/json");
        if (body == null) builder.GET();
        else builder.POST(HttpRequest.BodyPublishers.ofString(body.toString()));
        var response = HTTP.send(builder.build(), HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() < 200 || response.statusCode() >= 300)
            throw new IllegalStateException("API HTTP " + response.statusCode());
        return JsonParser.parseString(response.body()).getAsJsonObject();
    }
    public static void main(String[] args) throws Exception {
        String proxy = System.getenv("SOLVETHREE_PROXY");
        if (KEY == null || proxy == null) throw new IllegalArgumentException("Set the API key and proxy");
        var input = new JsonObject();
        input.addProperty("site", "accounts.example.com");
        input.addProperty("action", "login");
        input.addProperty("proxy", proxy);
        input.addProperty("requestId", UUID.randomUUID().toString());
        // Save input before creation if the task must be recovered after restart.
        long deadline = System.nanoTime() + Duration.ofSeconds(180).toNanos();
        var task = api("/tasks?waitMs=0", input, deadline);
        while (task.get("status").getAsString().equals("pending") || task.get("status").getAsString().equals("solving")) {
            String id = URLEncoder.encode(task.get("id").getAsString(), StandardCharsets.UTF_8);
            task = api("/tasks/" + id + "?waitMs=15000", null, deadline);
            if (task.get("status").getAsString().equals("pending") || task.get("status").getAsString().equals("solving"))
                Thread.sleep(1000);
        }
        if (!task.get("status").getAsString().equals("ready"))
            throw new IllegalStateException("Task failed: " + task.get("errorCode")
                + ": " + task.get("error"));
        var solution = task.getAsJsonObject("solution");
        // Submit solution.token with userAgent/secChUa and the original proxy.
        System.out.println("Ready task: " + task.get("id").getAsString());
    }
}

O método main independente demonstra a criação de tarefas e as consultas periódicas. Seu hostname accounts.example.com e sua ação login são valores de exemplo. Para a integração com Selenium, use esse arquivo como auxiliar e execute BrowserSolve em vez dele; executar os dois métodos main criaria tarefas separadas.

Uma solicitação de reCAPTCHA precisa de um hostname em site, da action da aplicação e de exatamente um dos campos proxy ou proxyCandidates. Não adicione type nem url. Omitir recaptchaType seleciona enterprise-v3, que é o valor usado nestes exemplos.

Inicie o Chrome com a identidade da solução pronta

BrowserSolve deriva site de TARGET_URL, cria a tarefa e faz consultas periódicas enquanto o status é pending ou solving. Somente uma tarefa ready fornece a solução usada pelo navegador.

Java · passar uma solução pronta para o Chrome
// Save as BrowserSolve.java beside Solve.java from the Java REST quickstart.
// Add Selenium Java 4.52.0 and Gson 2.15.0 to your Maven dependencies; Java 21+.
import com.google.gson.JsonObject;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.UUID;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class BrowserSolve {
    public static void main(String[] args) throws Exception {
        String target = System.getenv("TARGET_URL");
        String proxy = System.getenv("SOLVETHREE_PROXY");
        URI proxyUri = URI.create(proxy);
        if (proxyUri.getUserInfo() != null) throw new IllegalArgumentException("Use an IP-allowlisted proxy");
        var input = new JsonObject();
        input.addProperty("site", URI.create(target).getHost());
        input.addProperty("action", "login");
        input.addProperty("proxy", proxy);
        input.addProperty("requestId", UUID.randomUUID().toString());
        long deadline = System.nanoTime() + Duration.ofSeconds(180).toNanos();
        var task = Solve.api("/tasks?waitMs=0", input, deadline);
        while (task.get("status").getAsString().matches("pending|solving")) {
            String id = URLEncoder.encode(task.get("id").getAsString(), StandardCharsets.UTF_8);
            task = Solve.api("/tasks/" + id + "?waitMs=15000", null, deadline);
            if (task.get("status").getAsString().matches("pending|solving")) Thread.sleep(1000);
        }
        if (!task.get("status").getAsString().equals("ready")) throw new IllegalStateException("Task failed");
        var solution = task.getAsJsonObject("solution");
        var options = new ChromeOptions();
        options.addArguments("--proxy-server=" + proxy, "--user-agent=" + solution.get("userAgent").getAsString());
        var browser = new ChromeDriver(options);
        try {
            browser.executeCdpCommand("Network.enable", Map.of());
            browser.executeCdpCommand("Network.setExtraHTTPHeaders", Map.of("headers",
                Map.of("sec-ch-ua", solution.get("secChUa").getAsString())));
            browser.get(target);
            var wait = new WebDriverWait(browser, Duration.ofSeconds(20));
            var field = wait.until(driver -> driver.findElement(By.name("g-recaptcha-response")));
            browser.executeScript("arguments[0].value=arguments[1]; arguments[0].dispatchEvent(new Event('input',{bubbles:true}));",
                field, solution.get("token").getAsString());
            browser.findElement(By.cssSelector("button[type=submit]")).click();
            wait.until(driver -> driver.findElement(By.id("success"))); // Your application's success marker.
        } finally { browser.quit(); }
    }
}

A ordem importa: ChromeOptions define o proxy e o user agent retornado; depois, ChromeDriver define o cabeçalho sec-ch-ua retornado via CDP antes de browser.get(target). Não navegue primeiro com uma identidade diferente para alterá-la apenas ao enviar o token.

Este exemplo envia deliberadamente um único proxy, para que o Chrome possa usar esse mesmo proxy sem precisar escolher entre candidatos. Mantenha a URL de destino consistente com o hostname e a ação usados na tarefa.

Adapte o formulário antes de executar BrowserSolve

O exemplo de navegador usa um formulário sob seu controle com um campo de resposta do CAPTCHA, um botão de envio e um elemento de sucesso. Altere esses valores específicos da aplicação antes de executar BrowserSolve.main com as dependências do Maven no classpath.

  • action: substitua login pela ação que sua aplicação usa neste envio.
  • g-recaptcha-response: confirme o nome do campo que seu formulário realmente envia. O exemplo atribui solution.token e dispara um evento input com propagação.
  • button[type=submit]: substitua este seletor se ele não identificar o botão de envio do formulário desejado.
  • success: substitua este ID de elemento por um estado que apareça somente após o envio atual ser bem-sucedido.

Definir um campo e disparar um evento não é um callback universal de CAPTCHA. Se a lógica do formulário da sua aplicação não consumir esse campo ou evento, adapte a etapa de envio à vinculação real. Inspecione a requisição de saída para confirmar que ela contém solution.token, e não o ID da tarefa ou um token antigo.

A espera final do WebDriver verifica a presença de um elemento de sucesso da aplicação. Escolha esse indicador com cuidado: um elemento já presente antes do envio não comprova nada sobre a nova requisição. Uma tarefa pronta significa que o solvethree gerou uma solução; a aceitação pelo destino é confirmada pela resposta da aplicação.

Trate falhas sem criar outra tarefa desnecessariamente

A API retorna uma resposta HTTP sem sucesso.

Verifique a resposta HTTP separadamente do status da tarefa. Solve.api lança uma exceção antes de tratá-la como um payload de sucesso.

Experimente: Diagnostique o erro da requisição antes de tentar novamente. Confirme os campos da requisição e o perfil de site ativo, em vez de enviar repetidamente os mesmos dados inválidos.

A tarefa chega ao status failed.

Leia errorCode e error na resposta da tarefa. A exceção genérica de BrowserSolve não os exibe, embora o exemplo independente Solve.java os exiba.

Experimente: Pare de consultar essa tarefa e exponha esses campos no tratamento de erros. Resoluções com falha são reembolsadas; não presuma que toda falha é um problema de créditos.

A criação excede o tempo limite ou o prazo local expira.

Verifique se você já tem um ID de tarefa ou se salvou o corpo original da requisição e o requestId. Um tempo limite de conexão não comprova que a criação falhou.

Experimente: Retome a consulta usando o ID da tarefa ou recupere a criação com o mesmo requestId e dados de entrada idênticos. Salve o corpo antes da criação se a recuperação precisar funcionar após uma reinicialização; executar novamente o método main fornecido gera um novo requestId.

A tarefa está pronta, mas a aplicação rejeita o envio.

Inspecione o token enviado, a ação, a URL de destino, o proxy, o user agent e sec-ch-ua. Confirme que a aplicação realmente enviou o valor recém-atribuído ao campo.

Experimente: Corrija o valor incompatível ou a vinculação do envio antes de pagar por outra resolução. Mantenha juntos o proxy que funcionou e a identidade retornada.

O prazo de 180 segundos da API e a espera de 20 segundos da aplicação são limites locais escolhidos pelos exemplos, não garantias do serviço. Para mais detalhes sobre erros da API, consulte Erros da API de CAPTCHA.

Execute sua primeira tarefa.

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

Criar um espaço de trabalho
Use a API de CAPTCHA com Selenium em Java · solvethree