首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 打造專屬搜尋引擎:Google 代理抓取與結果重構實戰

     編輯:PHP 相關知識

專案背景與架構思路

自建全文搜尋引擎成本極高(爬蟲、索引、排序、儲存)。替代方案:元搜尋引擎 —— 代理用戶請求至成熟引擎(Google),解析回應,重構呈現。核心流程:

  1. 前端表單提交關鍵字
  2. PHP 後端模擬瀏覽器 GET 請求 Google
  3. 解析 HTML 回應,提取標題、連結、摘要
  4. 重構輸出自有樣式,去除廣告/追蹤/導航雜訊

Google 搜尋請求協議分析

訪問 https://www.google.com/search?q=關鍵字,關鍵參數:

  • q:查詢字串(需 urlencode)
  • hl:介面語言(zh-TW, en)
  • gl:地區(tw, us)
  • num:每頁結果數(預設 10,最大 100)
  • start:分頁偏移(0, 10, 20...)

反爬蟲機制:User-Agent 檢查、IP 速率限制、驗證碼、動態渲染(JavaScript 生成結果)。簡單 file_get_contents 易被封鎖,生產級需使用 cURL + 完整 Header + Cookie 池 + 代理 IP + 延遲/隨機間隔。

PHP 實作核心代碼

1. 前端表單 search.html

<form method="get" action="search.php">
  <input type="text" name="q" placeholder="輸入搜尋關鍵字" required>
  <input type="hidden" name="hl" value="zh-TW">
  <button type="submit">搜尋</button>
</form>

2. 後端代理 search.php

<?php
function googleSearch(string $query, int $start = 0, string $hl = 'zh-TW'): array {
    $url = 'https://www.google.com/search';
    $params = [
        'q' => $query,
        'hl' => $hl,
        'start' => $start,
        'num' => 10,
    ];
    
    $ch = curl_init($url . '?' . http_build_query($params));
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_TIMEOUT => 15,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        CURLOPT_HTTPHEADER => [
            'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language: zh-TW,zh;q=0.9,en;q=0.8',
            'Accept-Encoding: gzip, deflate, br',
            'Connection: keep-alive',
            'Upgrade-Insecure-Requests: 1',
        ],
        CURLOPT_COOKIEJAR => '/tmp/google_cookies.txt',
        CURLOPT_COOKIEFILE => '/tmp/google_cookies.txt',
        CURLOPT_ENCODING => 'gzip, deflate',
    ]);
    
    $html = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    
    if ($httpCode !== 200 || $error) {
        throw new RuntimeException("Google 請求失敗: HTTP $httpCode, $error");
    }
    
    return parseGoogleResults($html);
}

function parseGoogleResults(string $html): array {
    libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $dom->loadHTML('' . $html);  // 強制 UTF-8
    $xpath = new DOMXPath($dom);
    
    $results = [];
    // Google 結果容器選擇器(需隨版本更新調整)
    $nodes = $xpath->query('//div[@class="g"]');  // 經典結構
    // 現代結構可能為 //div[@data-hveid] 或 //div[contains(@class, "MjjYud")]
    
    foreach ($nodes as $node) {
        $titleNode = $xpath->query('.//h3', $node)->item(0);
        $linkNode = $xpath->query('.//a[@href]', $node)->item(0);
        $snippetNode = $xpath->query('.//div[@class="VwiC3b"] | .//span[@class="st"] | .//div[contains(@class, "aCOpRe")]', $node)->item(0);
        
        if (!$titleNode || !$linkNode) continue;
        
        $title = trim($titleNode->textContent);
        $url = $linkNode->getAttribute('href');
        $snippet = $snippetNode ? trim($snippetNode->textContent) : '';
        
        // 過濾 Google 內部連結
        if (strpos($url, '/url?q=') === 0) {
            parse_str(parse_url($url, PHP_URL_QUERY), $qs);
            $url = $qs['q'] ?? $url;
        }
        if (strpos($url, 'google.com') !== false) continue;
        
        $results[] = [
            'title' => $title,
            'url' => $url,
            'snippet' => $snippet,
        ];
    }
    return $results;
}

// 主程式
try {
    $query = $_GET['q'] ?? '';
    $start = (int)($_GET['start'] ?? 0);
    if ($query) {
        $results = googleSearch($query, $start);
    }
} catch (Exception $e) {
    $error = $e->getMessage();
}
?>
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>搜尋結果</title></head><body>
<form method="get"><input name="q" value="<?= htmlspecialchars($query) ?>"><button>搜尋</button></form>
<?php if (!empty($error)): ?><div class="error"><?= $error ?></div><?php endif; ?>
<?php if (!empty($results)): ?>
  <ol>
  <?php foreach ($results as $i => $r): ?>
    <li>
      <h3><a href="<?= $r['url'] ?>" target="_blank" rel="noopener"><?= htmlspecialchars($r['title']) ?></a></h3>
      <p><?= htmlspecialchars($r['snippet']) ?></p>
      <cite><?= $r['url'] ?></cite>
    </li>
  <?php endforeach; ?>
  </ol>
  <nav>
    <a href="?q=<?= urlencode($query) ?>&start=<?= $start-10 ?>" <?= $start==0?'style="visibility:hidden"':'' ?>>上一頁</a>
    <a href="?q=<?= urlencode($query) ?>&start=<?= $start+10 ?>">下一頁</a>
  </nav>
<?php endif; ?>
</body></html>

關鍵技術難點與對策

挑戰解決方案
Google HTML 結構頻繁變動建立多組 XPath 選擇器備援;監控 Google 官方部落格/SEO 社群變更;引入 Simple HTML DOM Parser 容錯解析
IP 被封鎖/驗證碼代理 IP 池輪換;請求間隔隨機化 (2-10秒);模擬真實瀏覽器指紋;遇驗證碼觸發人工/第三方打碼服務
動態渲染 (AJAX/JS)使用 Headless Chrome (Puppeteer/PHP-WebDriver) 執行 JS 後再解析;或分析 XHR 介面直接呼叫內部 API
法律/條款風險遵守 robots.txt、Terms of Service;添加 User-Agent 標識;提供移除請求管道;考慮使用官方 Custom Search JSON API (免費額度 100 次/日)
效能瓶頸結果快取 (Redis, 1-24小時);非同步預抓熱門查詢;前端 AJAX 分頁載入

進階替代方案:官方 API 與開源引擎

  1. Google Custom Search JSON API:官方、合法、結構化 JSON 回應、免費 100 次/日、付費擴展。
  2. Bing Web Search API:Microsoft Azure 市場,類似模式。
  3. Elasticsearch / Meilisearch / Typesense:自建全文搜尋,資料自主、即時索引、支援中文分詞、語義搜尋。
  4. SearXNG:開源元搜尋引擎,聚合 Google/Bing/DuckDuckGo 等,可自架、去中心化、隱私優先。

法律與道德提醒

大規模抓取搜尋引擎結果可能違反服務條款、著作權法、反爬蟲法(如美國 CFAA、歐盟 GDPR)。商業用途強烈建議使用官方 API 或自建索引。本文代碼僅供學習 HTTP 協議、HTML 解析、XPath 技術之用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved