Solveur de captcha en PHP avec cURL : exemple complet (2026)
PHP n'a besoin que de l'extension cURL, présente dans la plupart des installations, pour résoudre un captcha. Vous envoyez un POST JSON à l'API Scarnox, lisez solution.token dans la réponse, et soumettez ce token au formulaire du site. Ce guide présente le flux PHP complet pour PopularCaptcha, que Scarnox résout aujourd'hui sans proxy.
Démarrez avec un crédit d'essai gratuit, sans carte bancaire et testez le script sur une page que vous contrôlez avant de l'utiliser ailleurs.
Prérequis
- PHP 8.0 ou plus récent, avec les extensions
curletjsonactivées. Vérifiez avecphp -m. - Une clé d'API Scarnox.
- La sitekey du widget PopularCaptcha de la page. Pour savoir comment la trouver, consultez comment trouver la sitekey d'un captcha.
La fonction du solveur
Cette fonction envoie un POST à l'API, vérifie errorId et renvoie le token. Elle lève une exception en cas d'échec, pour que l'appelant puisse décider de réessayer :
<?php
declare(strict_types=1);
const SCARNOX_API_KEY = 'scarnox_YOURAPIKEY';
const SCARNOX_API_URL = 'https://api.scarnox.com/api/tasks/create';
function solveCaptcha(string $sitekey, string $pageUrl, bool $invisible = false): string
{
$body = [
'captcha_type' => 'PopularCaptchaTaskProxyless',
'site_key' => $sitekey,
'site_url' => $pageUrl,
];
if ($invisible) {
$body['is_invisible'] = true;
}
$ch = curl_init(SCARNOX_API_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body, JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . SCARNOX_API_KEY,
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 185, // l'appel revient lorsque le token est prêt
]);
$raw = curl_exec($ch);
if ($raw === false) {
$error = curl_error($ch);
throw new RuntimeException('cURL error: ' . $error);
}
$data = json_decode((string) $raw, true);
if (!is_array($data)) {
throw new RuntimeException('Response was not JSON');
}
if (($data['errorId'] ?? 1) !== 0) {
throw new RuntimeException(
($data['errorCode'] ?? 'ERROR') . ': ' . ($data['errorDescription'] ?? 'unknown')
);
}
return (string) $data['solution']['token'];
}
L'en-tête Authorization utilise le préfixe Bearer. Le délai d'attente est de 185 secondes, car l'API bloque jusqu'à ce que le token soit prêt, sans étape de polling.
Relancer les échecs transitoires
Une résolution échouée n'est pas facturée, donc quelques réessais sont peu coûteux. Placez la boucle autour de l'appel et attendez un peu plus après chaque échec :
function solveWithRetry(string $sitekey, string $pageUrl, int $attempts = 3): string
{
$lastError = null;
for ($i = 1; $i <= $attempts; $i++) {
try {
return solveCaptcha($sitekey, $pageUrl);
} catch (RuntimeException $e) {
$lastError = $e;
fwrite(STDERR, "Attempt $i failed: " . $e->getMessage() . PHP_EOL);
sleep($i);
}
}
throw $lastError;
}
Pour une politique d'erreur complète, y compris les échecs qui doivent arrêter les réessais, consultez la gestion des erreurs du solveur de captcha.
Soumettre le token avec un pot de cookies
Beaucoup de sites rattachent le captcha à la session qui a chargé le formulaire. Un fichier de cookies permet à cURL d'envoyer les mêmes cookies lors du GET et du POST. La fonction ci-dessous soumet le token au formulaire de la page :
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// GET d'abord, pour que le site définisse le cookie de session.
$ch = curl_init($pageUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_COOKIEFILE => $cookieFile,
CURLOPT_COOKIEJAR => $cookieFile,
CURLOPT_TIMEOUT => 60,
]);
curl_exec($ch);
// Puis POST du formulaire avec le token dans les deux champs de captcha.
$fields = http_build_query([
'email' => 'you@example.com',
'h-captcha-response' => $token,
'g-recaptcha-response' => $token,
]);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fields,
CURLOPT_TIMEOUT => 60,
]);
$body = curl_exec($ch);
if ($body === false) {
throw new RuntimeException('Form submit failed: ' . curl_error($ch));
}
return (string) $body;
}
Deux points comptent. Le GET s'exécute avant la résolution pour que le cookie soit en place. Et le token part juste après la résolution, car il expire en environ deux minutes. Placez l'appel de résolution juste avant cette fonction, et non au début d'un long lot.
Le fichier de cookies est partagé par tous les appels du même processus. Si vous lancez plusieurs inscriptions en parallèle, donnez un fichier distinct à chaque compte ou session. Sinon, une session peut écraser les cookies d'une autre, et le second POST échouera pour des raisons qui ressemblent à un problème de captcha mais n'en sont pas.
Tout assembler
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
Exécutez-le depuis la ligne de commande :
php signup.php
Captchas invisibles
Si le widget est invisible, appelez solveCaptcha($sitekey, $pageUrl, true). Le champ is_invisible est alors envoyé avec la requête. Certaines pages ont aussi besoin d'un callback JavaScript appelé avec le token, ce qu'un script côté serveur ne peut pas déclencher. Dans ce cas, utilisez plutôt un outil de navigateur. Le guide sur le captcha invisible couvre les différents cas.
Timing et expiration
Le token est valide pendant environ deux minutes. Gardez la résolution et la soumission proches l'une de l'autre. L'expiration des tokens de captcha explique comment distinguer un token expiré d'un token rejeté.
Scraper de manière responsable
Si votre script PHP scrape des pages publiques, consultez le robots.txt et les conditions du site avant de commencer. Ajoutez un délai entre les requêtes, et ne conservez pas de données personnelles dont vous n'avez pas besoin. Résoudre un captcha ne change pas ce que vous êtes autorisé à collecter. Pour l'aspect juridique, consultez le web scraping est-il légal.
Tarifs
Vous payez par résolution réussie. Les résolutions échouées ne sont pas facturées. Consultez les tarifs actuels, et démarrez avec un crédit d'essai gratuit, sans carte bancaire.