一,数据组织分析:

HtmlParser主要靠Node、AbstractNode和Tag来表达Html,因为Remark和Text相对简单,此处就将其忽略了。

  • Node是形成树结构表示HTML的基础,所有的数据表示都是接口Node的实现,Node定义了与页面树结构所表达的页面Page对象,定义了获取父、子、兄弟节点的方法,定义了节点到对应html文本的方法,定义了该节点对应的起止位置,定义了过滤方法,定义了Visitor访问机制。
  • AbstractNode是Node的一种具体的类实现,起到构成树形结构的作用,除了同具体Node相关的accetp方法,toString,toHtml,toPlainTextString方法以外,AbstractNode实现了大多基本的方法,使得它的子类,不用理会具体的树操作。
  • Tag是具体分析的主要内容。Tag分成composite的Tag和不能包含其他Tag的简单Tag两类,其中前者的基类是CompositeTag,其子类包含BodyTag,Div,FrameSetTag,OptionTag,等27个子类;而简单Tag有BaseHrefTag、DoctypeTag,FrameTag,ImageTag,InputTag,JspTag,MetaTag,ProcessingInstructionTag这八类。

Node分成三类:

  • RemarkNode:代表Html中的注释
  • TagNode:标签节点,是种类最多的节点类型,上述Tag的具体节点类都是TagNode的实现。
  • TextNode:文本节点
二,Visitor方式访问Html:
1,整体解析过程
  • 用一个URL或页面String做一个Parser
  • 用这个Parser做一个Visitor
  • 使用Parser.visitAllNodeWith(Visitor)来遍历节点
  • 获取Visitor遍历后得到的数据
2,Visit过程
  • 做解析之前做的事情:visitor.beginParsing();
  • 每次取到一个节点Node,让该Node接受accept该Visitor
  • 做解析后做的事情:visitor.finishedParsing();
3,获取节点的过程:逐步遍历Html,分析出Node。此部分较为复杂,且对于我们应用来说无需很多了解,暂跳过。
4,节点访问
节点访问采用Visitor模式,Node的accept方法和具体Visitor的visit方法是关键。
首先三类Node来accept的方式各不相同:
  • 对于所有TagNode都使用一个accept方法,即TagNode的accept方法。首先判断是否是标签结尾,如果是就visitor.visitEndTag (this);否则visitor.visitTag (this);
  • 如果是TextNode,那就visitor.visitStringNode (this);就可以了。
  • 如果是RemarkNode,那就visitor.visitRemarkNode (this);就可以了。

实际上NodeVisitor里边这四种visit方法都是空的,因为在不同的Visitor中对于这三类节点的处理是不同的;对于需要处理的节点,只要重载对应的visit方法就行了,如果不处理那就不理会就可以了;另外,如果用户用自己的Visitor,那么还可以灵活的处理不同类型的节点了。

系统为我们实现了下面我要介绍的8种Visitor,实际上可以看作是系统给我们演示了如何做各种各样的Visitor来访问Html,因为实际上我们要真正来用HtmlParser的话,还需要特定的Visitor,而通过简单的这些系统提供的Visitor组合是难以做成什么事情的。
三,系统Visitor功能简介:
  • ObjectFindingVisitor:用来找出所有指定类型的节点,采用getTags()来获取结果。
  • StringBean:用来从一个指定的URL获取移除了<SCRIPT></SCRIPT>和<PRE></PRE>之间代码的Html代码,也可以用做Visitor,用来移除这两种标签内部的代码,采用StringBean.getStrings()来获取结果。
  • HtmlPage:提取Title,body中的节点和页面中的TableTag节点。
  • LinkFindingVisitor:找出节点中包含某个链接的总个数。
  • StringFindingVisitor:找出遍历的TextNode中含有指定字符串的个数。
  • TagFindingVisitor:找出指定Tag的所有节点,可以指定多种类型。
  • TextExtractingVisitor:从网页中把所有标签去掉来提取文本,这个提取文本的Visitor有时是很实用的,只是注意在提取文本时将标签的属性也去掉了,也就是说只剩下标签之间的文本,例如<a>中的链接也去掉了。
  • UrlModifyingVisitor:用来修改网页中的链接。
四,Filter
如果说visitor是遍历提取信息,当然这个信息可以包括某些节点或者从节点分析出来的更有效的信息,这都取决于我们的Visitor做成什么样子,那么Filter则目标很明确,就是用来提取节点的。所以说要想用HtmlParser,首先要熟悉上面讲到的数据组织。
系统定义了17种具体的Filter,包括依据节点父子关系的Filter,连接Filter组合的Filter,依据网页内容匹配情况的filter,等等。我们也可以implement Filter来做自己的Filter来提取节点。
Filter的调用是同Visitor独立的,因为也无需先filter出一些NodeList,再用Visitor来访问。调用Filter的方法是:
NodeList nodeList = myParser.parse(someFilter);
解析之后,我们可以采用:
Node[] nodes = nodeList.toNodeArray();
来获取节点数组,也可以直接访问:
Node node = nodeList.elementAt(i)来获取Node。
另外,在Filter后得到NodeList以后,我们仍然可以使用NodeList的extractAllNodesThatMatch(someFilter)来进一步过滤,同时又可以用NodeList的isitAllNodesWith(someVisitor)来做进一步的访问。
这样,我们可以看到HtmlParser为我们提供了非常方便的Html解析方式,针对不同的应用可以采用visitor来遍历Html节点提取数据,也可以用Filter来过滤节点,提取出我们所关注的节点,再对节点进行处理。通过这样的组合,一定能够找出我们所需要的信息。
参考:
http://htmlparser.sourceforge.net/
http://www.blogjava.net/rocky/archive/2005/12/21/24997.aspx
http://www.westing.cn/xblog/?p=90
获取帮助:
 邮件列表:
http://sourceforge.net/mail/?group_id=24399
主页上的sample:
http://htmlparser.sourceforge.net/samples.html
在发布的包里没有demo或example文件夹,但是在有些类,比如org.htmlparser.Parser
有public static void main(String[] args)这个方法,其中有一些该类的使用方法。
org.htmlparser.Parser.main(String[] args)中就有Parse a web page and print the tags in a simple loop的方法。这在http://htmlparser.sourceforge.net/samples.html上有说明。
特别的:一个java web start
http://htmlparser.sourceforge.net/samples/filterbuilder.jnlp
帮助认识和使用filter。

一些常见处理:

应用HtmlParser处理含HTML标签的字符串或网页

String Extraction

To get all the text content from a web page, use the TextExtractingVisitor, like so:

import org.htmlparser.Parser;import org.htmlparser.util.ParserException;import org.htmlparser.visitors.TextExtractingVisitor;public class StringDemo{    public static void main (String[] args) throws ParserException    {        Parser parser = new Parser ("http://pageIwantToParse.com");        TextExtractingVisitor visitor = new TextExtractingVisitor ();        parser.visitAllNodesWith (visitor);        System.out.println (visitor.getExtractedText());    }}

If you want a more browser like behaviour, use the StringBean like so:

import org.htmlparser.beans.StringBean;public class StringDemo{    public static void main (String[] args)    {        StringBean sb = new StringBean ();        sb.setLinks (false);        sb.setReplaceNonBreakingSpaces (true);        sb.setCollapse (true);        sb.setURL ("http://pageIwantToParse.com");        System.out.println (sb.getStrings ());    }}

To get all the text content from a web page you already have in a string:

import org.htmlparser.Parser;import org.htmlparser.Node;import org.htmlparser.nodes.TextNode;import org.htmlparser.util.ParserException;public class StringDemo{    public static void main (String[] args) throws ParserException    {        Parser myParser;        Node[] nodes = null;        String content = "";        myParser = Parser.createParser(content, null);

        nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could be thrown here

        for (int i = 0; i < nodes.length; i++)        {            TextNode textnode = (TextNode) nodes[i];            String line = textnode.toPlainTextString().trim();            if (line.equals("")) continue;            System.out.println(line);        }    }

http://blog.csdn.net/redez/archive/2005/11/21/534277.aspx
 HTMLParser 使用

最近在研究lucene,主要做ftp搜索和网页的站内搜索。
ftp搜索比较好做,主流的FTP有两种一种是IIS的一种是Server-U的.
真对这两种FTP分别进行分析就可以得到FTP资源的文件名和路径及大小和日期
然后对其进行索引就可以了,比较简单。
网页检索可不像ftp那样了,我试着用lucene自带的htmlparser,解析纯英文的网页
没有问题,可解析中文的网页时有时会遇到编码问题。郁闷。。。
SourceForge搜到了一个开源的HTMLParser。网址是http://htmlparser.sourceforge.net
目前的版本为1.6。

测试代码为:

import java.io.*;
import org.htmlparser.filters.*;
import org.htmlparser.*;
import org.htmlparser.nodes.*;
import org.htmlparser.tags.*;
import org.htmlparser.util.*;
import org.htmlparser.visitors.*;

public class HTMLParserTest
{
 public static void main(String args[]) throws Exception
 {
  String path = "D://Webdup//MyWebsites//biti//download//latest//cisco.biti.edu.cn//index.html";
  StringBuffer sbStr = new StringBuffer();
  BufferedReader reader  = new BufferedReader(new FileReader(new File(path)));
  String temp = "";
  while((temp=reader.readLine())!=null)
  {
   sbStr.append(temp);
   sbStr.append("/r/n");
  }
  reader.close();
 
 
  String result = sbStr.toString();
   readAll(result);
        readTextAndLink(result);
        readByHtml(result);
     readTextAndTitle(result);
 }

//按页面方式处理.解析标准的html页面
 public static void readByHtml(String content) throws Exception
    {
        Parser myParser;
        myParser = Parser.createParser(content, "GB2312");

HtmlPage visitor = new HtmlPage(myParser);

myParser.visitAllNodesWith(visitor);

String textInPage = visitor.getTitle();
        System.out.println(textInPage);
        NodeList nodelist ;
        nodelist = visitor.getBody();
        System.out.print(nodelist.asString().trim());
 
 
    }
   
    //读取文本内容和标题
 public static void readTextAndTitle(String result) throws Exception
 {
  Parser parser ;
  NodeList nodelist ;
  parser = Parser.createParser(result,"GB2312");
  NodeFilter textFilter = new NodeClassFilter(TextNode.class);
  NodeFilter titleFilter = new NodeClassFilter(TitleTag.class);
  OrFilter lastFilter = new OrFilter();
  lastFilter.setPredicates(new NodeFilter[]{textFilter,titleFilter});
  nodelist = parser.parse(lastFilter);
  Node[] nodes = nodelist.toNodeArray();
  String line ="";
  for(int i=0;i<nodes.length;i++)
  {
   Node node = nodes[i];
   if(node instanceof TextNode)
   {
    TextNode textnode = (TextNode) node;
    line = textnode.getText();
   }
   else
   if(node instanceof TitleTag)
   {
    TitleTag titlenode = (TitleTag) node;
    line = titlenode.getTitle();
   }
   if (isTrimEmpty(line))
                continue;
            System.out.println(line);
  }
 }
 
 //分别读纯文本和链接
 
 public static void readTextAndLink(String result) throws Exception
 {
  Parser parser;
  NodeList nodelist;
  parser = Parser.createParser(result,"GB2312");
  NodeFilter textFilter = new NodeClassFilter(TextNode.class);
  NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);
  OrFilter lastFilter = new OrFilter();
  lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });
  nodelist = parser.parse(lastFilter);
  Node[] nodes = nodelist.toNodeArray();
  String line ="";
  for(int i=0;i<nodes.length;i++)
  {
   Node node = nodes[i];
   if(node instanceof TextNode)
   {
    TextNode textnode = (TextNode) node;
    line = textnode.getText();
   }
   else
   if(node instanceof LinkTag)
   {
    LinkTag link = (LinkTag)node;
    line = link.getLink();
   }
   if (isTrimEmpty(line))
                continue;
            System.out.println(line);
  }
 }
 
 
 
 
 
 public static void readAll(String result) throws Exception
 {
  Parser parser;
  Node[] nodes ;
  parser = Parser.createParser(result,"GB2312");
  nodes = parser.extractAllNodesThatAre(TextNode.class);
 
  //读取所有的内容节点
  for (int i = 0; i < nodes.length; i++)
        {
            TextNode textnode = (TextNode) nodes[i];
            String line = textnode.toPlainTextString().trim();
            if (line.equals(""))
                continue;
            System.out.println(line);
        }
 }
 
 
 /**
     * 去掉左右空格后字符串是否为空
     */
    public static boolean isTrimEmpty(String astr)
    {
        if ((null == astr) || (astr.length() == 0))
        {
            return true;
        }
        if (isBlank(astr.trim()))
        {
            return true;
        }
        return false;
    }

/**
     * 字符串是否为空:null或者长度为0.
     */
    public static boolean isBlank(String astr)
    {
        if ((null == astr) || (astr.length() == 0))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

}

}
 
来源:http://htmlparser.sourceforge.net/wiki/index.php/StringExtraction
参考:http://htmlparser.sourceforge.net/

处理特定tag:
参考:http://sourceforge.net/mailarchive/message.php?msg_id=25aac9fc0704200423h78893925y72cb75136be7330%40mail.gmail.com
package cn.yethyeth.forTest;
思路:建立一个新的NodeVisitor,在其中处理visitTag这个函数(具体原理见上面第一篇文章)


import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.NodeVisitor;


public class HTMLParserHandleTag extends NodeVisitor...{
    public void visitTag (Tag tag)
    ...{
    if( tag.getAttribute("class")!=null )...{
    System.out.println (" " + tag.getTagName () + tag.getAttribute("class"));
    }
    }
   
    public static void main (String[] args) throws ParserException
    ...{
    Parser parser = new Parser ("http://bbs.qihoo.com/ttgz/index.html");
    NodeVisitor visitor = new HTMLParserHandleTag ();
    parser.visitAllNodesWith (visitor);
    }
}

更简单的方法:使用TagNameFilter , HasAttributeFilter,AndFilter。
TagNameFilter过滤特定名字的tag,
HasAttributeFilter过滤特定名字和值的tag,
AndFilter将多个filter组合起来。

/*
 * TestFilter.java, 2007-5-13 1:22:45.
 *
 * CopyRight (c) 2007-2007, yethyeth ,All rights reserved.
 *
 * This file is licenced under the Apache License.
 */

package com.bighai.forTest;

import org.apache.commons.lang.StringUtils;
import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class TestFilter {

/**
     * @param args
     * @throws ParserException
     */
    public static void main(String[] args) throws ParserException {
        // TODO Auto-generated method stub
        Parser parser = new Parser("http://bbs.qihoo.com/ttgz/index.html");
        AndFilter filter =
            new AndFilter(
                    new TagNameFilter("div"),
                        new HasAttributeFilter("class","rLCon") );

NodeList nodes = parser.parse(filter);

for( int i = 0; i < nodes.size(); i++ ){

System.out.println(
                    ((Tag)nodes.elementAt(i)).getTagName()+" class="+
                    ((Tag)nodes.elementAt(i)).getAttribute("class") );
        }
    }

}

结果:

DIV class=rLCon

HtmlParser初步研究相关推荐

  1. GWT与Eclipse集成开发初步研究

    GWT与Eclipse集成开发初步研究 原文:http://blog.sina.com.cn/s/blog_415bd707010086cy.html JDK6.0 下载.安装.配置 http://b ...

  2. .net HtmlParser初步使用研究

    这两天准备做一些网站编程的工作,于是对HtmlParse小研究了一下,目的是快速入手,而不是深入研究,做了一下整理,和大家共同讨论一下. 一,数据组织分析: HtmlParser主要靠Node.Abs ...

  3. 支持小米java文件阅读器_小米开源文件管理器MiCodeFileExplorer-源码研究(0)-初步研究...

    2011年对着书本Android应用开发揭秘,写了2个月的HelloWorld. 现在想复习并深入,我没有耐心再去一点点地敲代码了. 4年前自己是个学生,实习,现在有工作,只能业余时间研究. 这一点是 ...

  4. 小米开源文件管理器MiCodeFileExplorer-源码研究(0)-初步研究

    2011年对着书本Android应用开发揭秘,写了2个月的HelloWorld. 现在想复习并深入,我没有耐心再去一点点地敲代码了. 4年前自己是个学生,实习,现在有工作,只能业余时间研究. 这一点是 ...

  5. 基于聚类算法的IMT-2030应用场景初步研究

    [摘  要]IMT系统已进入新的研究周期,支持的业务种类将更为丰富,业务品质将更加高级,同时业务特性表现为更多的维度和更大的范围,如何对业务进行客观而高效的分析以得到典型的应用场景,对于IMT系统的标 ...

  6. 图解用工具对BHO做初步研究

    一 BHO和浏览器劫持 BHO Browser Helper Objects (也被称为 BHOs) 是com组件,扮演着ie插件的角色.BHOs可以在某种程度上定制IE,如:用户交互的修改,网页过滤 ...

  7. 一款名为Blue_Moon的后台模板的初步研究

    其介绍曰,Blue Moon后台管理模板是一款适合微信公众平台后台的蓝色清爽风格模板. 1 先看下其效果 表单效果: 图表效果: 界面元素:按钮等等: 表格: 左上角用户登录: 左上角部分的代码结构如 ...

  8. iOS7 UIKit Dynamics 的初步研究

    这回开始学习iOS7新的UIKit Dynamics,我看有人翻译成UIKit 力学,我觉得倒挺贴切的,所以就借来用一用. 这个UIKit力学系统里要设计到四个东西: 1.UIDynamicAnima ...

  9. IE6下z-index犯癫不起作用bug的初步研究

    by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=471 一.匆匆带过的 ...

  10. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

最新文章

  1. wifi boombox android,android filament入门,GLB和GLTF模型查看器
  2. 开源FPGA硬件模拟游戏机,原汁原味的复古游戏体验带你回童年
  3. P4945-最后的战役【dp,离散化】
  4. linux vps 命令,CentOS最常用Linux vps操作命令整理大全
  5. 2015 年出现的十大流行 Python 库
  6. 本地未安装Oracle数据库,如何连接远程Oracle数据库
  7. 解决无法连接mysql问题
  8. 七月在线python数据分析_七月在线Python数据分析笔记
  9. 中数据库url怎么写_WIN10下怎么找到MYSQL数据库中存储数据的位置
  10. 如何解压 GZ 文件
  11. 基于HTML5实现五彩连珠小游戏
  12. 6. LaTeX 参考文献的排版与引用
  13. 第三章:x264视频制作meGUI工具使用
  14. 【LibTorch】Microsoft C++ 异常: c10::NotImplementedError,位于内存位置 0x000000E8A9DAEDC0 处。
  15. 〖2011.08.19〗秋无痕常用软件全功能装机光盘2011年八月版(支持64位WIN7)
  16. 洛谷 P1192 台阶问题
  17. 计算机名打印机无法共享,打印机共享不了怎么回事 打印机共享不了原因和解决办法【详解】...
  18. iscroll4升级到iscroll5全攻略笔记
  19. 什么才是AI公司的商业模式?
  20. MSP430F149学习随笔(三)

热门文章

  1. lighttpd http响应报文(Response)增加安全头Referrer-Policy和X-Permitted-Cross-Domain-Policies方法
  2. 定义并实现一个银行类
  3. 贝塔自助授权系统php源码,贝塔自助授权系统v1.1
  4. 阿里云服务器+N2N搭建远程办公环境
  5. 2014大众点评Hackathon参赛感想
  6. jpa+hibernate整合达梦数据库(附源码)
  7. 天津财经大学珠江学院考计算机二级,【2019年12月天津计算机二级考试报名入口已开通】- 环球网校...
  8. Java实现坦克大战小游戏
  9. 2014省赛----神奇算式(填空)
  10. Day001-2021-07-29 变量定义/数据类型/基础运算 判断/循环/数组