當我們需要解析一個web頁面的時候,如果非常簡單,可以用字串查詢的方式,複雜一點可以用正規表示式,但是有時候正則很麻煩的,因為html程式碼本身就比較麻煩,像常用的img標籤,這個東東到了瀏覽器上就沒了閉合標籤(一直還沒搞懂為什麼),想用XML解析,也是同樣的原因根本解析不了,今天發現一個解析html控制元件,用了一下,非常好用。
這個控制元件叫做Html Agility Pack,主頁在這兒:http://htmlagilitypack.codeplex.com/
這兒還有一篇blog介紹怎麼使用的 (English):http://olussier.net/2010/03/30/easily-parse-html-documents-in-csharp/
我直接把例子貼這兒,一看就明白。因為是作為xml解析的,所以呢,少不了XPath,如果不懂這個東西的話,趕緊看看吧,現在xpath語法都擴充套件到css裡面了,語法比較簡單,先看看基礎的就行了。
最基本的使用方法不是SelectSingleNode,而是GetElementById,這是與XmlDocument不同的地方。
// The HtmlWeb class is a utility class to get the HTML over HTTP HtmlWeb htmlWeb = new HtmlWeb(); // Creates an HtmlDocument object from an URL HtmlAgilityPack.HtmlDocument document = htmlWeb.Load("http://www.somewebsite.com"); // Targets a specific node HtmlNode someNode = document.GetElementbyId("mynode"); // If there is no node with that Id, someNode will be null if (someNode != null) { // Extracts all links within that node IEnumerable<htmlnode> allLinks = someNode.Descendants("a"); // Outputs the href for external links foreach (HtmlNode link in allLinks) { // Checks whether the link contains an HREF attribute if (link.Attributes.Contains("href")) { // Simple check: if the href begins with "http://", prints it out if (link.Attributes["href"].Value.StartsWith("http://")) Console.WriteLine(link.Attributes["href"].Value); } } }</htmlnode>
使用xpath
// Extracts all links under a specific node that have an href that begins with "http://" HtmlNodeCollection allLinks = document.DocumentNode.SelectNodes("//*[@id='mynode']//a[starts-with(@href,'http://')]"); // Outputs the href for external links foreach (HtmlNode link in allLinks) Console.WriteLine(link.Attributes["href"].Value);
One more
path = "//table[@id='1' or @id='2' or @id='3']//a[@onmousedown]"; xpath = "//ul[@id='wg0']//li[position()<4]/h3/a"; xpath = "//div[@class='resitem' and position()<4]/a"; xpath = "//li[@class='result' and position()<4]/a";
使用方法:
剛剛學習了XPath路徑表示式,主要是對XML文件中的節點進行搜尋,通過XPath表示式可以對XML文件中的節點位置進行快速定位和訪問,html也是也是一種類似於xml的標記語言,但是語法沒有那麼嚴謹,在codeplex裡有一個開源專案HtmlAgilityPack,提供了用XPath解析HTML檔案,下面掩飾如何使用該類庫的使用
首先說下XPath路徑表示式
XPath路徑表示式
用來選取XML文件中的節點或節點集的
1、術語:節點(Node):7種型別:元素,屬性,文字,名稱空間,處理命令,註釋,文件(根)節點
2、節點關係:父(Parent),子(Children),同胞(Sibling),先輩(Ancestor),後代(Descendant)
3、路徑表示式
nodename 節點名,選取此節點的所有子節點 例: childnode 當前節點中的childnode子節點,不包含孫子及以下的節點
/ 從根節點選取 例:/root/childnode/grandsonnode
// 表示所有後代節點 例://childnode 所有名為childnode的後代節點
. 表示當前節點 例: ./childnode 表示當前節點的childnode節點
.. 表示父節點 例: ../nearnode 表示父親節點的nearnode子節點
@ 選取屬性 /root/childnode/@id 表示childnode的所有含有id屬性的節點集
4、謂語(Predicates)
謂語可以對節點集進行一些限制,使選擇更精確
/root/book[1] 節點集中的第一個節點
/root/book[last()] 節點集中最後一個節點
/root/book[position() - 1] 節點集中倒數第二個節點集
/root/book[position() < 5] 節點集中前五個節點集
/root/book[@id] 節點集中含有屬性id的節點集
/root/book[@id='chinese'] 節點集中id屬性值為chinese的節點集
/root/book[price > 35]/title 節點集中book的price元素值大於35的title節點集
5、萬用字元:XPath路徑中同樣支援萬用字元(*,@*,node(), text())
例: /bookstore/*
//title[@*]
6、XPath軸
定義相對於當前節點的節點集
ancestor 所有祖先節點
attribute 所有屬性節點
child 所有子元素
descendant 所有後代節點(子,孫。。。)
following 結束標記後的所有節點 preceding 開始標記前的所有節點
following-sibling 結束標記後的所有同胞節點
preceding-sibling 開始標記前的所有同胞節點
namespace 當前名稱空間的所有節點
parent 父節點
self 當前節點
用法:軸名稱::節點測試[謂語]
例: ancestor::book
child::text()
7、運算子
| 兩個節點集的合併 例:/root/book[1] | /root/book[3]
+,-,*,dev,mod
=,!=,<,>,<=,>=
or,and 或和與
//刪除註釋,script,style node.Descendants() .Where(n => n.Name == "script" || n.Name == "style" || n.Name=="#comment") .ToList().ForEach(n => n.Remove()); //遍歷node節點的所有後代節點 foreach(var HtmlNode in node.Descendants()) { }
HtmlAgilityPack類庫用法
1、首先需要獲取到html頁面資料,可以通過WebRequest類來獲取
public static string GetHtmlStr(string url) { try { WebRequest rGet = WebRequest.Create(url); WebResponse rSet = rGet.GetResponse(); Stream s = rSet.GetResponseStream(); StreamReader reader = new StreamReader(s, Encoding.UTF8); return reader.ReadToEnd(); } catch (WebException) { //連線失敗 return null; } }
2、通過HtmlDocument類載入html資料
string htmlstr = GetHtmlStr("http://www.hao123.com"); HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); doc.LoadHtml(htmlstr); HtmlNode rootnode = doc.DocumentNode; //XPath路徑表示式,這裡表示選取所有span節點中的font最後一個子節點,其中span節點的class屬性值為num //根據網頁的內容設定XPath路徑表示式 string xpathstring = "//span[@class='num']/font[last()]"; HtmlNodeCollection aa = rootnode.SelectNodes(xpathstring); //所有找到的節點都是一個集合 if(aa != null) { string innertext = aa[0].InnerText; string color = aa[0].GetAttributeValue("color", ""); //獲取color屬性,第二個引數為預設值 //其他屬性大家自己嘗試 }
也可以通過HtmlWeb類來獲得HtmlDocument
HtmlWeb web = new HtmlWeb(); HtmlAgilityPack.HtmlDocument doc = web.Load(url); HtmlNode rootnode = doc.DocumentNode;
補充:
多個屬性條件查詢 //div[@align='center' and @height='24']
不存在class屬性 //div[not(@class)]