当前位置: 代码迷 >> HTML/CSS >> HTMLParser运用详解
  详细解决方案

HTMLParser运用详解

热度:395   发布时间:2012-12-19 14:13:14.0
HTMLParser使用详解

?

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):

?

?