by lostfire
這兩天準(zhǔn)備做一些網(wǎng)站編程的工作,于是對(duì)HtmlParse小研究了一下,目的是快速入手,而不是深入研究,做了一下整理,和大家共同討論一下。
這兩天準(zhǔn)備做一些網(wǎng)站編程的工作,于是對(duì)HtmlParse小研究了一下,目的是快速入手,而不是深入研究,做了一下整理,和大家共同討論一下。
?
一,數(shù)據(jù)組織分析:
HtmlParser主要靠Node、AbstractNode和
- Node是形成樹(shù)結(jié)構(gòu)表示HTML的基礎(chǔ),所有的數(shù)據(jù)表示都是接口
Node的實(shí)現(xiàn),Node定義了與頁(yè)面樹(shù)結(jié)構(gòu)所表達(dá)的頁(yè)面Page 對(duì)象,定義了獲取父、子、兄弟節(jié)點(diǎn)的方法,定義了節(jié)點(diǎn)到對(duì)應(yīng)htm l文本的方法,定義了該節(jié)點(diǎn)對(duì)應(yīng)的起止位置,定義了過(guò)濾方法 ,定義了Visitor訪問(wèn)機(jī)制。 - AbstractNode是Node的一種具體的類(lèi)實(shí)現(xiàn)
,起到構(gòu)成樹(shù)形結(jié)構(gòu)的作用,除了同具體Node相關(guān)的accetp 方法,toString,toHtml,toPlainTextS tring方法以外,AbstractNode實(shí)現(xiàn)了大多基本的方 法,使得它的子類(lèi),不用理會(huì)具體的樹(shù)操作。 - Tag是具體分析的主要內(nèi)容。Tag分成composite的Ta
g和不能包含其他Tag的簡(jiǎn)單Tag兩類(lèi),其中前者的基類(lèi)是Compo siteTag,其子類(lèi)包含BodyTag,Div ,FrameSetTag,OptionTag,等27個(gè)子類(lèi) ;而簡(jiǎn)單Tag有BaseHrefTag 、DoctypeTag,FrameTag,ImageTag ,InputTag,JspTag,MetaTag ,ProcessingInstructionTag這八類(lèi)。
Node分成三類(lèi):
- RemarkNode:代表Html中的注釋
- TagNode:標(biāo)簽節(jié)點(diǎn),是種類(lèi)最多的節(jié)點(diǎn)類(lèi)型,上述Tag的具體節(jié)點(diǎn)類(lèi)都是TagNode的實(shí)現(xiàn)。
- TextNode:文本節(jié)點(diǎn)
?
二,Visitor方式訪問(wèn)Html:
?
1,整體解析過(guò)程
- 用一個(gè)URL或頁(yè)面String做一個(gè)Parser
- 用這個(gè)Parser做一個(gè)Visitor
- 使用Parser.visitAllNodeWith(Visitor)來(lái)遍歷節(jié)點(diǎn)
- 獲取Visitor遍歷后得到的數(shù)據(jù)
2,Visit過(guò)程
- 做解析之前做的事情:visitor.beginParsing
(); - 每次取到一個(gè)節(jié)點(diǎn)Node,讓該Node接受accept該Vis
itor - 做解析后做的事情:visitor.finishedParsin
g();
3,獲取節(jié)點(diǎn)的過(guò)程:逐步遍歷Html,分析出Node。此部分較為復(fù)雜,且對(duì)于我們應(yīng)用來(lái)說(shuō)無(wú)需很多了解,暫跳過(guò)。
?
4,節(jié)點(diǎn)訪問(wèn)
節(jié)點(diǎn)訪問(wèn)采用Visitor模式,Node的accept方法和具體Visitor的visit方法是關(guān)鍵。
首先三類(lèi)Node來(lái)accept的方式各不相同:
- 對(duì)于所有TagNode都使用一個(gè)accept方法
,即TagNode的accept方法。首先判斷是否是標(biāo)簽結(jié)尾 ,如果是就visitor.visitEndTag (this);否則visitor.visitTag (this); - 如果是TextNode,那就visitor.visitStri
ngNode (this);就可以了。 - 如果是RemarkNode,那就visitor
.visitRemarkNode (this);就可以了。
實(shí)際上NodeVisitor里邊這四種visit方法都是空的
系統(tǒng)為我們實(shí)現(xiàn)了下面我要介紹的8種Visitor,實(shí)際上可以看作是系統(tǒng)給我們演示了如何做各種各樣的Visitor來(lái)訪問(wèn)Html,因?yàn)閷?shí)際上我們要真正來(lái)用HtmlParser的話(huà),還需要特定的Visitor,而通過(guò)簡(jiǎn)單的這些系統(tǒng)提供的Visitor組合是難以做成什么事情的。
?
三,系統(tǒng)Visitor功能簡(jiǎn)介:
- ObjectFindingVisitor:用來(lái)找出所有指定類(lèi)型
的節(jié)點(diǎn),采用getTags()來(lái)獲取結(jié)果。 - StringBean:用來(lái)從一個(gè)指定的URL獲取移除了
<SCRIPT></SCRIPT>和<PRE></PRE >之間代碼的Html代碼,也可以用做Visitor ,用來(lái)移除這兩種標(biāo)簽內(nèi)部的代碼,采用StringBean .getStrings()來(lái)獲取結(jié)果。 - HtmlPage:提取Title,body中的節(jié)點(diǎn)和頁(yè)面中的T
ableTag節(jié)點(diǎn)。 - LinkFindingVisitor:找出節(jié)點(diǎn)中包含某個(gè)鏈接的
總個(gè)數(shù)。 - StringFindingVisitor:找出遍歷的TextN
ode中含有指定字符串的個(gè)數(shù)。 - TagFindingVisitor:找出指定Tag的所有節(jié)點(diǎn)
,可以指定多種類(lèi)型。 - TextExtractingVisitor:從網(wǎng)頁(yè)中把所有標(biāo)簽
去掉來(lái)提取文本,這個(gè)提取文本的Visitor有時(shí)是很實(shí)用的 ,只是注意在提取文本時(shí)將標(biāo)簽的屬性也去掉了,也就是說(shuō)只剩下標(biāo)簽 之間的文本,例如<a>中的鏈接也去掉了。 - UrlModifyingVisitor:用來(lái)修改網(wǎng)頁(yè)中的鏈接。
四,F(xiàn)ilter
?
如果說(shuō)visitor是遍歷提取信息,當(dāng)然這個(gè)信息可以包括某些節(jié)點(diǎn)或者從節(jié)點(diǎn)分析出來(lái)的更有效的信息,這都取決于我們的Visitor做成什么樣子,那么Filter則目標(biāo)很明確,就是用來(lái)提取節(jié)點(diǎn)的。所以說(shuō)要想用HtmlParser,首先要熟悉上面講到的數(shù)據(jù)組織。
?
系統(tǒng)定義了17種具體的Filter,包括依據(jù)節(jié)點(diǎn)父子關(guān)系的Filter,連接Filter組合的Filter,依據(jù)網(wǎng)頁(yè)內(nèi)容匹配情況的filter,等等。我們也可以implement Filter來(lái)做自己的Filter來(lái)提取節(jié)點(diǎn)。
?
Filter的調(diào)用是同Visitor獨(dú)立的,因?yàn)橐矡o(wú)需先f(wàn)ilter出一些NodeList,再用Visitor來(lái)訪問(wèn)。調(diào)用Filter的方法是:
NodeList nodeList = myParser.parse(someFilter);
解析之后,我們可以采用:
Node[] nodes = nodeList.toNodeArray();
來(lái)獲取節(jié)點(diǎn)數(shù)組,也可以直接訪問(wèn):
Node node = nodeList.elementAt(i)來(lái)獲取Node。
?
另外,在Filter后得到NodeList以后,我們?nèi)匀豢梢允褂肗odeList的extractAllNodesThatMatch(someFilter)來(lái)進(jìn)一步過(guò)濾,同時(shí)又可以用NodeList的isitAllNodesWith(someVisitor)來(lái)做進(jìn)一步的訪問(wèn)。
這樣,我們可以看到HtmlParser為我們提供了非常方便的Html解析方式,針對(duì)不同的應(yīng)用可以采用visitor來(lái)遍歷Html節(jié)點(diǎn)提取數(shù)據(jù),也可以用Filter來(lái)過(guò)濾節(jié)點(diǎn),提取出我們所關(guān)注的節(jié)點(diǎn),再對(duì)節(jié)點(diǎn)進(jìn)行處理。通過(guò)這樣的組合,一定能夠找出我們所需要的信息。
?
參考: