转自http://www.blogjava.net/lostfire/archive/2006/07/02/56212.html,作者:lostfire
一,数据组织分析:
HtmlParser主要靠Node、AbstractNode和
- Node是形成树结构表示HTML的基础,所有的数据表示都是接口
Node的实现,Node定义了与页面树结构所表达的页面Page 对象,定义了获取父、子、兄弟节点的方法,定义了节点到对应htm l文本的方法,定义了该节点对应的起止位置,定义了过滤方法 ,定义了Visitor访问机制。 - AbstractNode是Node的一种具体的类实现
,起到构成树形结构的作用,除了同具体Node相关的accetp 方法,toString,toHtml,toPlainTextS tring方法以外,AbstractNode实现了大多基本的方 法,使得它的子类,不用理会具体的树操作。 - Tag是具体分析的主要内容。Tag分成composite的Ta
g和不能包含其他Tag的简单Tag两类,其中前者的基类是Compo siteTag,其子类包含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该Vis
itor - 做解析后做的事情:visitor.finishedParsin
g();
3,获取节点的过程:逐步遍历Html,分析出Node
。此部分较为复杂,且对于我们应用来说无需很多了解,暂跳过。
4,节点访问
节点访问采用Visitor模式,Node的accept方法和具
体Visitor的visit方法是关键。
首先三类Node来accept的方式各不相同:
- 对于所有TagNode都使用一个accept方法
,即TagNode的accept方法。首先判断是否是标签结尾 ,如果是就visitor.visitEndTag (this);否则visitor.visitTag (this); - 如果是TextNode,那就visitor.visitStri
ngNode (this);就可以了。 - 如果是RemarkNode,那就visitor
.visitRemarkNode (this);就可以了。
实际上NodeVisitor里边这四种visit方法都是空的
系统为我们实现了下面我要介绍的8种Visitor
,实际上可以看作是系统给我们演示了如何做各种各样的Visito
r来访问Html,因为实际上我们要真正来用HtmlParser
的话,还需要特定的Visitor,而通过简单的这些系统提供的V
isitor组合是难以做成什么事情的。
三,系统Visitor功能简介:
- ObjectFindingVisitor:用来找出所有指定类型
的节点,采用getTags()来获取结果。 - StringBean:用来从一个指定的URL获取移除了
<SCRIPT></SCRIPT>和<PRE></PRE >之间代码的Html代码,也可以用做Visitor ,用来移除这两种标签内部的代码,采用StringBean .getStrings()来获取结果。 - HtmlPage:提取Title,body中的节点和页面中的T
ableTag节点。 - LinkFindingVisitor:找出节点中包含某个链接的
总个数。 - StringFindingVisitor:找出遍历的TextN
ode中含有指定字符串的个数。 - 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来过滤节点,提取出我们所关注的节点,再对节点进行处理。通过这样的组合,一定能够找出我们所需要的信息。