1. 程式人生 > >C# 網絡爬蟲利器之Html Agility Pack如何快速實現解析Html

C# 網絡爬蟲利器之Html Agility Pack如何快速實現解析Html

mlp get 設計 navig send 介紹 sca 元素 對象

簡介

  現在越來越多的場景需要我們使用網絡爬蟲,抓取相關數據便於我們使用,今天我們要講的主角Html Agility Pack是在爬取的過程當中,能夠高效的解析我們抓取到的html數據。

優勢

  在.NET技術下,解析html工具也很多,比如很多人可能會使用htmlparser,或者微軟的MSHTML,htmlparser雖然比較易上手,但是相對應的解析速度較慢,而Html Agility Pack解析速度相當快,並且開源,易用,它可以幫助我們解析html文檔就像用XmlDocument類來解析xml一樣輕松、方便。

  傳送門:官網地址,Github開源代碼地址

方法介紹

  其實Html Agility Pack的類不是很多,我們解析Html的時候,用到的也就HtmlDocument和HtmlNode(還有HtmlNodeCollection集合類)這幾個類。官網也有相對應的API文檔說明,其實真的是簡單易懂,傳送門:API文檔

Question 1、如何加載Html?

  HtmlDocument類定義; 多個重載Load方法來實現不同方式的Html加載,主要常見的有三種方式;從文件加載、從字符串加載、從網頁鏈接加載。

  示例:

 1 // 從物理路徑的文件加載
 2 var doc = new HtmlDocument();
 3 doc.Load(filePath);//文件路徑
 4 
 5 // 從Stream當中加載
 6 var doc = new HtmlDocument();
 7 doc.LoadHtml(html);
 8 
 9 // 從網頁的Url鏈接加載
10 var url = "http://www.cnblogs.com/xuliangxing/
"; 11 var web = new HtmlWeb(); 12 var doc = web.Load(url);

  以Stream對象為主的重載方法:

1public void Load(Stream stream)    ///從指定的Stream對象中加載html;2public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)    ///指定是否從順序字節流中解析編碼格式3public void Load(Stream stream, Encoding encoding)    ///指定編碼格式4
public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks) (5public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize) ///緩沖區大小

  以指定的物理路徑為主的重載方法:

1public void Load(string path)
(2public void Load(string path, bool detectEncodingFromByteOrderMarks)    ///指定是否從順序字節流中解析編碼格式3public void Load(string path, Encoding encoding)    ///指定編碼格式4public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)

Question 2、如何精準定位到我們需要的數據

  這個時候我們需要用到HtmlNodeCollection和HtmlNode這兩個類,我們把Html每個標簽看作一個Node,所有我們想到定位到某個標簽的內容,就需要知道這個標簽的相關屬性。順便說一下,HtmlNode類實現了IXPathNavigable接口,這說明了它可以通過xpath來定位數據了,如果你對解析XML格式數據的XmlDocument類了解的話,特別是使用過了SelectNodes()和SelectSingleNode()方法的人來說,對使用HtmlNode類將會很熟悉。其實Html Agility Pack內部是把html解析成xml文檔格式了的,所以支持xml中的一些常用查詢方式。下面通過簡單示例對HtmlNode的一些主要的常用成員作簡要的說明。

  就以我博客園主頁為例,希望大家在此基礎上能夠舉一反三,這裏只做拋磚引玉,界面圖如下:

技術分享圖片

  後臺Html代碼,我抓取了部分代碼拿來做示例

 1 <!DOCTYPE html>
 2 <html lang="zh-cn">
 3 <head>
 4 <meta charset="utf-8"/>
 5 <meta name="viewport" content="width=device-width, initial-scale=1" />
 6 <title>法號阿興 - 博客園</title>
 7 </head>
 8 <body>
 9 <div id="home">
10 <div id="header">
11     <div id="blogTitle">
12     <a id="lnkBlogLogo" href="http://www.cnblogs.com/xuliangxing/"><img id="blogLogo" src="/Skins/custom/images/logo.gif" alt="返回主頁" /></a>            
13     <h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法號阿興</a></h1>
14     <h2>你的能力還駕馭不了你的目標時,就應該沈下心來歷練</h2>
15     </div>   <!--end: blogTitle 博客的標題和副標題 -->
16     <div id="navigator">
17 <ul id="navList">
18     <li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客園</a></li>
19     <li><a id="blog_nav_myhome" class="menu" href="http://www.cnblogs.com/xuliangxing/">首頁</a></li>
20     <li><a href="http://news.cnblogs.com/">新聞</a></li>
21     <li><a id="blog_nav_newpost" class="menu" rel="nofollow" href="https://i.cnblogs.com/EditPosts.aspx?opt=1">新隨筆</a></li>
22     <li><a id="blog_nav_contact" accesskey="9" class="menu" rel="nofollow" href="https://msg.cnblogs.com/send/%E6%B3%95%E5%8F%B7%E9%98%BF%E5%85%B4">聯系</a></li>
23     <li><a id="blog_nav_admin" class="menu" rel="nofollow" href="https://i.cnblogs.com/">管理</a></li>
24     <li><a id="blog_nav_rss" class="menu" href="http://www.cnblogs.com/xuliangxing/rss">訂閱</a>
25     <a id="blog_nav_rss_image" class="aHeaderXML" href="http://www.cnblogs.com/xuliangxing/rss"><img src="//www.cnblogs.com/images/xml.gif" alt="訂閱" /></a></li>
26 </ul>
27 </div><!--end: header 頭部 -->
28 <div id="main"></div><!--end: 正文 -->
29 <div id="footer"></div><!--end: 底部 -->
30 </div>
31 </body>
32 </html>

  一般Html最常見的是div標簽元素,它可能會定義一些屬性,比例本文當中的<div id="blogTitle">,有些不是id屬性,是class屬性,這個根據實際情況而定,要靈活變通

(1)通過ID屬性(或者其他屬性)來選擇對應的節點

  通用格式:@id=‘xxxx’(id可以是其他屬性等等),比如我們要定位到本文博客主頁的標題和副標題內容。

1 HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
2 doc.LoadHtml(url)//博客主頁URL
3 //下面的意思是:通過屬性id的值,來定位header下的blogTitle節點信息
4 HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[@id=‘header‘]/div[@id=‘blogTitle‘]");

  我們還可以不通過屬性id去定位,還有通過索引去定位,如下所示,這個效果和上面是等同的:

1 //下面的意思是:通過索引定位,div[2]是表示根節點的第二個
2 HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[2]/div[1]");

  備註:註意路徑裏"//"表示從根節點開始查找,兩個斜杠‘//’表示查找所有childnodes;一個斜杠‘/‘表示只查找第一層的childnodes(即不查找grandchild);點斜杠"./"表示從當前結點而不是根結點開始查找。我們接著上面titleNode節點,查找我博客園的ID。

1 //下面的意思是:通過當前titleNode節點,獲取便簽h1的節點
2 HtmlNode IDNode = titleNode.SelectSingleNode("./h1");

  講解了上面這些,大家應該已經能夠明白了Html Agility Pack的基本使用方法,那麽如何一次性獲取博主的ID呢?

1 HtmlNode IDNode = doc.DocumentNode.SelectSingleNode("//div[@id=‘header‘]/div[@id=‘blogTitle‘]/h1");

(2)如何獲取節點文本內容

  接著上面(1)所說的,通過代碼“HtmlNode IDNode = doc.DocumentNode.SelectSingleNode("//div[@id=‘header‘]/div[@id=‘blogTitle‘]/h1") ”獲取到了IDNode的節點,那麽接下來,我們需要這麽獲取具體的文本值呢(即博主ID)?有三種方式獲取OuterHtml,InnerHtml和InnerText。

  HtmlNode類設計了OuterHtml屬性和InnerHtml屬性用於獲取當前節點的Html源碼。兩者不同之處是,OuterHtml屬性返回的是包含當前節點的Html代碼在內的所有Html代碼,而InnerHtml屬性返回的是當前節點裏面子節點的所有Html代碼,InnerText屬性過濾掉了所有的Html標記代碼,只返回文本值。具體用哪種方式,要根據我們實際情況而定,一般InnerHtml和InnerText使用的頻率比較多。如下所示:

1 //我們獲取博客ID
2 IDNode.OuterHtml ///返回結果是:<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法號阿興</a></h1>
3 IDNode.InnerHtml ///返回結果是:<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法號阿興</a>
4 IDNode.InnerText ///返回結果是:法號阿興

(3)如何獲取節點屬性值

  假如我們上面Html數據當中,博主博客地址,在標簽<div id="header">裏的<a>標簽裏,這個時候就需要使用HtmlNode下的Attribute屬性了。

1 string url = doc.DocumentNode.SelectSingleNode("//div[@id=‘header‘]/div[@id=‘blogTitle‘]/a").Attributes["href"].Value;

(4)如何獲取某個標簽的所有節點

  我們如果獲取前面Html數據的li所有分類,這個時候需要使用方法SelectNodes了

HtmlNodeCollection uiListNodes = doc.DocumentNode.SelectNodes("//ui[@id=‘navList‘]/li");

Question 3、Html Agility Pack進行刪除操作

  Html Agility Pack是可以對Html做刪除操作的,具體的可以參考官網的API,這裏我們講下最常見

(1)如何去掉外層的html tag只留下文本內容

  回到我們剛剛上面講到的地方,用remove方法。假設要刪除上文結點<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法號阿興</a>,你想留下博客名稱而不要<a></a>的話,那你需要先得到這個Html結點,通過remove方法刪除掉多余的HTML Tag假設該節點叫Node:

Node.ParentNode.RemoveChild(Node,true); 

  參數true表示留下grandchild,在這裏即博主博客ID內容; false表示將此結點連同其grandchilds一起刪除。

  更多的方法大家可以到官網的API文檔進行了解,這裏就不做更多的說明。

 PS:如有疑問,請留言,未經允許,不得私自轉載,轉載請註明出處:http://www.cnblogs.com/xuliangxing/p/8004403.html

技術分享圖片

技術分享圖片

C# 網絡爬蟲利器之Html Agility Pack如何快速實現解析Html