目前筆者知道的 C# 抓取網頁資料的第三方套件最大的兩個是 AngleSharp 和 HtmlAgilityPack 
簡易比較如下:
  
    
(統計時間: 2023-03-22)
雖然 HtmlAgilityPack 下載量比較多,但上次更新是 2022 年 8 月 24 日,而 AngleSharp 是 2023 年 2 月,並且 AngleSharp 在 Github 上比較活躍,版本上也支援到 .NET 6 ,且屬於 .NET 基金會(.NET Foundation),故筆者選擇 AngleSharp,或許有機會再來試試看 HtmlAgilityPack
這個網站就是在蒐集歷史檔案,今天的範例就是使用 AngleSharp 套件將所有 Gif 檔案下載下來
上面是取回所有圖片連結,下載的部分則是使用 HttpClient:
註: """ 為 C# 11 語法,名稱為: 原始字串常值
爬取程式碼:
範例輸出:
參考資料:
Github - AngleSharp
AngleSharp Documentation
簡易比較如下:
| 套件 | 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 | 
雖然 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
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com