cURL로 만드는 PHP 캡차 솔버: 실전 예제 (2026)
PHP에서 캡차를 풀 때는 대부분의 설치에 기본으로 들어 있는 cURL 확장만 있으면 됩니다. Scarnox API에 JSON POST 요청 한 번을 보내고, 응답에서 solution.token을 읽은 뒤, 그 토큰을 사이트 폼에 제출하면 됩니다. 이 가이드는 Scarnox가 현재 프록시 없이 풀 수 있는 PopularCaptcha의 전체 PHP 흐름을 설명합니다.
무료 체험 크레딧으로 시작하세요. 카드 등록은 필요 없습니다. 다른 곳에 사용하기 전에, 내가 관리하는 페이지에서 스크립트를 먼저 시험해 보세요.
요구 사항
- PHP 8.0 이상,
curl과json확장 활성화.php -m으로 확인하세요. - Scarnox API 키.
- 페이지의 PopularCaptcha 위젯 sitekey. 찾는 방법은 캡차 sitekey 찾기를 참고하세요.
솔버 함수
이 함수는 API에 POST하고, errorId를 확인하고, 토큰을 반환합니다. 어떤 실패에서든 예외를 던지므로, 호출하는 쪽이 재시도 여부를 결정할 수 있습니다.
<?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, // 토큰이 준비되면 호출이 반환됩니다
]);
$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'];
}
Authorization 헤더에는 Bearer 접두사를 사용합니다. 타임아웃은 185초인데, API가 토큰이 준비될 때까지 블록되며 폴링 단계가 없기 때문입니다.
일시적인 실패 재시도하기
실패한 풀이는 청구되지 않으므로 몇 번 재시도하는 것은 저렴합니다. 호출을 루프로 감싸고, 실패할 때마다 조금 더 기다리세요.
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;
}
어떤 실패에서 멈출지를 포함한 완전한 오류 정책은 캡차 솔버 오류 처리를 참고하세요.
쿠키 파일로 토큰 제출하기
많은 사이트가 캡차를 폼을 불러온 세션에 묶어 둡니다. 쿠키 파일을 사용하면 cURL이 GET과 POST에서 같은 쿠키를 보낼 수 있습니다. 아래 함수는 토큰을 페이지의 폼에 제출합니다.
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// 먼저 GET 요청으로 사이트가 세션 쿠키를 설정하게 합니다.
$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);
// 그다음 두 캡차 필드에 토큰을 넣어 폼을 POST합니다.
$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;
}
중요한 점은 두 가지입니다. 쿠키가 준비되도록 GET이 풀이보다 먼저 실행됩니다. 그리고 토큰은 풀이 직후에 나가는데, 약 2분 뒤에 만료되기 때문입니다. 풀이 호출은 긴 배치의 시작이 아니라 이 함수 바로 앞에 두세요.
쿠키 파일은 같은 프로세스의 모든 호출이 공유합니다. 회원가입을 병렬로 여러 개 실행한다면 계정이나 세션마다 별도의 파일을 주세요. 그렇지 않으면 한 세션이 다른 세션의 쿠키를 덮어쓰고, 두 번째 POST는 캡차 문제처럼 보이지만 실제로는 다른 이유로 실패하게 됩니다.
모두 합치기
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
명령줄에서 실행하세요.
php signup.php
비가시형 위젯
위젯이 보이지 않는 형태라면 solveCaptcha($sitekey, $pageUrl, true)를 호출하세요. 그러면 요청과 함께 is_invisible 필드가 전송됩니다. 일부 페이지는 토큰과 함께 호출해야 하는 JavaScript 콜백도 필요로 하는데, 서버 측 스크립트로는 이를 트리거할 수 없습니다. 이런 경우에는 브라우저 도구를 사용하세요. 경우별 설명은 비가시형 캡차 가이드에 있습니다.
타이밍과 만료
토큰은 약 2분 동안 유효합니다. 풀이와 제출을 가깝게 유지하세요. 캡차 토큰 만료에서 만료된 토큰과 거부된 토큰을 구별하는 방법을 설명합니다.
스크래핑은 책임감 있게
PHP 스크립트가 공개 페이지를 스크래핑한다면, 시작하기 전에 robots.txt와 사이트 약관을 확인하세요. 요청 사이에 지연을 두고, 필요 없는 개인 데이터는 저장하지 마세요. 캡차를 푼다고 해서 수집할 수 있는 범위가 바뀌지는 않습니다. 법적인 측면은 웹 스크래핑은 합법인가를 참고하세요.
요금
성공한 풀이 건당 요금이 청구됩니다. 실패한 풀이는 청구되지 않습니다. 현재 요금은 요금 페이지를 참고하세요. 무료 체험 크레딧으로 시작하세요. 카드 등록은 필요 없습니다.