Captcha-solver in PHP met cURL: werkend voorbeeld (2026)
PHP heeft alleen de cURL-extensie nodig, die bij de meeste installaties al zit, om een captcha op te lossen. Je stuurt één JSON-POST naar de Scarnox-API, leest solution.token uit de respons, en dient dat token in bij het formulier van de site. Deze gids loopt de volledige PHP-flow door voor PopularCaptcha, dat Scarnox vandaag zonder proxy oplost.
Begin met gratis proefcredit, zonder creditcard en probeer het script op een pagina die je beheert voordat je het ergens anders gebruikt.
Vereisten
- PHP 8.0 of nieuwer, met de extensies
curlenjsoningeschakeld. Controleer metphp -m. - Een Scarnox-API-sleutel.
- De sitekey van de PopularCaptcha-widget van de pagina. Voor hulp bij het vinden ervan, zie hoe je de captcha-sitekey vindt.
De solverfunctie
Deze functie stuurt een verzoek naar de API, controleert errorId, en geeft het token terug. Ze gooit een uitzondering bij elke fout, zodat de aanroeper kan beslissen of hij opnieuw probeert:
<?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, // de aanroep keert terug wanneer het token klaar is
]);
$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'];
}
De Authorization-header gebruikt het voorvoegsel Bearer. De time-out is 185 seconden, omdat de API blokkeert totdat het token klaar is, zonder polling-stap.
Tijdelijke fouten opnieuw proberen
Een mislukte oplossing wordt niet in rekening gebracht, dus een paar nieuwe pogingen zijn goedkoop. Zet de lus om de aanroep en wacht na elke fout iets langer:
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;
}
Voor een volledig foutbeleid, inclusief bij welke fouten je moet stoppen, zie foutafhandeling van de captcha-solver.
Het token indienen met een cookiejar
Veel sites koppelen de captcha aan de sessie die het formulier heeft geladen. Een cookiebestand laat cURL dezelfde cookies sturen bij de GET en de POST. De functie hieronder dient het token in bij het formulier van de pagina:
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// Eerst een GET, zodat de site de sessiecookie instelt.
$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);
// Daarna het formulier posten met het token in beide captchavelden.
$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;
}
Twee dingen zijn belangrijk. De GET draait vóór de oplossing, zodat de cookie al op zijn plek staat. En het token gaat meteen na de oplossing eruit, omdat het na ongeveer twee minuten verloopt. Zet de oplossingsaanroep direct voor deze functie, niet aan het begin van een lange batch.
Het cookiebestand wordt gedeeld door elke aanroep in hetzelfde proces, dus geef elk account of elke sessie een eigen bestand als je meerdere aanmeldingen parallel draait. Anders kan de ene sessie de cookies van de andere overschrijven, en mislukt de tweede POST om redenen die op een captchaprobleem lijken maar dat niet zijn.
Alles samenvoegen
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
Uitvoeren vanaf de opdrachtregel:
php signup.php
Onzichtbare widgets
Als de widget onzichtbaar is, roep dan solveCaptcha($sitekey, $pageUrl, true) aan. Het veld is_invisible wordt dan met het verzoek meegestuurd. Sommige pagina's hebben ook een JavaScript-callback nodig met het token, en die kan een server-side script niet activeren. Gebruik in dat geval een browsertool. De gids over onzichtbare captcha behandelt de gevallen.
Timing en verval
Het token is ongeveer twee minuten geldig. Houd de oplossing en het verzenden dicht bij elkaar. Verlopen captchatokens legt uit hoe je een verlopen token van een afgewezen token onderscheidt.
Verantwoord scrapen
Als je PHP-script publieke pagina's scrapet, controleer dan robots.txt en de voorwaarden van de site voordat je begint. Voeg een vertraging toe tussen verzoeken en bewaar geen persoonsgegevens die je niet nodig hebt. Een captcha oplossen verandert niet wat je mag verzamelen. Voor de juridische kant, zie is webscraping legaal.
Prijzen
Je betaalt per geslaagde oplossing. Mislukte oplossingen worden niet in rekening gebracht. Zie actuele prijzen voor de huidige tarieven, en begin met gratis proefcredit, zonder creditcard.