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

C# HTML 相對路徑轉絕對路徑:使用 MSHTML 解析與修正 href/src 屬性

     編輯:關於C語言

應用場景

爬蟲、郵件範本處理、CMS 內容儲存、離線瀏覽器等場景中,HTML 內容常包含相對路徑(如 /images/logo.png、../style.css)。儲存或轉發前,需將其解析為絕對 URL,確保資源正確載入。

核心實作

using System;
using mshtml; // 參考 COM: Microsoft HTML Object Library

public static string ConvertToAbsoluteUrls(string html, Uri baseUri)
{
    // 建立 DOM 文件
    IHTMLDocument2 doc = new HTMLDocumentClass();
    doc.write(new object[] { html });
    doc.close();

    // 處理所有 <a href>
    foreach (IHTMLAnchorElement anchor in doc.links)
    {
        IHTMLElement elem = (IHTMLElement)anchor;
        string href = (string)elem.getAttribute("href", 2);
        if (!string.IsNullOrEmpty(href))
        {
            Uri absolute = new Uri(baseUri, href);
            anchor.href = absolute.AbsoluteUri;
        }
    }

    // 處理所有 <img src>
    foreach (IHTMLImgElement img in doc.images)
    {
        IHTMLElement elem = (IHTMLElement)img;
        string src = (string)elem.getAttribute("src", 2);
        if (!string.IsNullOrEmpty(src))
        {
            Uri absolute = new Uri(baseUri, src);
            img.src = absolute.AbsoluteUri;
        }
    }

    return doc.body.innerHTML;
}

使用範例

string html = @"<a href='./page.html'>連結</a><img src='../images/logo.png' />";
Uri baseUri = new Uri("https://example.com/folder/");
string result = ConvertToAbsoluteUrls(html, baseUri);
// 結果:
// <a href="https://example.com/folder/page.html">連結</a>
// <img src="https://example.com/images/logo.png" />

依賴與部署注意事項

  • COM 參考:專案需加入「Microsoft HTML Object Library」(mshtml.dll),屬於非受控 COM 元件
  • 平台限制:需在 Windows 環境執行,註冊 mshtml.dll(IE 安裝自動註冊)
  • 32/64 位元:專案目標平台需與 mshtml.dll 位元數一致,或勾選「Prefer 32-bit」
  • 授權:mshtml 為 Windows 系統元件,一般應用無授權問題

現代替代方案(無 COM 依賴)

HtmlAgilityPack + 手動解析

using HtmlAgilityPack;

public static string ConvertUrlsModern(string html, Uri baseUri)
{
    var doc = new HtmlDocument();
    doc.LoadHtml(html);

    foreach (var a in doc.DocumentNode.SelectNodes("//a[@href]") ?? Enumerable.Empty())
    {
        string href = a.GetAttributeValue("href", "");
        if (Uri.TryCreate(baseUri, href, out Uri abs))
            a.SetAttributeValue("href", abs.AbsoluteUri);
    }

    foreach (var img in doc.DocumentNode.SelectNodes("//img[@src]") ?? Enumerable.Empty())
    {
        string src = img.GetAttributeValue("src", "");
        if (Uri.TryCreate(baseUri, src, out Uri abs))
            img.SetAttributeValue("src", abs.AbsoluteUri);
    }

    return doc.DocumentNode.OuterHtml;
}

優點:純 .NET、跨平台、無 COM 依賴、效能佳、支援 .NET Core / .NET 5+ / Linux Docker。

AngleSharp(現代 DOM 解析器)

using AngleSharp;
using AngleSharp.Dom;

public static async Task ConvertUrlsAsync(string html, Uri baseUri)
{
    var config = Configuration.Default;
    var context = BrowsingContext.New(config);
    var doc = await context.OpenAsync(req => req.Content(html));
    
    foreach (var a in doc.QuerySelectorAll("a[href]"))
    {
        if (Uri.TryCreate(baseUri, a.GetAttribute("href"), out Uri abs))
            a.SetAttribute("href", abs.AbsoluteUri);
    }
    foreach (var img in doc.QuerySelectorAll("img[src]"))
    {
        if (Uri.TryCreate(baseUri, img.GetAttribute("src"), out Uri abs))
            img.SetAttribute("src", abs.AbsoluteUri);
    }
    return doc.DocumentElement.OuterHtml;
}

Uri 類別解析規則補充

相對路徑基底 URI解析結果
page.htmlhttps://site.com/dir/https://site.com/dir/page.html
/page.htmlhttps://site.com/dir/https://site.com/page.html
../page.htmlhttps://site.com/dir/sub/https://site.com/dir/page.html
https://other.com/x.jpghttps://site.com/https://other.com/x.jpg(已為絕對,保持不變)

錯誤處理建議

try
{
    return ConvertToAbsoluteUrls(html, baseUri);
}
catch (UriFormatException ex)
{
    _logger.LogWarning(ex, "Invalid base URI or malformed HTML");
    return html; // 回傳原始內容
}
catch (COMException ex) when (ex.ErrorCode == -2147221164) // CLASS_E_CLASSNOTAVAILABLE
{
    _logger.LogError(ex, "mshtml.dll not registered");
    throw new InvalidOperationException("HTML parser unavailable", ex);
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved