[轉貼] 通過HtmlAgilityPack+XPath來優化網頁採集

2018070810:57
今天特別學習和實踐了一下HtmlAgilityPack和XPath,並作下筆記。

1.下載HtmlAgilityPack.dll並將其添加引用到項目中,然後在代碼中聲明引用。
下載地址:http://www.codeplex.com/htmlagilitypack
引用:
using HtmlAgilityPack;

2.下載獲取HTML頁面的步驟和我上篇文章裡介紹的差不多,都是先用WebClient或者WebRequest類來下載HTML頁面然後處理成字符串。

3.與上次不同的是,這裡分析和抓取HTML節點中的數據不再是之前那種STRING字符串操作的方式,而是封裝成一個HtmlDocument對象,通過HtmlDocument中的方法來索引你需要抓取HTML節點,進而取出節點中的值。

4.若需要抓取的節點有ID,類似「<div id='post_list'>value</div>」這種,那很簡單只需調用GetElementbyId方法根據節點ID即可獲取所需節點。從而通過HtmlNode中的InnerText或Attribute屬性來獲取你想要的值。
CODE:
//實例化HtmlAgilityPack.HtmlDocument對像
HtmlDocument doc = new HtmlDocument();
//載入HTML
doc.LoadHtml(mainData);

//根據HTML節點NODE的ID獲取節點
HtmlNode navNode = doc.GetElementbyId("post_list");

5.但很多情況下HTML節點是沒有ID的,那就需要通過XPATH語言來查找匹配所需節點(XPath教程)。以抓取博客園首頁文章為例,通過查看博客園HTML可以發現博客園首頁裡的文章列表都是放在一個ID為"post_list"的"<div>"節點中的。
 
這樣的話就可以通過調用GetElementbyId方法來定位到這個節點了。

6.在獲取到"post_list"節點後,接下來就可以調用SelectSingleNode方法通過XPATH表達式來索引出需要抓取的節點,從而抓取到文章的標題和鏈接地址。
(PS:在博客園首頁"post_list"節點裡,平均每4個DIV就是一篇新的文章可以利用這一規律遍歷出首頁所有文章)
CODE:
//實例化HtmlAgilityPack.HtmlDocument對像
HtmlDocument doc = new HtmlDocument();
//載入HTML
doc.LoadHtml(mainData);

//根據HTML節點NODE的ID獲取節點
HtmlNode navNode = doc.GetElementbyId("post_list");
//根據XPATH來索引節點
//div[2]表示文章鏈接a位於post_list裡面第3個div節點中
HtmlNode navNode2 = navNode.SelectSingleNode("//div[2]/h3/a");
//獲取文章鏈接地址
string articleTitle = navNode2.Attributes["href"].Value.ToString();
//獲取文章標題
string articleName = navNode2.InnerText;
對比一下之前使用string截取字符串的方法:
//以"<a class=\"titlelnk\" href=\""作為抓取點開始採集
mainData=mainData.Substring(mainData.IndexOf("<a class=\"titlelnk\" href=\"") + 26);

//獲取文章頁面的鏈接地址
string articleAddr = mainData.Substring(0,mainData.IndexOf("\""));

//獲取文章標題
string articleTitle = mainData.Substring(mainData.IndexOf("target=\"_blank\">") + 16,
                                               mainData.IndexOf("</a>") - mainData.IndexOf("target=\"_blank\">") - 16);
可見與之前相比,使用HtmlAgilityPack.HtmlDocument類來實現前台HTML的分析和採集在頁面編碼和數據分析上面處理更加合理、優化,代碼也更加簡潔。

目前只是粗淺地學了一下HtmlAgilityPack提取HTML節點數值的應用,更多應用以及採集速度的優化處理等方面尚未仔細研究,還望高人指點。