玩转C#网页抓取
網頁抓取是通過自動化手段檢索數據的過程。它在許多場景中都是不可或缺的,例如競爭對手價格監控、房地產清單列表、潛在客戶和輿情監控、新聞文章或金融數據聚合等。 如果您想了解更多相關信息,可以前往Oxylabs中文官網Oxylabs.cn參見我們的文章“網絡抓取合法嗎?”
在編寫網頁抓取代碼時,您要做出的第一個決定是選擇您的編程語言。您可以使用多種語言進行編寫,例如Python、JavaScript、Java、Ruby或C#。所有提到的語言都提供強大的網絡抓取功能。
在本文中,我們將探索C#并向您展示如何創建一個真實的C#公共網絡爬蟲。請記住,即使我們使用C#,您也可以將此信息調整為.NET平臺支持的所有語言,包括VB.NET和F#。
01.C#網頁抓取工具
在編寫任何代碼之前,第一步是選擇合適的C#庫或包。這些C#庫或包將具有下載HTML頁面、解析它們以及從這些頁面中提取所需數據的功能。一些最流行的C#包如下:
●ScrapySharp
●Puppeteer Sharp
●Html Agility Pack
Html Agility Pack是最受歡迎的C#包,僅Nuget就有近5,000萬次下載。其流行有多種原因,其中最重要的原因是該HTML解析器能夠直接或使用瀏覽器下載網頁。這個包可以容忍格式錯誤的HTML并支持XPath。此外,它甚至可以解析本地HTML文件;因此,我們將在本文中進一步使用這個包。
ScrapySharp為C#編程添加了更多功能。這個包支持CSS選擇器并且可以模擬網絡瀏覽器。雖然ScrapySharp被認為是一個強大的C#包,但程序員使用它進行維護的概率并不是很高。
Puppeteer Sharp是著名的Node.js Puppeteer項目的.NET端口。它使用相同的Chromium瀏覽器來加載頁面。此外,這個包采用了async-await風格的代碼,支持異步及預操作管理。如果您已經熟悉這個C#包并且需要一個瀏覽器來呈現頁面,那么Puppeteer Sharp可能是一個不錯的選擇。
02.使用C#構建網絡爬蟲
如前所述,現在我們將演示如何編寫將使用Html Agility Pack的C#公共網絡抓取代碼。我們將使用帶有Visual Studio Code的.NET 5 SDK。此代碼已在 .NET Core 3和.NET 5上測試過,它應該適用于其他版本的.NET。
我們將設置一個假設的場景:爬取一家在線書店并收集書名和價格。
在編寫C#網絡爬蟲之前,我們先來設置下開發環境。
03.設置開發環境
對于C#開發環境,請安裝Visual Studio Code。請注意,如果您使用Visual Studio和Visual Studio Code編寫C#代碼,則需要注意它們是兩個完全不同的應用程序。
安裝Visual Studio Code后,安裝.NET 5.0或更高版本。您還可以使用.NET Core 3.1。安裝完成后,打開終端并運行以下命令以驗證.NET CLI或命令行界面是否正常工作:
dotnet --version該行命令會輸出安裝的.NET的版本號。
04.項目結構和依存關系
該代碼將成為.NET項目的一部分。為簡單起見,創建一個控制臺應用程序。然后,創建一個文件夾,您將在其中編寫C#代碼。打開終端并導航到該文件夾。輸入以下命令:
dotnet new console此命令的輸出應該是已成功創建控制臺應用程序的信息。
到時間安裝所需的軟件包了。使用C#抓取公共網頁,Html Agility Pack將是一個不錯的選擇。您可以使用以下命令為該項目安裝它:
dotnet add package HtmlAgilityPack再安裝一個包,以便我們可以輕松地將抓取的數據導出到CSV文件:
dotnet add package CsvHelper如果您使用的是Visual Studio而不是Visual Studio Code,請單擊文件,選擇新建解決方案,然后按控制臺應用程序按鈕。要安裝依賴項,請按照下列步驟操作:
●選擇項目;
●單擊管理項目依賴項。這將打開NuGet包窗口;
●搜索HtmlAgilityPack并選擇它;
●最后,搜索CsvHelper,選擇它,然后單擊添加包。
Visual Studio中的Nuget包管理器
安裝了這些包后,我們可以繼續編寫用于抓取線上書店的代碼。
05.下載和解析網頁數據
任何網頁抓取程序的第一步都是下載網頁的HTML。此HTML將是一個字符串,您需要將其轉換為可以進一步處理的對象,也就是第二步,這部分稱為解析。Html Agility Pack可以從本地文件、HTML字符串、任何URL和瀏覽器讀取和解析文件。
在我們的例子中,我們需要做的就是從URL獲取HTML。Html Agility Pack沒有使用.NET本機函數,而是提供了一個方便的類–HtmlWeb.這個類提供了一個Load函數,它可以接受一個URL并返回一個HtmlDocument類的實例,它也是我們使用的包的一部分。有了這些信息,我們可以編寫一個函數,接受一個URL并返回HtmlDocument這個實例。
打開Program.cs文件并在類中輸入此函數Program:
// Parses the URL and returns HtmlDocument object static HtmlDocument GetDocument (string url) {HtmlWeb web = new HtmlWeb();HtmlDocument doc = web.Load(url);return doc; }這樣,代碼的第一步就完成了。下一步是解析文檔。
06.解析HTML:獲取書籍鏈接
在這部分代碼中,我們將從網頁中提取所需的信息。在這個階段,文檔現在是一個類型的對象HtmlDocument。這個類公開了兩個函數來選擇元素。這兩個函數都接受XPath輸入并返回HtmlNode or HtmlNodeCollection。
下面是這兩個函數的簽名:
public HtmlNodeCollection SelectNodes(string xpath); public HtmlNode SelectSingleNode(string xpath);我們就SelectNodes先討論一下。
對于這個例子——C#網絡爬蟲——我們將從這個頁面中抓取所有書籍的詳細信息。
首先,需要對其進行解析,以便可以提取到所有書籍的鏈接。在瀏覽器中打開上述的書店頁面,右鍵單擊任何書籍鏈接,然后單擊按鈕“檢查”。將打開開發人員工具。
在了解標記后,您要選擇的XPath應該是這樣的:
//h3/a現在可以將此XPath傳遞給SelectNodes函數。
HtmlDocument doc = GetDocument(url); HtmlNodeCollection linkNodes = doc.DocumentNode.SelectNodes("//h3/a");請注意,該SelectNodes函數是由
HtmlDocument的DocumentNode屬性調用的。
變量linkNodes是一個集合。我們可以寫一個foreach循環,并從每個鏈接一個一個地獲取href值。我們只需要解決一個小問題——那就是頁面上的鏈接是相對鏈接。因此,在我們抓取這些提取的鏈接之前,需要將它們轉換為絕對URL。
為了轉換相對鏈接,我們可以使用Uri該類。我們使用此構造函數來獲取Uri具有絕對URL的對象。
dotnet --version一旦我們有了Uri對象,我們就可以簡單地檢查該AbsoluteUri屬性以獲取完整的URL。
我們將所有這些寫在一個函數中,以保持代碼的組織性。
static List<string> GetBookLinks(string url) {var bookLinks = new List<string>();HtmlDocument doc = GetDocument(url);HtmlNodeCollection linkNodes = doc.DocumentNode.SelectNodes("//h3/a");var baseUri = new Uri(url);foreach (var link in linkNodes){string href = link.Attributes["href"].Value;bookLinks.Add(new Uri(baseUri, href).AbsoluteUri);}return bookLinks; }在這個函數中,我們從一個空List<string>對象開始。在foreach循環中,我們將所有鏈接添加到此對象并返回它。
現在,就可以修改Main()函數了,以便我們可以測試到目前為止編寫的C#代碼。修改函數如下:
static void Main(string[] args){var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");Console.WriteLine("Found {0} links", bookLinks.Count); }要運行此代碼,請打開終端并導航到包含此文件的目錄,然后鍵入以下內容:
dotnet run輸出應如下所示:
Found 20 links然后我們轉到下一部分,我們將處理所有鏈接以獲取圖書數據。
07.解析HTML:獲取書籍詳細信息
此時,我們有一個包含書籍URL的字符串列表。我們可以簡單地編寫一個循環,首先使用我們已經編寫的函數GetDocument來獲取文檔。之后,我們將使用該SelectSingleNode函數來提取書名和價格。
為了讓數據清晰有條理,我們從一個類開始。這個類將代表一本書,有兩個屬性-Title和Price.示例如下:
public class Book {public string Title { get; set; }public string Price { get; set; } }然后,為Title – //h1在瀏覽器中打開一個書頁。為價格創建 XPath 有點棘手,因為底部的附加書籍應用了相同的類。
價格的XPath
價格的XPath將是這樣的:
//div[contains(@class,"product_main")]/p[@class="price_color"]請注意,XPath包含雙引號。我們將不得不通過在它們前面加上反斜杠來轉義這些字符。
現在我們可以使用SelectSingleNode函數來獲取節點,然后使用InnerText屬性獲取元素中包含的文本。我們可以將所有內容放在一個函數中,如下所示:
static List<Book> GetBookDetails(List<string> urls) { var books = new List<Book>(); foreach (var url in urls){HtmlDocument document = GetDocument(url);var titleXPath = "//h1";var priceXPath = "//div[contains(@class,\"product_main\")]/p[@class=\"price_color\"]";var book = new Book();book.Title = document.DocumentNode.SelectSingleNode (priceXPath).InnerText;book.Price = document.DocumentNode.SelectSingleNode(priceXPath).InnerText;books.Add(book);} return books; }此函數將返回一個Book對象列表。是時候更新Main()函數了:
static void Main(string[] args) {var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");Console.WriteLine("Found {0} links", bookLinks.Count);var books = GetBookDetails(bookLinks); }這個網絡抓取項目的最后一部分是將數據導出為CSV。
08.導出數據
如果您尚未安裝CsvHelper,則可以通過
dotnet add package CsvHelper在終端內運行命令來完成此操作。
導出功能非常簡單。首先,我們需要創建一個StreamWriter并發送CSV文件名作為參數。接下來,我們將使用此對象創建一個CsvWriter.最后,我們可以使用該WriteRecords函數在一行代碼中編寫所有書籍。
為了確保所有資源都正確關閉,我們可以使用using塊。我們還可以將所有內容包裝在一個函數中,如下所示:
static void exportToCSV(List<Book> books) { using (var writer = new StreamWriter("./books.csv")) using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)){csv.WriteRecords(books);} }最后,我們可以從Main()函數中調用這個函數:
static void Main(string[] args) {var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");var books = GetBookDetails(bookLinks);exportToCSV(books); }要運行此代碼,請打開終端并運行以下命令:
dotnet run在幾秒鐘內,您將創建一個books.csv文件。
09.結論
如果您想用C#編寫一個網絡爬蟲,您可以使用多個包。在本文中,我們展示了如何使用Html Agility Pack,這是一個功能強大且易于使用的包。也是一個可以進一步增強的簡單示例;例如,您可以嘗試將上述邏輯添加到此代碼中以處理多個頁面。
如果您想了解更多有關使用其他編程語言進行網絡抓取的工作原理,可以查看使用Python進行網絡抓取的指南。我們還有一個關于如何使用JavaScript編寫網絡爬蟲的分步教程
常見問題
Q:C#適合網頁抓取嗎?
A:與Python類似,C#被廣泛用于網頁抓取。在決定選擇哪種編程語言時,選擇您最熟悉的一種至關重要。不過您將能夠在Python和C#中找到示例的網頁抓取工具。
Q:網絡抓取合法嗎?
A:如果在不違反任何法律的情況下使用代理,則它們可能是合法的。然而,在與代理進行任何活動之前,您應該就您的特定案件獲得專業的法律建議。
總結
- 上一篇: 淘宝 NPM 镜像解决软件下载速度慢的问
- 下一篇: python 内置模块 subproc