Utiliser Guzzle avec l’API de tâches CAPTCHA
Utilisez Guzzle 7 pour créer une tâche, puis interrogez son ID jusqu’à ce qu’elle soit ready ou failed. Conservez le requestId en cas de problème : un délai de connexion dépassé ne prouve pas que la création de la tâche a échoué.
Il s’agit d’une intégration REST, pas d’un SDK PHP officiel.
Sur cette page
Préparer la requête reCAPTCHA
- Installez Guzzle 7 avec Composer. La commande d’installation figure en haut de l’exemple.
- Définissez SOLVETHREE_API_KEY sur la clé API de votre espace de travail et SOLVETHREE_PROXY sur l’URL du proxy. Gardez la clé sur le serveur.
- Créez un profil actif pour votre site cible dans la console avant de demander une résolution. Consultez la configuration du profil de site.
- Remplacez accounts.example.com et login par le nom d’hôte et l’action cibles. Le champ site attend un nom d’hôte, pas une URL complète.
L’exemple demande reCAPTCHA Enterprise v3, la valeur par défaut de recaptchaType. N’ajoutez pas de champs type ou url. Il fournit un seul proxy ; si vous utilisez proxyCandidates à la place, omettez entièrement proxy.
Créer une seule fois, puis interroger dans un délai fixe
<?php
// composer require guzzlehttp/guzzle:^7
require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://api.solvethree.com/v1/',
'headers' => ['Authorization' => 'Bearer '.getenv('SOLVETHREE_API_KEY'), 'Accept' => 'application/json'],
'allow_redirects' => false,
'http_errors' => false,
]);
$input = ['site' => 'accounts.example.com', 'action' => 'login',
'proxy' => getenv('SOLVETHREE_PROXY'), 'requestId' => bin2hex(random_bytes(16))];
$deadline = microtime(true) + 180;
$call = function (string $method, string $path, array $options = []) use ($client, $deadline): array {
$remaining = $deadline - microtime(true);
if ($remaining <= 0) throw new RuntimeException('Local deadline reached');
$response = $client->request($method, $path, $options + ['timeout' => min(25, $remaining), 'connect_timeout' => min(10, $remaining)]);
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
throw new RuntimeException('API HTTP '.$response->getStatusCode());
}
return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
};
$id = null;
try {
$result = $call('POST', 'tasks?waitMs=0', ['json' => $input]);
$id = $result['id'];
while (in_array($result['status'], ['pending', 'solving'], true)) {
$result = $call('GET', 'tasks/'.rawurlencode($id).'?waitMs=15000');
if (in_array($result['status'], ['pending', 'solving'], true)) usleep(1000000);
}
if ($result['status'] !== 'ready') {
throw new RuntimeException('Task failed: '.($result['errorCode'] ?? 'unknown'));
}
echo 'Ready task: '.$id.PHP_EOL;
// Submit $result['solution']['token'] with userAgent/secChUa and the same proxy.
} catch (Throwable $error) {
fwrite(STDERR, 'Recovery requestId='.$input['requestId'].' taskId='.($id ?? 'unknown').PHP_EOL);
throw $error;
}Le client s’authentifie avec une clé Bearer. Son base_uri se termine par /v1/ et les chemins de requête sont relatifs, ce qui conserve ce préfixe d’API. L’option json de Guzzle envoie les paramètres de la tâche au format JSON.
La fonction utilitaire effectue un seul POST de création. Elle interroge ensuite l’ID de tâche renvoyé tant que status vaut pending ou solving. La création et les interrogations partagent un budget de 180 secondes ; chaque appel HTTP est limité au temps restant, avec des délais maximaux de requête et de connexion de 25 et 10 secondes respectivement. Une nouvelle interrogation ne réinitialise pas le budget global.
Les redirections sont désactivées. Définir http_errors sur false permet à la fonction utilitaire de vérifier explicitement les réponses non-2xx avant de décoder le contenu d’une réponse réussie ; cela ne supprime ni les erreurs de connexion ni les dépassements de délai.
- Une réponse HTTP non-2xx lève une erreur HTTP d’API. Analysez le statut et le corps de la réponse au lieu de la traiter comme un échec de résolution.
- Une tâche dans l’état terminal failed arrête les interrogations. L’exemple lève une exception contenant son errorCode ; examinez également le champ error de la tâche pour obtenir le message de diagnostic. Les résolutions échouées sont remboursées.
- Seul ready contient une solution utilisable. La ligne affichée « Ready task » indique que la tâche est prête, pas que le site cible l’a acceptée.
Reprendre une requête ayant dépassé le délai sans payer une autre tâche
Conservez le requestId généré et les paramètres exacts de la tâche avant d’envoyer le POST. Le bloc catch affiche requestId et, si la création en a renvoyé un, taskId. Cette sortie facilite la récupération, mais ne remplace pas l’enregistrement de la requête avant son envoi.
- 1.
Si vous avez un ID de tâche, récupérez cette tâche
Utilisez GET /v1/tasks/:id pour vérifier son statut. Atteindre la limite de temps locale de la fonction utilitaire ne prouve pas que la tâche distante a échoué.
- 2.
Si le délai de création a expiré sans renvoyer d’ID, récupérez la tâche avec requestId
Soumettez la même requête de tâche avec le requestId enregistré. Des paramètres identiques renvoient la tâche existante ; des paramètres différents avec cet ID provoquent un conflit.
- 3.
Ne relancez pas le script comme raccourci de récupération
Chaque exécution génère un nouveau requestId. N’ajoutez pas de nouvelle tentative automatique de POST qui génère un autre ID et ne réessayez pas aveuglément avec des paramètres invalides inchangés.
Soumettre le jeton via le même proxy
L’exemple s’arrête avant de contacter la cible. Soumettez solution.token — pas l’ID de tâche — et utilisez les valeurs solution.userAgent et solution.secChUa renvoyées comme en-têtes User-Agent et Sec-CH-UA de la requête cible.
Le proxy dans le JSON de la tâche indique à solvethree quel proxy utiliser pour la résolution. Il ne configure ni la connexion de Guzzle à l’API ni votre requête ultérieure vers la cible. Configurez séparément la requête cible pour utiliser ce même proxy.
Utilisez un client distinct pour la requête cible afin que l’en-tête Authorization par défaut du client API ne soit pas envoyé au site web. Conservez ensemble le jeton, l’identité de navigateur renvoyée, le proxy et la cible prévue. Un jeton prêt peut tout de même être rejeté si la requête suivante ne correspond pas.
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.