在.net中運用HTMLParser解析網頁的原理和方法

來源:互聯網
上載者:User
本文介紹了.net 版的一個HTMLParser網頁解析開源類庫(Winista.HTMLParser)的功能特性、工作原理和使用方法。對於使用.net進行Web資訊提取的開發人員進行了一次HTMLParser的初步講解。應用執行個體將會在日後的文中介紹,敬請關注。  

一、背景知識
    HTMLParser原本是一個在sourceforge上的一個Java開源項目,使用這個Java類庫可以用來線性地或嵌套地解析HTML文本。他的功能強大和開源等特性吸引了大量Web資訊提取的工作者。然而,許多.net開發人員朋友一直在尋找一種能在.net中使用的HTMLParser類庫,筆者將介紹Winista.HTMLParser類庫,對比於其他原本數量就非常少的.net版HTMLParser類庫,Winista的版本的類庫結構可以說更接近於原始Java版本。
    該類庫目前分為Utltimate、Pro、Lite和Community四個版本,前三個版本都是收費的。只有Community版本可以免費下載並查看所有的源碼。
當前Community最新版本1.8 下載。
該版本的類庫文檔下載。

二、功能和特性
    1.可以在任何.net語言中使用(C#,VB.net,J#等)
    2.可以解析幾乎所有的Html標籤,並且可以通過標籤類別、屬性或Regex來搜尋標籤。有些甚至在Java版本中無法支援的標籤也在這個版本中得到了支援。
    3.設定可擴充的過濾器來過濾結果集中不需要的標籤。
    4.高效能的API介面使得你能處理許多常見的問題,如:哪些是頁面中的外部連結?哪些是圖片?哪些是不同的表格?頁面中有錯誤的連結嗎等等問題。
    5.一個基於Http協議引擎的設定檔使得你能通過一個指定的URL地址來獲得該頁面內容。該爬蟲可以遵循robot.txt協議檔案來獲得組織和允許訪問的列表。
    6.Http協議引擎能夠完整地處理來自任何網站的反饋。

三、詞法分析的工作原理
    HTMLParser的詞法分析器對HTML進行了4級封裝,從低級到進階的順序為:ParserStream、Source、Page、Lexer。ParserStream負責從檔案中擷取位元據,但不做任何處理。Source把二進位檔案轉換成相應的字元序列,儲存一組未加工的字元序列。Page可以看成是一個string數組,按行儲存一個Source文本的每一行第一個字元開始的位置索引。Lexer包含了詞法分析的代碼,從Page裡讀取字串,用Cursor記錄當前字元所在位置,通過狀態機器來產生Nodes節點。
    Lexer中真正執行詞法分析的是NextCode()方法,它每次詞都尋找返回下一個Node節點,直到Page結束。演算法描述如下:
    1.讀入一個字元,判斷是否已是頁尾,是則返回null。
    2.判斷是否是"<",如果是,則可能是標籤入口,需讀取下一字元確認。
    3.如果都不是,ParserString狀態機器開始解析一個StringNode,如果是"<",繼續讀取下一字元。
    4.判斷是否到頁尾,是則產生一個StringNode返回。
    5.如果讀取到"%",則說明是JSP標籤,進入JSP狀態機器去解析。
    6.如果讀取到"?",則說明是XML標籤,進入XML狀態機器去解析。
    7.如果讀取到"/"或任何字母,說明是Tag標籤,進入Tag標籤狀態機器去解析。
    8.如果讀取到"!",則說明進入了一個注釋標籤,需要再讀取一個字元,如果到頁尾,則產生一個StringNode返回,如果字元為">"則產生一個RemarkNode返回,否則    回退一個字元,再判斷字元如果是"-"則回退一個字元,進入Remark狀態機器去解析,如果不是,則回退一個字元進入Tag狀態機器去解析。

四、三種使用方法的比較
1.使用Lexer詞法分析器直接解析HTML。
    這樣的方法較為底層,只能返回一個線性Node節點序列,通過Lexer.NextNode()方法獲得下一個Node的資訊。雖然不夠方便,但有時可完成一些較為靈活的工作。
    調用的方法是(傳入string類型的html代碼):

    Lexer lexer = new Lexer(htmlcode);
    INode node = lexer.NextNode();
    Console.Write(node.ToString());

    返回結果是該頁面的第一個標籤"html"的Node結點資訊。

2.使用Filter結點過濾模式。
    如果你有一些很明確的結點需要提取,那麼就該使用Filter結點過濾模式。系統定義了17種具體的Filter,根據不同的過濾條件來獲得需要的結點。包括依據結點父子關係的Filter,串連Filter組合的Filter,依據網頁內容匹配情況的filter,等等。我們也可以繼承 Filter做自己的Filter來提取節點。

    NodeList nodeList = myParser.parse(someFilter);
解析之後,我們可以採用:
    INode[] nodes = nodeList.toNodeArray();

來擷取節點數組,也可以直接存取:
    INode node = nodeList.elementAt(i);
來擷取Node。
另外,在Filter後得到NodeList以後,我們仍然可以使用nodeList.extractAllNodesThatMatch(someFilter)來進一步過濾,同時又可以用nodeList.visitAllNodesWith(someVisitor)來做進一步的訪問。

3.使用Visitor結點訪問模式
   如果你希望HTMLParser遍曆所有的結點,並按結點的不同類型(StringNode、RemarkNode、TagNode)和不同的訪問過程來進行不同操作的話,可以使用Visitor模式。NodeVisitor是一個抽象類別,分別定義了如下方法:
    BeginParsing():解析前進行的操作
    VitisTag():訪問到開始標籤時的操作
    VisitEndTag():訪問到結束標籤時的操作
    VisitStringNode():訪問到文本結點時的操作
    VisitRemarkNode():訪問注釋結點時的操作
自己定義一個類並繼承NodeVisitor類,實現以上幾個方法,即完成Visitor模式的訪問類。系統也提供了7個具體的結點訪問類,具體見上文提供的類庫文檔。不過這7個類並不實用,大多數的功能還需要自己來擴充定義。調用方法:
     Parser parser = Parser.CreateParser((htmlcode), "GBK");//傳入string類型的html代碼
  NodeVisitor visitor = new LinkFindingVisitor(linktext); //以連結尋找的Visitor舉例
    parser.VisitAllNodesWith(visirot); 

靈活使用以上三種模式的結合,相信就可以提取到任何我們所需要的資訊了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.