.Net解析html文档类库HtmlAgilityPack完整使用说明
在前幾篇文章中([搜房網房產數據采集程序demo--GeckoWebBrowser實例]?)都有提到一個解析html的C#類庫HtmlAgilityPack,
今天終于有時間整理一下,并把Demo分享一下。
HtmlAgilityPack是一個基于.Net的、第三方免費開源的微型類庫,主要用于在服務器端解析html文檔(在B/S結構的程序中客戶端可以用Javascript、jquery解析html)。截止到本文發表時,HtmlAgilityPack的最新版本為?1.4.6。下載地址:http://htmlagilitypack.codeplex.com/。最新版本支持Linq?to?Objects?(?LINQ?to?Xml?).
準備:
如果你有安裝Nuget的話,可以直接查找安裝即可。
下載后解壓縮后有3個文件,這里只需要將其中的HtmlAgilityPack.dll(程序集)、HtmlAgilityPack.xml(文檔,用于Visual?Studio?2008中代碼智能提示和幫助說明之用)引入解決方案中即可使用,無需安裝任何東西,非常好用。
在C#類文件開頭引入using?HtmlAgilityPack;就可以使用該命名空間下的類型了。實際使用中,幾乎都是以HtmlDocument類為主線的,這一點非常類似于微軟.net?framework中的XmlDocument類。XmlDocument類是操作的是xml文檔,而HtmlDocument類操作的是html文檔(其實也可以操作xml文檔),它們的操作方式都是基于Dom,所不同的是后者取消了諸如GetElementsByTagName這樣的方法,強化了GetElementById方法(在HtmlDocument中可以直接使用,而XmlDocument則不可以)。
HtmlAgilityPack中定位節點基本上都用Xpath表達式,Xpath表達式的參考文檔可見:http://www.w3school.com.cn/xpath/xpath_syntax.asp。自行學習。
不過可以先用幾個簡單就可以。比如,我們用到最多可能就是針對某個元素(div)、或者某個class屬性的div、或者某個id的div,或者以什么開頭的div,
類似這樣的Xpath還是比較簡單的。
Xpath舉幾個例子,下面的代碼中我們就會用到:
| "//comment()"在XPath中表示“所有注釋節點” 1、獲取網頁title:doc.DocumentNode.SelectSingleNode("//title").InnerText;? 解釋:XPath中“//title”表示所有title節點。SelectSingleNode用于獲取滿足條件的唯一的節點。 2、獲取所有的超鏈接:doc.DocumentNode.Descendants("a") 3、獲取name為kw的input,也就是相當于getElementsByName(): ????????????var?kwBox?=?doc.DocumentNode.SelectSingleNode("//input[@name='kw']"); 解釋:"//input[@name='kw']"也是XPath的語法,表示:name屬性等于kw的input標簽。 //li/h3/a[@href]:所有li下面的h3包含a超級鏈接有href屬性才符合。有的a可能是支持的js事件 //div[starts-with(@class,'content_single')]:所有符合條件的div,并且它的class是由字符串content_single?開頭的。 | 
//標示獲取documet下的所有符合條件。/div標示從根目錄開始的符合條件的。
以上是準備工作。下面說一下HtmlAgilityPack讀取web頁面,并解析的方法步驟。
1.讀取url:
| ????????????????HtmlAgilityPack.HtmlWeb?hw?=?new?HtmlAgilityPack.HtmlWeb(); ????????????????HtmlAgilityPack.HtmlDocument?doccc?=?hw.Load(url);//是你需要解析的url ????????????????ArrayList?ImagePtahs?=?GetHrefs(doccc); | 
這里可能會遇到2個問題。
一個是編碼問題,一個是gzip不支持的問題。
首先編碼問題解決辦法:就是不用HtmlAgilityPack去獲取Url的data數據,自己獲取了。大家可能就問了:我自己獲取了他不給我解析那?
沒事,他不會那么笨的。誰的肉不是吃啊?
方法如下:
| ??????????????WebProxy?proxyObject?=?new?WebProxy(IP,?port);//這里我是用的代理。 ????????????????//向指定地址發送請求 ???????????????HttpWebRequest?HttpWReq?=?(HttpWebRequest)WebRequest.Create(url); ????????????????HttpWReq.Proxy?=?proxyObject; ????????????????HttpWReq.Timeout?=?10000; ????????????????HttpWebResponse?HttpWResp?=?(HttpWebResponse)HttpWReq.GetResponse();??????????????? ????????????????StreamReader?sr?=?new?StreamReader(HttpWResp.GetResponseStream(),?System.Text.Encoding.GetEncoding("UTF-8"));?????????????? ????????????????//注意上面的編碼了嗎?? ????????????????HtmlAgilityPack.HtmlDocument?doc?=?new?HtmlAgilityPack.HtmlDocument(); ????????????????doc.Load(sr); ????????????????int?res?=?CheckIsGoodProxy(doc);?//這是我解析的函數,還沒到那一步。不解釋了。 ????????????????sr.Close(); ????????????????HttpWResp.Close(); ????????????????HttpWReq.Abort(); | 
另一個問題就是很奇怪了。gzip的問題開啟了gzip壓縮的網頁請求時會報錯。報錯信息為“gzip”不是受支持的編碼名。
?在谷歌上搜索了半天,終于找到解決方案,而且不必更換HttpRequest或WebClient進行請求。同時還可以用此方法設置cookie,render偽裝等等。。。解決后代碼如下:在你發起請求的是修改一下。
| HtmlWeb?webClient?=?new?HtmlWeb(); HtmlAgilityPack.HtmlWeb.PreRequestHandler?handler?=?delegate(HttpWebRequest?request) { ???????request.Headers[HttpRequestHeader.AcceptEncoding]?=?"gzip,?deflate"; ???????request.AutomaticDecompression?=?DecompressionMethods.Deflate?|?DecompressionMethods.GZip; ???????request.CookieContainer?=?new?System.Net.CookieContainer(); ???????return?true; }; webClient.PreRequest?+=?handler; HtmlDocument?doc?=?webClient.Load(this.getUrl()); | 
可能最新版本的HtmlAgilityPack會修復這個問題吧。期待中。
2.用Xpath解析。
這一步就比較簡單了。就用Xpath選出你想要的數據,遍歷他們,取出他們的value即可。
實例代碼:
| ????private?ArrayList?GetHrefs(HtmlAgilityPack.HtmlDocument?_doc) ????????{ ????????????try ????????????{ ????????????????Images?=?new?ArrayList(); ????????????????HtmlNodeCollection?hrefs?=?_doc.DocumentNode.SelectNodes("//li/h3/a[@href]"); ???????????????????HtmlNodeCollection?hrefs2?=?_doc.DocumentNode.SelectNodes("//div[starts-with(@class,'content_single')]"); ????????????????if?(hrefs?==?null) ????????????????????return?new?ArrayList(); ????????????????foreach?(HtmlNode?href?in?hrefs) ????????????????{ ????????????????????//??Images.Add(href.Attributes["src"].Value); ????????????????????string?hreff?=?href.Attributes["href"].Value;//?排除??博海拾貝第二百零二期】吃完薯條寂寞了? ????????????????????string?title?=?href.Attributes["title"].Value; ??????????????????if?(title.IndexOf("邪惡")?>=?0) ????????????????????{ ????????????????????????continue; ????????????????????} ????????????????????if?(title.IndexOf("惡搞")?>=?0) ????????????????????{ ????????????????????????continue; ????????????????????} ????????????????????if?(title.IndexOf("雷人")?>=?0) ????????????????????{ ????????????????????????continue; ????????????????????} ????????????????????///執行數據保存的邏輯 ????????????????} } ?catch?(Exception?ex) ????????????{ ????????????????ShowLogMsg("出錯了:"+ex.Message+ex.StackTrace); ????????????????return?new?ArrayList(); ????????????} ????????} | 
每一個Htmlnode,你要獲取他的數據用這個方法:??img.Attributes["src"].Value
總結
以上是生活随笔為你收集整理的.Net解析html文档类库HtmlAgilityPack完整使用说明的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 史铁生励志故事100字(史铁生的故事10
- 下一篇: 解析HTML文件 - 运用SgmlRea
