Bộ giải captcha bằng PHP với cURL: ví dụ hoạt động (2026)
PHP chỉ cần extension cURL, có sẵn trong hầu hết các bản cài đặt, để giải captcha. Bạn gửi một yêu cầu POST JSON đến API của Scarnox, đọc solution.token từ phản hồi, và submit token đó vào form của website. Hướng dẫn này đi qua toàn bộ luồng PHP cho PopularCaptcha, loại mà Scarnox giải hôm nay theo kiểu proxyless.
Bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ và thử script trên một trang bạn kiểm soát trước khi dùng nó ở nơi khác.
Yêu cầu
- PHP 8.0 trở lên, đã bật extension
curlvàjson. Kiểm tra bằngphp -m. - Một khóa API của Scarnox.
- Sitekey của widget PopularCaptcha trên trang. Để được hướng dẫn tìm nó, xem cách tìm sitekey của captcha.
Hàm bộ giải
Hàm này gửi yêu cầu đến API, kiểm tra errorId, và trả về token. Nó ném ngoại lệ khi có bất kỳ lỗi nào, để người gọi quyết định có thử lại hay không:
<?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ời gọi trả về khi token đã sẵn sàng
]);
$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'];
}
Header Authorization dùng tiền tố Bearer. Timeout là 185 giây vì API bị chặn cho đến khi token sẵn sàng, không có bước polling.
Thử lại các lỗi tạm thời
Một lần giải thất bại không bị tính phí, nên vài lần thử lại không tốn kém. Đặt vòng lặp quanh lời gọi và chờ lâu hơn một chút sau mỗi lần thất bại:
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;
}
Để có chính sách xử lý lỗi đầy đủ, bao gồm những lỗi nào nên dừng, xem xử lý lỗi bộ giải captcha.
Submit token với cookie jar
Nhiều website gắn captcha với phiên đã tải form. Một file cookie cho phép cURL gửi cùng các cookie trong GET và POST. Hàm dưới đây submit token vào form của trang:
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// GET trước, để website đặt cookie phiên.
$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);
// Sau đó POST form với token ở cả hai trường 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;
}
Có hai điều quan trọng. GET chạy trước khi giải để cookie đã có sẵn. Và token được gửi ngay sau khi giải, vì nó hết hạn trong khoảng hai phút. Hãy đặt lời gọi giải ngay trước hàm này, không phải ở đầu một lô dài.
File cookie được dùng chung bởi mọi lời gọi trong cùng một tiến trình, nên hãy cấp cho mỗi tài khoản hoặc phiên một file riêng nếu bạn chạy nhiều đăng ký song song. Nếu không, một phiên có thể ghi đè cookie của phiên khác, và POST thứ hai sẽ thất bại vì những lý do trông giống vấn đề captcha nhưng thực ra không phải.
Ghép lại
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
Chạy từ dòng lệnh:
php signup.php
Widget ẩn
Nếu widget là ẩn, hãy gọi solveCaptcha($sitekey, $pageUrl, true). Trường is_invisible khi đó được gửi cùng yêu cầu. Một số trang cũng cần một callback JavaScript được gọi với token, mà script phía máy chủ không thể kích hoạt. Trong trường hợp đó, hãy dùng công cụ trình duyệt thay thế. Hướng dẫn captcha ẩn bao quát các trường hợp.
Thời gian và hết hạn
Token có hiệu lực trong khoảng hai phút. Giữ việc giải và việc submit gần nhau. Hết hạn token captcha giải thích cách phân biệt token đã hết hạn với token bị từ chối.
Thu thập dữ liệu có trách nhiệm
Nếu script PHP của bạn thu thập các trang công khai, hãy kiểm tra robots.txt và điều khoản của website trước khi bắt đầu. Thêm độ trễ giữa các yêu cầu, và đừng lưu dữ liệu cá nhân mà bạn không cần. Việc giải captcha không thay đổi những gì bạn được phép thu thập. Về khía cạnh pháp lý, xem web scraping có hợp pháp không.
Giá
Bạn trả tiền theo mỗi lần giải thành công. Các lần giải thất bại không bị tính phí. Xem bảng giá hiện tại để biết mức phí hiện tại, và bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ.