提供兩個獨立 PHP 函數,透過抓取百度搜尋結果頁 HTML 並以正則/字串截取方式,解析出:
site:domain 查詢返回的「找到相關網頁約 X 頁」。domain 直接查詢,從結果中提取綠色字體顯示的快照時間 (如 37K 2008-9-13)。<?php
/**
* 百度 SEO 查詢工具類
* 注意:百度反爬極嚴格,簡單抓取極易失效,建議配合代理 IP、Headless Chrome 或官方 API 使用
*/
class BaiduSeoTools {
private $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
/** 通用抓取 */
private function fetch($url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20,
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => 'gzip,deflate', // 百度回傳壓縮內容
CURLOPT_COOKIEJAR => '', // 啟用記憶體 Cookie
]);
$html = curl_exec($ch);
$errno = curl_errno($ch);
curl_close($ch);
if ($errno) return false;
// 百度頁面通常為 UTF-8,若為 GBK 需轉碼
// if (mb_detect_encoding($html, 'GBK,UTF-8') === 'GBK') $html = mb_convert_encoding($html, 'UTF-8', 'GBK');
return $html;
}
/** 字串截取輔助:取 $start 和 $end 之間內容 */
private function cut($string, $start, $end) {
$pos1 = strpos($string, $start);
if ($pos1 === false) return '';
$pos1 += strlen($start);
$pos2 = strpos($string, $end, $pos1);
if ($pos2 === false) return '';
return substr($string, $pos1, $pos2 - $pos1);
}
/**
* 查詢收錄量
* @return string 數量字串 (已移除逗號) 或 "0"
*/
public function getIndexCount($domain) {
$url = "https://www.baidu.com/s?wd=site:" . urlencode($domain);
$html = $this->fetch($url);
if (!$html) return "0";
// 嘗試多種關鍵字模式 (百度頁面結構常變)
$patterns = [
'找到相關網頁約',
'找到相關網頁',
'百度為您找到相關結果約',
'results-num">', // 可能的 class
];
$endMarkers = ['頁', '個', '条', ''];
foreach ($patterns as $start) {
foreach ($endMarkers as $end) {
$num = $this->cut($html, $start, $end);
if ($num !== '') {
return str_replace(',', '', trim($num));
}
}
}
return "0";
}
/**
* 查詢首頁快照日期
* @return string 日期字串 (如 "2023-10-15") 或 "無"
*/
public function getSnapshotDate($domain) {
$url = "https://www.baidu.com/s?wd=" . urlencode($domain);
$html = $this->fetch($url);
if (!$html) return "無";
// 百度快照通常在綠色字體中:domain ... 37K 2023-10-15
// 嘗試定位域名後的綠色區塊
$startMarker = '' . $domain;
$snippet = $this->cut($html, $startMarker, '');
if ($snippet === '') {
// 備用:搜尋所有綠色字體
if (preg_match_all('/(.*?)<\/font>/is', $html, $m)) {
foreach ($m[1] as $snippet) {
if (stripos($snippet, $domain) !== false) break;
}
}
}
if ($snippet !== '') {
// 格式通常: "37K 2023-10-15" 或 "2023-10-15"
if (preg_match('/(\d{4}-\d{1,2}-\d{1,2})/', $snippet, $m)) {
return $m[1];
}
// 兼容舊格式 "2008-9-13"
if (preg_match('/(\d{4}-\d{1,2}-\d{1,2})/', $snippet, $m)) {
return $m[1];
}
}
return "無";
}
}
// ===== 使用範例 =====
$baidu = new BaiduSeoTools();
$domain = 'example.com';
echo "收錄量: " . $baidu->getIndexCount($domain) . PHP_EOL;
echo "快照日期: " . $baidu->getSnapshotDate($domain) . PHP_EOL;
?>
百度歷史頁面為 GBK 編碼,現代多為 UTF-8。建議抓取後統一檢測並轉為 UTF-8:
$encoding = mb_detect_encoding($html, 'GBK,UTF-8,BIG5');
if ($encoding !== 'UTF-8') $html = mb_convert_encoding($html, 'UTF-8', $encoding);
| 機制 | 特徵 | 應對策略 |
|---|---|---|
| IP 頻率限制 | 短時間大量請求回傳驗證碼/403 | 住宅代理 IP 池、請求間隔隨機化 (1-5秒)、分散式節點 |
| User-Agent 檢查 | 空 UA 或 Python/Go/Java 字樣直接封禁 | 使用真實瀏覽器完整 UA 字串,定期更新 |
| Cookie/Session 綁定 | 需攜帶有效 Cookie 才返回正常結果 | 預熱會話、維護 Cookie 池、模擬登入 |
| JS 渲染/加密參數 | 關鍵數據由 JS 解密填充、URL 參數加密 | Headless Chrome (Puppeteer/Playwright) / 逆向 JS 邏輯 |
| 字體加密 (Font Encryption) | 數字/文字對應自定義字體檔案 (WOFF) | 下載字體 -> 解析 cmap 表 -> 建立映射表 -> 替換解密 |
不要依賴脆弱的字串截取。推薦使用 symfony/dom-crawler 或 sunra/php-simple-html-dom-parser:
use Symfony\Component\DomCrawler\Crawler;
$crawler = new Crawler($html);
// 収錄量
$text = $crawler->filter('.nums_text, .result-stats, #result-stats')->text();
// 快照日期
$crawler->filter('font[color="#008000"], .c-color-gray, .g-time')->each(function (Crawler $node) use ($domain) {
if (stripos($node->text(), $domain) !== false) {
// 提取日期
}
});
百度提供 站長平台 (zhanzhang.baidu.com) 開放 API,可查詢:
/site/index)/keyword/rank)流程:驗證網站擁有權 -> 開通 API 權限 -> 獲取 Access Token -> 簽名請求。此為唯一合法、穩定、準確的數據來源。
本文提供的函數適合理解「搜尋引擎結果頁 (SERP) 解析」基本原理。生產環境下,請務必遷移至官方站長平台 API,或使用成熟的第三方 SEO 數據服務商 (如 DataForSEO、5118、愛站) 的 API,避免法律風險與維護地獄。