Solver captcha w PHP z cURL: działający przykład (2026)
Do rozwiązania captcha w PHP wystarczy rozszerzenie cURL, które jest w większości instalacji. Wysyłasz jedno żądanie POST z JSON do API Scarnox, odczytujesz solution.token z odpowiedzi i przesyłasz ten token do formularza strony. Ten przewodnik przechodzi przez pełny przepływ w PHP dla PopularCaptcha, które Scarnox dziś rozwiązuje bez proxy.
Zacznij od darmowego kredytu próbnego, bez karty i wypróbuj skrypt na stronie, którą kontrolujesz, zanim użyjesz go gdziekolwiek indziej.
Wymagania
- PHP 8.0 lub nowszy, z włączonymi rozszerzeniami
curlijson. Sprawdź poleceniemphp -m. - Klucz API Scarnox.
- Sitekey widżetu PopularCaptcha na stronie. Pomoc w jego znalezieniu znajdziesz w artykule jak znaleźć sitekey captcha.
Funkcja solvera
Ta funkcja wysyła żądanie do API, sprawdza errorId i zwraca token. Przy każdym błędzie rzuca wyjątek, więc wywołujący może zdecydować, czy ponowić:
<?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, // wywołanie zwraca wynik, gdy token będzie gotowy
]);
$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'];
}
Nagłówek Authorization używa prefiksu Bearer. Timeout wynosi 185 sekund, bo API blokuje się, aż token będzie gotowy, bez etapu odpytywania.
Ponawianie przejściowych błędów
Nieudane rozwiązanie nie jest naliczane, więc kilka ponowień jest tanie. Umieść pętlę wokół wywołania i czekaj trochę dłużej po każdym błędzie:
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;
}
Pełną politykę błędów, w tym to, przy których błędach się zatrzymać, znajdziesz w artykule obsługa błędów solvera captcha.
Wysłanie tokenu z cookie jar
Wiele serwisów wiąże captcha z sesją, która załadowała formularz. Plik ciasteczek pozwala cURL wysłać te same ciasteczka przy GET i POST. Poniższa funkcja wysyła token do formularza strony:
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// Najpierw GET, aby serwis ustawił ciasteczko sesji.
$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);
// Następnie POST formularza z tokenem w obu polach 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;
}
Liczą się dwie rzeczy. GET wykonuje się przed rozwiązaniem, żeby ciasteczko było na miejscu. Token jest wysyłany zaraz po rozwiązaniu, bo wygasa po około dwóch minutach. Umieść wywołanie solvera bezpośrednio przed tą funkcją, a nie na początku długiej partii.
Plik ciasteczek jest współdzielony przez wszystkie wywołania w tym samym procesie, więc jeśli uruchamiasz kilka rejestracji równolegle, daj każdemu kontu lub sesji osobny plik. W przeciwnym razie jedna sesja nadpisze ciasteczka drugiej, a drugi POST zawiedzie z przyczyn, które wyglądają na problem z captcha, ale nim nie są.
Składamy całość
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
Uruchom z wiersza poleceń:
php signup.php
Niewidoczne widżety
Jeśli widżet jest niewidoczny, wywołaj solveCaptcha($sitekey, $pageUrl, true). Pole is_invisible zostanie wtedy wysłane z żądaniem. Niektóre strony wymagają też wywołania zwrotnego JavaScript z tokenem, którego skrypt po stronie serwera nie może uruchomić. W takim przypadku użyj narzędzia przeglądarkowego. Przewodnik o niewidocznej captcha omawia te przypadki.
Czas i wygasanie
Token jest ważny przez około dwie minuty. Trzymaj rozwiązanie i wysłanie blisko siebie. Wygasanie tokenu captcha wyjaśnia, jak odróżnić token wygasły od odrzuconego.
Scrapuj odpowiedzialnie
Jeśli Twój skrypt PHP scrapuje publiczne strony, sprawdź robots.txt i regulamin serwisu przed startem. Dodaj opóźnienie między żądaniami i nie przechowuj danych osobowych, których nie potrzebujesz. Rozwiązanie captcha nie zmienia tego, co wolno Ci zbierać. Stronę prawną omawia artykuł czy web scraping jest legalny.
Cennik
Płacisz za każde udane rozwiązanie. Nieudane rozwiązania nie są naliczane. Aktualne stawki znajdziesz na stronie cennika, Aby zacząć, odbierz darmowy kredyt próbny, bez karty.