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

PHP 使用 DOMDocument 解析網頁提取所有連結完整教學

     編輯:PHP 綜合知識

為什麼不用正則表達式?

HTML 結構複雜、巢狀、屬性順序不固定,正則表達式極難完整處理。PHP 內建 DOMDocument + DOMXPath 是標準、健壯的解析工具。

基本提取範例

<?php
$url = 'https://www.example.com';
$html = @file_get_contents($url); // @ 抑制警告,正式環境建議用 Guzzle/cURL

if ($html === false) {
    die("無法取得網頁內容");
}

$dom = new DOMDocument();
// 避免 HTML5 標籤/實體報錯
libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_clear_errors();

$xpath = new DOMXPath($dom);
$links = $xpath->query('//a[@href]'); // 所有擁有 href 屬性的 

$results = [];
foreach ($links as $link) {
    $href = $link->getAttribute('href');
    $text = trim($link->textContent);
    if ($href !== '' && $href !== '#') {
        // 轉為絕對網址
        $absolute = (parse_url($href, PHP_URL_SCHEME) ? $href : rtrim($url, '/') . '/' . ltrim($href, '/'));
        $results[] = ['url' => $absolute, 'text' => $text];
    }
}

print_r($results);

進階:過濾與分類連結

<?php
function extractLinks(string $html, string $baseUrl): array
{
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML($html);
    libxml_clear_errors();

    $xpath = new DOMXPath($dom);
    $anchors = $xpath->query('//a[@href]');

    $internal = [];
    $external = [];
    $assets = [];
    $mailto = [];
    $tel = [];

    foreach ($anchors as $a) {
        $href = trim($a->getAttribute('href'));
        if ($href === '' || $href === '#' || str_starts_with($href, 'javascript:')) continue;

        $text = trim($a->textContent);
        $parsed = parse_url($href);

        if ($parsed === false) continue; // 相對路徑 parse_url 會失敗

        if (isset($parsed['scheme'])) {
            // 絕對網址
            $host = $parsed['host'] ?? '';
            $baseHost = parse_url($baseUrl, PHP_URL_HOST);
            if ($host === $baseHost) {
                $internal[] = ['url' => $href, 'text' => $text];
            } else {
                $external[] = ['url' => $href, 'text' => $text];
            }
        } else {
            // 相對路徑 -> 轉絕對
            $absolute = rtrim($baseUrl, '/') . '/' . ltrim($href, '/');
            $internal[] = ['url' => $absolute, 'text' => $text];
        }

        // 特殊協定
        if (str_starts_with($href, 'mailto:')) $mailto[] = $href;
        if (str_starts_with($href, 'tel:')) $tel[] = $href;
        if (preg_match('/\.(css|js|png|jpg|jpeg|gif|svg|woff2?)$/i', $href)) $assets[] = $href;
    }

    return compact('internal', 'external', 'assets', 'mailto', 'tel');
}

// 使用
$links = extractLinks($html, 'https://www.example.com');
echo "站內連結: " . count($links['internal']) . "\n";
echo "外部連結: " . count($links['external']) . "\n";

效能優化建議

  1. 使用 cURL/Guzzle 取代 file_get_contents:支援逾時、重導向、Cookie、Header 自訂
  2. 限制解析範圍:$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD) 減少記憶體
  3. 大型頁面改用 XMLReader (SAX):串流式解析,不載入完整 DOM 樹
  4. 快取結果:同一 URL 短時間內勿重複抓取

常見問題排查

問題原因解決
中文亂碼網頁編碼非 UTF-8$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'auto'); 再 loadHTML
載入極慢/記憶體爆炸頁面過大 (數 MB)改用 XMLReader 或先用 regex 粗略擷取 <a 區塊
相對路徑轉換錯誤base href、./ ../ 處理使用 League\Uri 或手動實作 RFC 3986 解析
JavaScript 動態產生的連結抓不到DOMDocument 不執行 JS改用 Headless Chrome (Puppeteer/PHP-WebDriver)

法律與道德提醒

  • 遵守 robots.txt 與網站服務條款
  • 設定合理的 User-Agent、Rate Limit (如 1 req/sec)
  • 僅提取公開資料,勿繞過登入/驗證機制

掌握 DOMDocument + XPath,即可可靠地從任何靜態網頁提取結構化連結資料。

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