現代網頁大量採用 AJAX 異步載入數據,**直接抓取首頁 HTML 只能得到空容器或 JS 代碼**。正確姿勢:使用瀏覽器開發者工具(Network 面板)定位真實 API 接口、請求參數、Header,然後用 cURL 模擬該請求獲取結構化數據(通常為 JSON)。
目標頁:https://www.example.com/news/list,列表數據由 JS 異步載入。
Request URL: https://www.example.com/api/news/list
Request Method: POST
Request Headers:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://www.example.com/news/list
Cookie: PHPSESSID=abc123; user_trace_id=xyz
Form Data:
page: 1
page_size: 20
category_id: 101
_token: csrf_token_here
Response (JSON):
{ "code": 0, "data": { "list": [...], "total": 1500 } }
<?php
function fetchNewsList(int $page = 1, int $pageSize = 20, int $categoryId = 101): ?array {
$url = 'https://www.example.com/api/news/list';
// 必須攜帶的 Header(模擬瀏覽器 AJAX 特徵)
$headers = [
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With: XMLHttpRequest',
'Referer: https://www.example.com/news/list',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
// 'Cookie: PHPSESSID=abc123; user_trace_id=xyz', // 若需登錄態
];
$postData = http_build_query([
'page' => $page,
'page_size' => $pageSize,
'category_id' => $categoryId,
// '_token' => getCsrfToken(), // 若有 CSRF 需先獲取
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_ENCODING => 'gzip, deflate', // 自動解壓
]);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno !== CURLE_OK) {
error_log("cURL Error [$errno]: $error");
return null;
}
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("JSON Decode Error: " . json_last_error_msg());
return null;
}
return $data['data']['list'] ?? [];
}
// 使用
$news = fetchNewsList(1, 20, 101);
foreach ($news as $item) {
echo $item['title'] . PHP_EOL;
}
?>
<meta name="csrf-token"> 或表單隱藏字段,再帶入 API 請求。encrypt(data, publicKey)。選項:① PHP 端用 OpenSSL 實現同算法;② 嵌入 V8JS/QuickJS 執行原 JS;③ 改用 Headless Chrome (Puppeteer/PHP-WebDriver)。<?php
$cookieJar = sys_get_temp_dir() . '/cookies_' . md5($domain) . '.txt';
// 1. 登錄獲取 Cookie
$ch = curl_init('https://example.com/login');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => ['username' => $user, 'password' => $pass],
CURLOPT_COOKIEJAR => $cookieJar, // 保存 Cookie
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
curl_close($ch);
// 2. 後續請求攜帶 Cookie
$ch = curl_init('https://example.com/api/private/data');
curl_setopt_array($ch, [
CURLOPT_COOKIEFILE => $cookieJar, // 讀取 Cookie
CURLOPT_RETURNTRANSFER => true,
]);
$data = curl_exec($ch);
curl_close($ch);
?>
| 策略 | 應對 |
|---|---|
| User-Agent 檢測 | 設置真實瀏覽器 UA,輪換池 |
| Referer/Origin 檢測 | 設置正確 Referer、Origin |
| 請求頻率限制 | 隨機延遲、IP 代理池、分散式爬蟲 |
| JS 生成簽名/Token | 逆向算法、V8JS、Headless Chrome |
| 字體加密/圖形驗證碼 | OCR 識別、字體映射表、打碼平台 |
| 行為分析(鼠標軌跡、點擊) | Headless Chrome + 模擬操作 |
robots.txt、網站服務條款 (ToS)。