HTMLParser 使用詳解
HTMLParser 具有小巧,快速的優點,缺點是相關文檔比較少(英文的也少),很多功能需要自己摸索。對於初學者還是要費一些功夫的,而一旦上手以後,會發現 HTMLParser 的結構設計很巧妙,非常實用,基本你的各種需求都可以滿足。
這裏我根據自己這幾個月來的經驗,寫了一點入門的東西,希望能對新學習 HTMLParser 的朋友們有所幫助。(不過當年高考本人語文只比及格高一分,所以文法方面的問題還希望大家多多擔待)
HTMLParser 的核心模塊是 org.htmlparser.Parser 類, 這個類實際完成了對於 HTML 頁面的分析工作 。這個類有下面幾個構造函數:
public Parser ();
public Parser (Lexer lexer, ParserFeedback fb);
public Parser (URLConnection connection, ParserFeedback fb) throws ParserException;
public Parser (String resource, ParserFeedback feedback) throws ParserException;
public Parser (String resource) throws ParserException;
public Parser (Lexer lexer);
public Parser (URLConnection connection) throws ParserException;
和一個靜態類 public static Parser createParser (String html, String charset);
對於大多數使用者來說,使用最多的是通過一個 URLConnection 或者一個保存有網頁內容的字符串來初始化 Parser ,或者使用靜態函數來生成一個 Parser 對象。 ParserFeedback 的代碼很簡單, 是針對調試和跟蹤分析過程的 ,一般不需要改變。 而使用 Lexer 則是一個相對比較高級的話題 ,放到以後再討論吧。
這裏比較有趣的一點是, 如果需要設置頁面的編碼方式的話 ,不使用 Lexer 就只有靜態函數一個方法了。對於大多數中文頁面來說,好像這是應該用得比較多的一個方法。
下面是初始化 Parser 的例子。
package com.baizeju.htmlparsertester;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import org.htmlparser.visitors.TextExtractingVisitor;
import org.htmlparser.Parser;
/**
* @author www.baizeju.com
*/
public class Main {
private static String ENCODE = "GBK";
private static void message( String szMsg ) {
try{System.out.println(new String(szMsg.getBytes(ENCODE), System.getProperty("file.encoding"))); } catch(Exception e ){}
}
public static String openFile( String szFileName ) {
try {
BufferedReader bis = new BufferedReader(new InputStreamReader(new FileInputStream( new File(szFileName)), ENCODE ) );
String szContent="";
String szTemp;
while ( (szTemp = bis.readLine()) != null) {
szContent+=szTemp+"\n";
}
bis.close();
return szContent;
}
catch( Exception e ) {
return "";
}
}
public static void main(String[] args) {
String szContent = openFile( "E:/My Sites/HTMLParserTester.html");
try{
//Parser parser = Parser.createParser(szContent, ENCODE);
//Parser parser = new Parser( szContent );
Parser parser = new Parser( (HttpURLConnection) (new URL("http://127.0.0.1:8080/HTMLParserTester.html")).openConnection() );
TextExtractingVisitor visitor = new TextExtractingVisitor ();
parser. visitAllNodesWith ( visitor );
String textInPage = visitor.getExtractedText();
message(textInPage);
}
catch( Exception e ) {
}
}
}
加重的部分測試了幾種不同的初始化方法,後面的顯示了結果。大家看到能 Parser 出內容就可以了,如何操作訪問 Parser 的內容我們在後面討論。
HTMLParser 將解析過的信息保存爲一個樹的結構。 Node 是信息保存的數據類型基礎 。
請看 Node 的定義:
public interface Node extends Cloneable;
Node 中包含的方法有幾類:
對於樹型結構進行遍歷的函數 ,這些函數最容易理解:
Node getParent () : 取得父節點
NodeList getChildren () : 取得子節點的列表
Node getFirstChild () : 取得第一個子節點
Node getLastChild () : 取得最後一個子節點
Node getPreviousSibling () : 取得前一個兄弟(不好意思,英文是兄弟姐妹,直譯太麻煩而且不符合習慣,對不起女同胞了)
Node getNextSibling () : 取得下一個兄弟節點
取得 Node 內容的函數 :
String getText () : 取得文本
String toPlainTextString () : 取得純文本信息 。
String toHtml () : 取得 HTML 信息(原始 HTML )
String toHtml (boolean verbatim) : 取得 HTML 信息(原始 HTML )
String toString () : 取得字符串信息(原始 HTML )
Page getPage () : 取得這個 Node 對應的 Page 對象
int getStartPosition () : 取得這個 Node 在 HTML 頁面中的起始位置
int getEndPosition () : 取得這個 Node 在 HTML 頁面中的結束位置
用於 Filter 過濾的函數:
void collectInto (NodeList list, NodeFilter filter) : 基於 filter 的條件對於這個節點進行過濾,符合條件的節點放到 list 中。
用於 Visitor 遍歷的函數:
void accept (NodeVisitor visitor) : 對這個 Node 應用 visitor
用於修改內容的函數,這類用得比較少 :
void setPage (Page page) : 設置這個 Node 對應的 Page 對象
void setText (String text) : 設置文本
void setChildren (NodeList children) : 設置子節點列表
其他函數 :
void doSemanticAction () : 執行這個 Node 對應的操作(只有少數 Tag 有對應的操作)
Object clone () : 接口 Clone 的抽象函數。
實際我們用 HTMLParser 最多的是處理 HTML 頁面, Filter 或 Visitor 相關的函數是必須的,然後第一類和第二類函數是用得最多的。第一類函數比較容易理解,下面用例子說明一下第二類函數。
下面是用於測試的 HTML 文件:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title> 白澤居 -www.baizeju.com</title></head>
<html xmlns="http://www.w3.org/1999/xhtml">
<body >
<div id="top_main">
<div id="logoindex">
<!-- 這是註釋 -->
白澤居 -www.baizeju.com
<a href="http://www.baizeju.com"> 白澤居 -www.baizeju.com</a>
</div>
白澤居 -www.baizeju.com
</div>
</body>
</html>
測試代碼:
/**
* @author www.baizeju.com
*/
package com.baizeju.htmlparsertester;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import org.htmlparser.Node;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.Parser;
/**
* @author www.baizeju.com
*/
public class Main {
private static String ENCODE = " GBK ";
private static void message( String szMsg ) {
try{ System.out.println(new String(szMsg.getBytes(ENCODE), System.getProperty("file.encoding"))); } catch(Exception e ){}
}
public static String openFile ( String szFileName ) {
try {
BufferedReader bis = new BufferedReader(new InputStreamReader(new FileInputStream( new File(szFileName)), ENCODE) );
String szContent="";
String szTemp;
while ( (szTemp = bis.readLine()) != null) {
szContent+=szTemp+"\n";
}
bis.close();
return szContent;
}
catch( Exception e ) {
return "";
}
}
public static void main(String[] args) {
try{
Parser parser = new Parser( (HttpURLConnection) (new URL("http://127.0.0.1:8080/HTMLParserTester.html")).openConnection() );
for (NodeIterator i = parser.elements (); i.hasMoreNodes(); ) {
Node node = i.nextNode();
message("getText:"+node.getText());
message("getPlainText:"+node.toPlainTextString());
message("toHtml:"+node.toHtml());
message("toHtml(true):"+node.toHtml(true));
message("toHtml(false):"+node.toHtml(false));
message("toString:"+node.toString());
message("=================================================");
}
}
catch( Exception e ) {
System.out.println( "Exception:"+e );
}
}
}
輸出結果:
getText:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
getPlainText:
toHtml:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
toHtml(true):<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
toHtml(false):<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
toString:Doctype Tag : !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd; begins at : 0; ends at : 121
=================================================
getText:
getPlainText:
toHtml:
toHtml(true):
toHtml(false):