Die CAPTCHA-API mit Selenium in Java verwenden

Von solvethree5 Min. Lesezeit

Fordern Sie zuerst das Token an und konfigurieren Sie Chrome dann vor dem Navigieren mit demselben Proxy und den zurückgegebenen Werten für userAgent und secChUa. Tragen Sie solution.token in das CAPTCHA-Feld Ihrer Anwendung ein, senden Sie das Formular ab und warten Sie auf den Erfolgszustand der Anwendung – nicht nur auf einen fertigen Task.

Die Beispiele verwenden einen Java-REST-Helfer und Selenium ChromeDriver. Es kommen weder eine automatische CAPTCHA-Erkennung noch ein Browser-Plugin zum Einsatz.

Auf dieser Seite

Java-Projekt und Zielwebsite vorbereiten

  1. 1.

    Projekt konfigurieren

    Verwenden Sie Java 21 oder höher. Setzen Sie in einem Maven-Projekt die Java-Kompilierungsversion auf 21 und fügen Sie Gson 2.15.0 sowie org.seleniumhq.selenium:selenium-java:4.52.0 hinzu. Konfigurieren Sie Chrome und ChromeDriver anhand der Selenium-Dokumentation zu Chrome.

  2. 2.

    Beide Java-Dateien speichern

    Speichern Sie das erste Beispiel als src/main/java/Solve.java und das zweite als src/main/java/BrowserSolve.java. Belassen Sie beide im selben Paket; die bereitgestellten Dateien haben keine Paketdeklaration. BrowserSolve ruft Solve.api auf, nicht Solve.main.

  3. 3.

    Websiteprofil aktivieren

    Richten Sie den Zielhostnamen in der solvethree-Konsole ein und stellen Sie sicher, dass sein Profil für Ihren Workspace aktiv ist. Durch das Senden eines Hostnamens und einer Aktion wird kein Profil erstellt. Siehe Website-Profil einrichten.

  4. 4.

    Umgebung einrichten

    Konfigurieren Sie die drei folgenden Umgebungsvariablen in dem Prozess, der BrowserSolve ausführt. Halten Sie den Workspace-API-Schlüssel in Ihrem vertrauenswürdigen Java-Prozess, nicht in der Seite oder im Browser-JavaScript.

Umgebungsvariablen für BrowserSolve
Umgebungsvariablen für BrowserSolve
VariableWert
SOLVETHREE_API_KEYIhr Workspace-API-Schlüssel.
SOLVETHREE_PROXYEine per IP-Freigabeliste autorisierte HTTP-Proxy-URL ohne eingebetteten Benutzernamen oder Passwort, Pfad, Abfrage oder Fragment.
TARGET_URLDie vollständige URL der Anwendungsseite, die das Formular enthält.

Dieses Beispiel erfordert einen per IP-Freigabeliste autorisierten Proxy, da es die Übergabe von Proxy-Zugangsdaten über die Proxy-URL von Chrome nicht unterstützt. Derselbe Proxy-Wert wird an die Task-API und an Chrome übergeben.

Solve.java für API-Anfragen hinzufügen

Solve.api sendet authentifizierte Anfragen an https://api.solvethree.com/v1, prüft den HTTP-Status vor dem Parsen einer Erfolgsantwort und begrenzt jede Anfrage auf die verbleibende lokale Frist.

Java 21+ · Solve.java (Gson-Abhängigkeit)
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());
    }
}

Die eigenständige Methode main demonstriert die Task-Erstellung und das Polling. Ihr Hostname accounts.example.com und die Aktion login sind Platzhalter. Verwenden Sie diese Datei für die Selenium-Integration als Helfer und führen Sie stattdessen BrowserSolve aus; das Ausführen beider main-Methoden würde separate Tasks erstellen.

Eine reCAPTCHA-Anfrage benötigt einen Hostnamen in site, die action der Anwendung und genau eines der Felder proxy oder proxyCandidates. Fügen Sie weder type noch url hinzu. Wenn recaptchaType weggelassen wird, wird enterprise-v3 ausgewählt; diese Variante verwenden die Beispiele.

Chrome mit der Identität der fertigen Lösung starten

BrowserSolve leitet site aus TARGET_URL ab, erstellt den Task und fragt ihn ab, solange sein Status pending oder solving ist. Nur ein Task mit dem Status ready liefert die vom Browser verwendete Lösung.

Java · Eine fertige Lösung an Chrome übergeben
// 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(); }
    }
}

Die Reihenfolge ist wichtig: ChromeOptions setzt den Proxy und den zurückgegebenen User-Agent. Anschließend setzt ChromeDriver vor browser.get(target) den zurückgegebenen Header sec-ch-ua über CDP. Navigieren Sie nicht zuerst mit einer anderen Identität zur Seite, um diese erst beim Übermitteln des Tokens zu ändern.

Dieses Beispiel übermittelt bewusst einen einzelnen proxy, damit Chrome denselben Proxy verwenden kann, ohne zwischen Kandidaten wählen zu müssen. Die Ziel-URL muss mit dem Hostnamen und der Aktion der Aufgabe übereinstimmen.

Formular vor dem Ausführen von BrowserSolve anpassen

Das Browserbeispiel ist auf ein eigenes Formular mit einem CAPTCHA-Antwortfeld, einer Absenden-Schaltfläche und einem Erfolgselement ausgelegt. Ändern Sie diese anwendungsspezifischen Werte, bevor Sie BrowserSolve.main mit den Maven-Abhängigkeiten im Klassenpfad ausführen.

  • action: Ersetzen Sie login durch die Aktion, die Ihre Anwendung für diese Übermittlung verwendet.
  • g-recaptcha-response: Prüfen Sie den Feldnamen, den Ihr Formular tatsächlich übermittelt. Das Beispiel weist solution.token zu und löst ein input-Event mit Bubbling aus.
  • button[type=submit]: Ersetzen Sie diesen Selektor, falls er nicht die Absenden-Schaltfläche des vorgesehenen Formulars identifiziert.
  • success: Ersetzen Sie diese Element-ID durch einen Zustand, der erst nach erfolgreicher aktueller Übermittlung erscheint.

Das Setzen eines Feldes und Auslösen eines Events ist kein universeller CAPTCHA-Callback. Wenn die Formularlogik Ihrer Anwendung dieses Feld oder Event nicht verarbeitet, passen Sie den Übermittlungsschritt an die tatsächliche Anbindung an. Prüfen Sie die ausgehende Anfrage darauf, ob sie solution.token enthält und nicht die Aufgaben-ID oder ein altes Token.

Die abschließende WebDriver-Wartebedingung prüft auf ein Erfolgselement der Anwendung. Wählen Sie dieses Merkmal sorgfältig: Ein bereits vor der Übermittlung vorhandenes Element beweist nichts über die neue Anfrage. Eine fertige Aufgabe bedeutet, dass solvethree eine Lösung generiert hat; ob das Ziel sie akzeptiert, zeigt die Antwort der Anwendung.

Fehler behandeln, ohne unnötig eine weitere Aufgabe zu erstellen

Die API gibt eine HTTP-Antwort zurück, die keinen Erfolg anzeigt.

Prüfen Sie die HTTP-Antwort getrennt vom Aufgabenstatus. Solve.api löst eine Ausnahme aus, bevor die Antwort als Erfolgsdaten verarbeitet wird.

Probiere Folgendes: Ermitteln Sie den Anfragefehler vor einem erneuten Versuch. Prüfen Sie die Anfragefelder und das aktive Websiteprofil, statt unveränderte ungültige Eingaben wiederholt zu senden.

Die Aufgabe erreicht den Status failed.

Lesen Sie errorCode und error aus der Aufgabenantwort. Die generische Ausnahme von BrowserSolve zeigt diese nicht an, das eigenständige Beispiel Solve.java hingegen schon.

Probiere Folgendes: Beenden Sie das Polling für diese Aufgabe und geben Sie diese Felder in Ihrer Fehlerbehandlung aus. Fehlgeschlagene Lösungsversuche werden erstattet; gehen Sie nicht davon aus, dass jeder Fehler auf ein Guthabenproblem zurückzuführen ist.

Beim Erstellen tritt ein Timeout auf oder das lokale Zeitlimit läuft ab.

Prüfen Sie, ob Sie bereits eine Aufgaben-ID haben oder den ursprünglichen Anfragebody samt requestId gespeichert haben. Ein Verbindungs-Timeout beweist nicht, dass die Erstellung fehlgeschlagen ist.

Probiere Folgendes: Setzen Sie den Abruf mit der Aufgaben-ID fort oder stellen Sie die Erstellung mit derselben requestId und identischen Eingaben wieder her. Speichern Sie den Body vor dem Erstellen, wenn die Wiederherstellung auch nach einem Neustart möglich sein muss; ein erneutes Ausführen der bereitgestellten main-Methode generiert eine neue requestId.

Die Aufgabe ist fertig, aber die Anwendung lehnt die Übermittlung ab.

Prüfen Sie das ausgehende Token, die Aktion, die Ziel-URL, den Proxy, den User-Agent und sec-ch-ua. Vergewissern Sie sich, dass die Anwendung tatsächlich den neu zugewiesenen Feldwert übermittelt hat.

Probiere Folgendes: Korrigieren Sie den abweichenden Wert oder die Anbindung der Übermittlung, bevor Sie für einen weiteren Lösungsversuch bezahlen. Verwenden Sie den erfolgreichen Proxy und die zurückgegebene Identität weiterhin zusammen.

Das API-Zeitlimit von 180 Sekunden und die Wartezeit der Anwendung von 20 Sekunden sind lokale Grenzen, die für die Beispiele gewählt wurden, keine Garantien des Dienstes. Weitere Details zu API-Fehlern finden Sie unter CAPTCHA-API-Fehler.

Führe deinen ersten Task aus.

Starte mit $5 Workspace-Guthaben.

Workspace erstellen
Die CAPTCHA-API mit Selenium in Java verwenden · solvethree