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

PHP 擷取網頁所有超連結:DOMDocument 解析、相對轉絕對 URL、異步並發採集

     編輯:PHP 相關知識

健壯解析:DOMDocument + XPath (推薦)

<?php
function extractLinks(string $url, array $options = []): array {
    $opts = array_merge([
        'timeout' => 10,
        'user_agent' => 'Mozilla/5.0 (compatible; LinkBot/1.0)',
        'max_redirects' => 5,
        'follow_location' => true,
    ], $options);

    $ctx = stream_context_create([
        'http' => [
            'timeout' => $opts['timeout'],
            'user_agent' => $opts['user_agent'],
            'max_redirects' => $opts['max_redirects'],
            'follow_location' => $opts['follow_location'],
            'ignore_errors' => true, // 取得錯誤頁面內容
        ],
        'ssl' => ['verify_peer' => false, 'verify_peer_name' => false], // 開發測試用,生產請驗證
    ]);

    $html = @file_get_contents($url, false, $ctx);
    if ($html === false) {
        throw new RuntimeException("無法取得內容: $url");
    }

    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML('' . $html); // 強制 UTF-8
    libxml_clear_errors();

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

    $baseUrl = $url; // 可改用  標籤或最終 URL
    $result = [];

    foreach ($links as $a) {
        $href = $a->getAttribute('href');
        $text = trim($a->textContent);

        // 過濾空、錨點、javascript:, mailto:, tel:
        if ($href === '' || $href[0] === '#' || preg_match('/^(javascript|mailto|tel):/i', $href)) continue;

        // 相對轉絕對
        $absolute = resolveUrl($baseUrl, $href);

        $result[] = [
            'url' => $absolute,
            'text' => $text,
            'title' => $a->getAttribute('title'),
            'rel' => $a->getAttribute('rel'),
        ];
    }
    return $result;
}

function resolveUrl(string $base, string $relative): string {
    $baseParts = parse_url($base);
    if (strpos($relative, '://') !== false) return $relative; // 已是絕對
    if ($relative[0] === '/') {
        return $baseParts['scheme'] . '://' . $baseParts['host'] . $relative;
    }
    // 相對路徑
    $basePath = dirname($baseParts['path'] ?? '/');
    return $baseParts['scheme'] . '://' . $baseParts['host'] . $basePath . '/' . $relative;
}
?>

進階:並發採集 (Swoole / Fibers / Guzzle Promise)

<?php
// Swoole 協程並發 (需 Swoole 擴展)
use Swoole\Coroutine;
use function Swoole\Coroutine\run;

$urls = ['https://a.com', 'https://b.com', 'https://c.com'];

run(function () use ($urls) {
    $chan = new Swoole\Coroutine\Channel(count($urls));
    foreach ($urls as $url) {
        Coroutine::create(function () use ($url, $chan) {
            try {
                $links = extractLinks($url);
                $chan->push(['url'=>$url, 'links'=>$links, 'error'=>null]);
            } catch (Throwable $e) {
                $chan->push(['url'=>$url, 'links'=>[], 'error'=>$e->getMessage()]);
            }
        });
    }
    $results = [];
    for ($i=0; $ipop();
    }
    print_r($results);
});
?>

反爬蟲與禮儀 (必遵守)

  1. 檢查 robots.txt:`User-agent: *` `Disallow: /private/`。
  2. 限制頻率:同域名請求間隔 ≥ 1-2 秒,使用 Token Bucket / Leaky Bucket 演算法。
  3. 設定 User-Agent:標識爬蟲身分,提供聯絡方式。
  4. 處理錯誤/重導向/驗證碼:指數退避重試、Cookie 持久化、驗證碼識別/人工介入。
  5. 法律風險:條款禁止爬取、個資法、著作權、計算機欺詐濫用法 (CFAA) 等。**授權優先**。

現代替代:Headless Browser (Puppeteer/Playwright/PHP WebDriver)

JS 渲染頁面、SPA、無限滾動、動態載入需瀏覽器引擎。PHP 可透過 `php-webdriver` 驅動 Chrome/Firefox Headless,或呼叫 Node.js 微服務。

總結

擷取超連結核心:**DOMDocument 解析 HTML (非正則)、相對轉絕對 URL、過濾無效連結**。採集系統需具備**並發控制、頻率限制、錯誤重試、法律合規**。JS 重度頁面改用 Headless Browser。

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