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

PHP 採集利器:URL 補全函數 FormatUrl(相對/絕對根路徑轉絕對全路徑)

     編輯:PHP 綜合知識

問題背景

網頁採集時,頁面鏈接常為相對路徑(../、./、無前綴)、絕對根路徑(/path/),需轉換為絕對全路徑(https://domain/path/)才能正確請求。

核心函數 FormatUrl

<?php
/**
 * 批量補全 HTML 中所有 href/src 鏈接為絕對 URL
 * @param string $html 原始 HTML
 * @param string $baseUrl 基礎 URL (如 https://www.jb51.net/)
 * @return string 處理後 HTML
 */
function formatUrl(string $html, string $baseUrl): string {
    // 正則匹配所有  和  (單雙引號)
    if (preg_match_all(
        '/(]+src=["\']([^"\']+)["\'][^>]*>)|(]+href=["\']([^"\']+)["\'][^>]*>)/i',
        $html, $matches, PREG_SET_ORDER
    )) {
        foreach ($matches as $m) {
            $wholeTag = $m[0];
            $url = $m[2] ?? $m[4]; // 提取 URL 部分
            $newUrl = resolveUrl($url, $baseUrl);
            $html = str_replace($wholeTag, str_replace($url, $newUrl, $wholeTag), $html);
        }
    }
    return $html;
}

/**
 * 單個 URL 解析補全
 */
function resolveUrl(string $url, string $baseUrl): string {
    // 1. 已是絕對 URL 或特殊協議,跳過
    if (preg_match('/^(https?|ftp):/i', $url)) return $url;
    if (preg_match('/^(mailto:|javascript:|#)/i', $url)) return $url;

    $parsed = parse_url($baseUrl);
    $scheme = $parsed['scheme'] . '://';
    $host = $parsed['host'];
    $base = $scheme . $host;
    $path = dirname($parsed['path'] ?? '/');
    if ($path === '\\' || $path === '.') $path = '';

    // 2. 絕對根路徑 /path/
    if ($url[0] === '/') return $base . $url;

    // 3. 相對路徑 ../ 或 ./
    if (str_starts_with($url, '../')) {
        while (str_starts_with($url, '../')) {
            $url = substr($url, 3);
            $path = dirname($path);
        }
        return $base . ($path ? "/$path" : '') . '/' . $url;
    }
    if (str_starts_with($url, './')) {
        $url = substr($url, 2);
        return $base . ($path ? "/$path" : '') . '/' . $url;
    }

    // 4. 無前綴相對路徑
    return $base . ($path ? "/$path" : '') . '/' . $url;
}

// 使用示例
$base = 'https://www.jb51.net/';
$html = '<a href="/index.htm">首頁</a><a href="Resolvent/index.htm">方案</a>';
echo formatUrl($html, $base);
// 輸出: 首頁方案

功能覆蓋表

原始 URL 類型示例補全結果 (基礎 https://a.com/dir/)
絕對 URLhttps://b.com/x.jpg保持不變
絕對根路徑/img/logo.pnghttps://a.com/img/logo.png
相對父目錄../style.csshttps://a.com/style.css
相對當前目錄./script.jshttps://a.com/dir/script.js
無前綴page.htmlhttps://a.com/dir/page.html
錨點#section保持 (或補全當前頁 URL)
JS/郵件協議javascript:; / mailto:a@b.com保持不變

進階優化建議

  1. 使用 DOMDocument 解析:比正則更健壯,自動處理屬性編碼、嵌套標簽、斷點 HTML。
  2. 基礎 URL 自動檢測:提取頁面 <base href=...> 或從響應 URL 推導。
  3. URL 規範化:移除多餘 ./、合併 //、處理 %20 等編碼。
  4. 異步批量處理:採集任務推隊列,Worker 並發執行 formatUrl。

DOMDocument 版本片段

<?php
function formatUrlDom(string $html, string $baseUrl): string {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    libxml_clear_errors();

    $xpath = new DOMXPath($dom);
    foreach ($xpath->query('//a[@href] | //img[@src] | //link[@href] | //script[@src]') as $node) {
        $attr = $node->hasAttribute('href') ? 'href' : 'src';
        $url = $node->getAttribute($attr);
        $node->setAttribute($attr, resolveUrl($url, $baseUrl));
    }
    return $dom->saveHTML();
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved