C# 使用 AngleSharp 套件製作網路爬蟲:下載網頁中的所有圖片

目前筆者知道的 C# 抓取網頁資料的第三方套件最大的兩個是 AngleSharpHtmlAgilityPack

簡易比較如下:
套件 AngleSharp 1.0.1 HtmlAgilityPack 1.11.46
.NET 支援 .NET 6.0、.NET Standard 2.0、.NET Framework 4.6.1 .NET Standard 1.3、.NET Framework 3.5
總下載量 60.5M 107.1M
目前版本下載量 157.4K 2.9M
平均每天下載量 16.9K 24.1K
Fork 數量 530 352
Stars 數量 4.6K 2.3K
(統計時間: 2023-03-22)

雖然 HtmlAgilityPack 下載量比較多,但上次更新是 2022 年 8 月 24 日,而 AngleSharp 是 2023 年 2 月,並且 AngleSharp 在 Github 上比較活躍,版本上也支援到 .NET 6 ,且屬於 .NET 基金會(.NET Foundation),故筆者選擇 AngleSharp,或許有機會再來試試看 HtmlAgilityPack

安裝

先使用 NuGet 安裝 AngleSharp 套件,或是使用 .NET CLI 執行以下指令安裝
	
dotnet add package AngleSharp
    

基本使用

筆者在逛 Hacker News 時發現了一個很有趣的網站: Please be patient - This Page is Under Construction!

這個網站就是在蒐集歷史檔案,今天的範例就是使用 AngleSharp 套件將所有 Gif 檔案下載下來
    
// 建立瀏覽器物件
var context = BrowsingContext.New(Configuration.Default.WithDefaultLoader());

// 目標連結:
string url = "http://textfiles.com/underconstruction/";

// 取得目標網頁的 HTML 內容
var document = await context.OpenAsync(url);

// 解析 HTML
var parser = new HtmlParser();
var html = parser.ParseDocument(document.ToHtml());

// 取得所有圖片連結
var images = html.Images.Select(l => l.GetAttribute("src")).ToList();

// 將圖片轉換為絕對路徑 url
var imageUrls = images.Select(image => new Uri(new Uri(url), image).AbsoluteUri).ToList();
    

上面是取回所有圖片連結,下載的部分則是使用 HttpClient:
    
// 檔案路徑
var path = @"C:\Users\ruyut\Desktop\images";

using var httpClient = new HttpClient();

// 下載所有檔案
foreach (var link in imageUrls)
{
    // 取得檔案名稱
    var fileName = Path.GetFileName(link);

    // 建立要下載的檔案路徑
    var filePath = Path.Combine(path, fileName);

    // 下載檔案
    var response = await httpClient.GetAsync(link);

    // 將檔案儲存到指定路徑
    using var fileStream = new FileStream(filePath, FileMode.Create);
    await response.Content.CopyToAsync(fileStream);

    Console.WriteLine($"Downloaded: {link}");
}
    

使用預存 HTML

測試時可以先擷取部分 html ,再使用下列方式讀取,就可以避免測試時一直呼叫實際連結
    

string html = """
<table>
	<tr id="35258877">
	</tr>
</table>
""";

var parser = new HtmlParser();
var document = parser.ParseDocument(html);
    

註: """ 為 C# 11 語法,名稱為: 原始字串常值

爬取資料範例

該如何定位元素呢? 就是使用 CSS 選擇器(也可以安裝套件後使用 XPath)來取得指定網頁元素,下面是爬取 Hacker News 網站的範例: 網頁內容節錄:
    
<tr id="35258877">
    <td class="title"><span class="rank">1.</span></td>
    <td class="votelinks" >
        <a id="up_35258877" href="vote?id=35258877&how=up&goto=news">
            <div class="votearrow" title="upvote"></div>
        </a>
    </td>
    <td class="title">
        <span class="titleline">
            <a href="https://amturing.acm.org/?2023">ACM Turing Award honors Bob Metcalfe for Ethernet</a>
            <span class="sitebit comhead"> (acm.org)
        </span>
        </span>
    </td>
</tr>
<tr>
    <td colspan="2"></td>
    <td class="subtext">
        <span class="subline">
          378 points by robbiet480 4 hours ago | hide | 102 comments
        </span>
    </td>
</tr>
    

爬取程式碼:
    
var context = BrowsingContext.New(Configuration.Default.WithDefaultLoader());

// 目標連結:
string url = "https://news.ycombinator.com/";

// 取得目標網頁的 HTML 內容
var document = await context.OpenAsync(url);

// 選擇所有包含 id 屬性的 tr 元素
var trElements = document.QuerySelectorAll("tr[id]");

// 遍歷每個 tr 元素,並抽取 id、rank 和 title 屬性
foreach (var tr in trElements)
{
    var id = tr.GetAttribute("id");
    var rank = tr.QuerySelector(".title > .rank")?.TextContent;
    var title = tr.QuerySelector(".titleline")?.TextContent;

    // 文章連結
    var link = tr.QuerySelector(".titleline > a[href]")?.GetAttribute("href");

    // 標題下方的資訊
    var data = tr.NextElementSibling?.QuerySelector(".subline")?.TextContent.Trim();

    Console.WriteLine($"Id: {id} Rank: {rank} Title: {title}, Link: {link}, Data: {data}");
}
    

範例輸出:
    
Id: 35261065 Rank: 1. Title: GitHub Copilot X: The AI-powered developer experience (github.blog), Link: https://github.blog/2023-03-22-github-copilot-x-the-ai-powered-developer-experience/, Data: 186 points by todsacerdoti 49 minutes ago  | hide | 110?comments
Id: 35258877 Rank: 2. Title: ACM Turing Award honors Bob Metcalfe for Ethernet (acm.org), Link: https://amturing.acm.org/?2023, Data: 398 points by robbiet480 4 hours ago  | hide | 110?comments
Id: 35260401 Rank: 3. Title: The Simplicity of Single-File Golang Deployments (amazingcto.com), Link: https://www.amazingcto.com/simplicity-of-golang-systemd-deployments/, Data: 47 points by KingOfCoders 1 hour ago  | hide | 40?comments
Id: 35258553 Rank: 4. Title: Show HN: ChatLLaMA – A ChatGPT style chatbot for Facebook's LLaMA (baseten.co), Link: https://chatllama.baseten.co/, Data: 213 points by aaronrelph 5 hours ago  | hide | 110?comments
Id: 35260815 Rank: 5. Title: Launch HN: Flower (YC W23) – Train AI models on distributed or sensitive data, Link: item?id=35260815, Data: 17 points by niclane7 1 hour ago  | hide | 8?comments
    


參考資料:
Github - AngleSharp
AngleSharp Documentation

留言