Utiliser l’API CAPTCHA avec Selenium en Java
Demandez d’abord le jeton, puis configurez Chrome avec le même proxy et les valeurs userAgent et secChUa renvoyées avant de naviguer. Placez solution.token dans le champ CAPTCHA de votre application, soumettez le formulaire et attendez l’état de réussite de l’application, pas simplement une tâche prête.
Les exemples utilisent un utilitaire REST Java et Selenium ChromeDriver. Ils ne font intervenir ni détection automatique de CAPTCHA ni extension de navigateur.
Sur cette page
Préparer le projet Java et le site cible
- 1.
Configurer le projet
Utilisez Java 21 ou une version ultérieure. Dans un projet Maven, définissez le niveau de compilation Java sur 21 et ajoutez Gson 2.15.0 et
org.seleniumhq.selenium:selenium-java:4.52.0. Configurez Chrome et ChromeDriver à l’aide de la documentation Selenium pour Chrome. - 2.
Enregistrer les deux fichiers Java
Enregistrez le premier exemple dans
src/main/java/Solve.javaet le second danssrc/main/java/BrowserSolve.java. Conservez-les dans le même package ; les fichiers fournis ne comportent pas de déclaration de package.BrowserSolveappelleSolve.api, pasSolve.main. - 3.
Activer le profil de site
Configurez le nom d’hôte cible dans la console solvethree et assurez-vous que son profil est actif pour votre espace de travail. L’envoi d’un nom d’hôte et d’une action ne crée pas de profil. Consultez la configuration du profil de site.
- 4.
Configurer l’environnement
Configurez les trois variables d’environnement ci-dessous dans le processus qui exécutera
BrowserSolve. Conservez la clé API de l’espace de travail dans votre processus Java de confiance, pas dans la page ni dans le JavaScript du navigateur.
| Variable | Valeur |
|---|---|
SOLVETHREE_API_KEY | Votre clé API d’espace de travail. |
SOLVETHREE_PROXY | Une URL de proxy HTTP avec liste d’adresses IP autorisées, sans nom d’utilisateur ni mot de passe intégrés, ni chemin, paramètres de requête ou fragment. |
TARGET_URL | L’URL complète de la page de l’application contenant le formulaire. |
Cet exemple nécessite un proxy avec liste d’adresses IP autorisées, car il ne prend pas en charge la transmission d’identifiants de proxy via l’URL du proxy de Chrome. La même valeur de proxy est transmise à l’API de tâches et à Chrome.
Ajouter Solve.java pour les requêtes API
Solve.api envoie des requêtes authentifiées à https://api.solvethree.com/v1, vérifie l’état HTTP avant d’analyser une réponse réussie et limite chaque requête au temps restant avant l’échéance locale.
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());
}
}La méthode main autonome illustre la création et l’interrogation des tâches. Son nom d’hôte accounts.example.com et son action login sont des valeurs d’exemple. Pour l’intégration Selenium, utilisez ce fichier comme utilitaire et exécutez plutôt BrowserSolve ; exécuter les deux méthodes main créerait des tâches distinctes.
Une requête reCAPTCHA nécessite un nom d’hôte dans site, l’action de l’application et exactement un des champs proxy ou proxyCandidates. N’ajoutez ni type ni url. Omettre recaptchaType sélectionne enterprise-v3, qui est utilisé dans ces exemples.
Démarrer Chrome avec l’identité de la solution prête
BrowserSolve déduit site de TARGET_URL, crée la tâche et l’interroge tant que son état est pending ou solving. Seule une tâche ready fournit la solution utilisée par le navigateur.
// 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(); }
}
}L'ordre est important : ChromeOptions définit le proxy et l'agent utilisateur renvoyé, puis ChromeDriver définit l'en-tête sec-ch-ua renvoyé via CDP avant browser.get(target). Ne naviguez pas d'abord avec une identité sans rapport pour ne la modifier qu'au moment de soumettre le jeton.
Cet exemple soumet volontairement un seul proxy, afin que Chrome puisse utiliser ce même proxy sans avoir à choisir parmi plusieurs candidats. Veillez à ce que l'URL cible soit cohérente avec le nom d'hôte et l'action utilisés pour la tâche.
Adapter le formulaire avant d'exécuter BrowserSolve
L'exemple de navigateur cible un formulaire que vous contrôlez, avec un champ de réponse CAPTCHA, un bouton d'envoi et un élément indiquant la réussite. Modifiez ces valeurs propres à l'application avant d'exécuter BrowserSolve.main avec les dépendances Maven dans son classpath.
action: remplacezloginpar l'action que votre application utilise pour cet envoi.g-recaptcha-response: vérifiez le nom du champ réellement envoyé par votre formulaire. L'exemple lui affectesolution.tokenet déclenche un événementinputqui se propage.button[type=submit]: remplacez ce sélecteur s'il ne désigne pas le bouton d'envoi du formulaire voulu.success: remplacez cet identifiant d'élément par un état qui n'apparaît qu'après la réussite de l'envoi en cours.
Définir un champ et déclencher un événement ne constitue pas un mécanisme de rappel CAPTCHA universel. Si la logique du formulaire de votre application n'exploite pas ce champ ou cet événement, adaptez l'étape d'envoi à son mécanisme de liaison réel. Inspectez la requête sortante pour vérifier qu'elle contient solution.token, et non l'identifiant de la tâche ou un ancien jeton.
L'attente finale de WebDriver vérifie la présence d'un élément de l'application indiquant la réussite. Choisissez cet indicateur avec soin : un élément déjà présent avant l'envoi ne prouve rien concernant la nouvelle requête. Une tâche prête signifie que solvethree a généré une solution ; l'acceptation par la cible est établie par la réponse de l'application.
Gérer les échecs sans créer inutilement une autre tâche
- L'API renvoie une réponse HTTP qui n'indique pas une réussite.
Vérifiez la réponse HTTP séparément du statut de la tâche. Solve.api lève une exception avant de la traiter comme une réponse de réussite.
Essayez ceci : Diagnostiquez l'erreur de requête avant de réessayer. Vérifiez les champs de la requête et le profil de site actif plutôt que de renvoyer en boucle les mêmes données invalides.
- La tâche passe à l’état failed.
Lisez errorCode et error dans la réponse de la tâche. L'exception générique de BrowserSolve ne les affiche pas, contrairement à l'exemple autonome Solve.java.
Essayez ceci : Arrêtez d'interroger cette tâche et exposez ces champs dans votre gestion des erreurs. Les résolutions échouées sont remboursées ; ne supposez pas que chaque échec est un problème de crédit.
- La création dépasse le délai d'attente ou l'échéance locale est atteinte.
Déterminez si vous disposez déjà d'un identifiant de tâche ou si vous avez enregistré le corps de la requête d'origine et requestId. Un dépassement du délai de connexion ne prouve pas que la création a échoué.
Essayez ceci : Reprenez la récupération à l'aide de l'identifiant de tâche, ou récupérez la tâche créée avec le même requestId et des données d'entrée identiques. Enregistrez le corps avant la création si la récupération doit rester possible après un redémarrage ; une nouvelle exécution de la méthode main fournie génère un nouveau requestId.
- La tâche est prête, mais l'application rejette l'envoi.
Inspectez le jeton sortant, l'action, l'URL cible, le proxy, l'agent utilisateur et sec-ch-ua. Vérifiez que l'application a effectivement envoyé la nouvelle valeur affectée au champ.
Essayez ceci : Corrigez la valeur incohérente ou la liaison utilisée pour l'envoi avant de payer une autre résolution. Conservez ensemble le proxy ayant fonctionné et l'identité renvoyée.
L'échéance de 180 secondes pour l'API et l'attente de 20 secondes pour l'application sont des limites locales choisies pour les exemples, et non des garanties du service. Pour plus de détails sur les erreurs de l'API, consultez Erreurs de l'API CAPTCHA.
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.