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

簡介

  如今愈來愈多的場景須要咱們使用網絡爬蟲,抓取相關數據便於咱們使用,今天咱們要講的主角Html Agility Pack是在爬取的過程中,可以高效的解析咱們抓取到的html數據。html

優點

  在.NET技術下,解析html工具也不少,好比不少人可能會使用htmlparser,或者微軟的MSHTML,htmlparser雖然比較易上手,可是相對應的解析速度較慢,而Html Agility Pack解析速度至關快,而且開源,易用,它能夠幫助咱們解析html文檔就像用XmlDocument類來解析xml同樣輕鬆、方便。node

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

方法介紹

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

Question 一、如何加載Html?web

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

  示例:網絡

 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)    ///指定編碼格式4public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)  ///緩衝區大小

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

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 二、如何精準定位到咱們須要的數據ui

  這個時候咱們須要用到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 三、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

相關文章
相關標籤/搜索