正則表達(dá)式 _HTMLParser使用詳解-2010-03-21.ppt_第1頁(yè)
正則表達(dá)式 _HTMLParser使用詳解-2010-03-21.ppt_第2頁(yè)
正則表達(dá)式 _HTMLParser使用詳解-2010-03-21.ppt_第3頁(yè)
正則表達(dá)式 _HTMLParser使用詳解-2010-03-21.ppt_第4頁(yè)
正則表達(dá)式 _HTMLParser使用詳解-2010-03-21.ppt_第5頁(yè)
已閱讀5頁(yè),還剩75頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Java正則表達(dá)式入門 + HTMLParser使用詳解,一、 Java正則表達(dá)式入門 眾所周知,在程序開(kāi)發(fā)中,難免會(huì)遇到需要匹配、查找、替換、判斷字符串的情況發(fā)生,而這些情況有時(shí)又比較復(fù)雜,如果用純編碼方式解決,往往會(huì)浪費(fèi)程序員的時(shí)間及精力。 因此,學(xué)習(xí)及使用正則表達(dá)式,便成了解決這一矛盾的主要手段。 大家都知道,正則表達(dá)式是一種可以用于模式匹配和替換的規(guī)范,一個(gè)正則表達(dá)式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)組成的文字模式,它 用以描述在查找文字主體時(shí)待匹配的一個(gè)或多個(gè)字符串。正則表達(dá)式作為一個(gè)模板,將某個(gè)字符模式與所搜索的字符串進(jìn)行匹配。 自從jdk1.4推出java.

2、util.regex包,就為我們提供了很好的JAVA正則表達(dá)式應(yīng)用平臺(tái)。,說(shuō)明,轉(zhuǎn)義符,a,f,響鈴符 = x07,換頁(yè)符 = x0C,換頁(yè)符,n,響鈴符 = x07,換行 (u000A),r,回車符 = x0D,回車 (u000D),t,制表符 = x09,間隔 (u0009),v,垂直制表符 = x0B,e,ESC 符 = x1B, Escape,x20,使用兩位十六進(jìn)制表示形式,可與該編號(hào)的字符匹配,u002B,使用四位十六進(jìn)制表示形式,可與該編號(hào)的字符匹配,x20A060,使用任意位十六進(jìn)制表示形式,可與該編號(hào)的字符匹配,說(shuō)明,字符,$,匹配輸入字符串的開(kāi)始位置。要匹配 字符本身,請(qǐng)使

3、用 ,匹配輸入字符串的結(jié)尾位置。要匹配 “$” 字符本身,請(qǐng)使用 “$”,( ),標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置。要匹配小括號(hào),請(qǐng)使用 ( 和 ), ,用來(lái)自定義能夠匹配 多種字符 的表達(dá)式。要匹配中括號(hào),請(qǐng)使用 和 , ,修飾匹配次數(shù)的符號(hào)。要匹配大括號(hào),請(qǐng)使用 和 ,.,匹配除了換行符(n)以外的任意一個(gè)字符。要匹配小數(shù)點(diǎn)本身,請(qǐng)使用 .,?,修飾匹配次數(shù)為 0 次或 1 次。要匹配 ? 字符本身,請(qǐng)使用 ?,+,修飾匹配次數(shù)為至少 1 次。要匹配 + 字符本身,請(qǐng)使用 +,*,修飾匹配次數(shù)為 0 次或任意次。要匹配 * 字符本身,請(qǐng)使用*,|,左右兩邊表達(dá)式之間 或 關(guān)系。匹配 | 本

4、身,請(qǐng)使用 |,說(shuō)明,字符集合,.,w,小數(shù)點(diǎn)可以匹配除了換行符(n)以外的任意一個(gè)字符,可以匹配任何一個(gè)字母或者數(shù)字或者下劃線,單獨(dú)字符 a-zA-Z_0-9,W,W大寫,可以匹配任何一個(gè)字母或者數(shù)字或者下劃線以外的字符,非單獨(dú)字符 a-zA-Z_0-9,s,可以匹配空格、制表符、換頁(yè)符等空白字符的其中任意一個(gè),空白符號(hào) tnx0Bfr,S,S大寫,可以匹配任何一個(gè)空白字符以外的字符,非空白符號(hào)tnx0Bfr,d,可以匹配任何一個(gè) 09 數(shù)字字符,數(shù)字 等價(jià)于0-9,D,D大寫,可以匹配任何一個(gè)非數(shù)字字符,非數(shù)字 等價(jià)于0-9,字符集合 可以匹配 “多個(gè)字符” 其中任意一個(gè)字符的正則表達(dá)式。

5、雖然是 “多個(gè)字符”,但每次只能匹配其中一個(gè)。DEELX 正則表達(dá)式中標(biāo)準(zhǔn)的字符集合有:,說(shuō)明,限定符,n,m, n,表達(dá)式固定重復(fù)n次,比如:w2 相當(dāng)于 ww,表達(dá)式盡可能重復(fù)n次,至少重復(fù)m次:ba1,3可以匹配 ba或baa或baaa,m, ,表達(dá)式盡可能的多匹配,至少重復(fù)m次:“wd2,”可以匹配a12,x456.,?,表達(dá)式盡可能匹配1次,也可以不匹配,相當(dāng)于 0, 1,+,表達(dá)式盡可能的多匹配,至少匹配1次,相當(dāng)于 1, ,*,表達(dá)式盡可能的多匹配,最少可以不匹配,相當(dāng)于 0, ,匹配次數(shù)限定符 使被修飾的表達(dá)式可多次重復(fù)匹配的修飾符??墒贡恍揎椀谋磉_(dá)式重復(fù)固定次數(shù),也可以限定一

6、定的重復(fù)匹配的次數(shù)范圍。在限定符之后的表達(dá)式能夠匹配成功的情況下,不定次數(shù)的限定符總是盡可能的多匹配。如果之后的表達(dá)式匹配失敗,限定符可適當(dāng)“讓出”能夠匹配的字符,以使整個(gè)表達(dá)式匹配成功。這種模式就叫“貪婪模式”。,說(shuō)明,限定符,m, n?,m, ?,表達(dá)式盡量只匹配m次,最多重復(fù)n次。,表達(dá)式盡量只匹配m次,最多可以匹配任意次。,?,表達(dá)式盡量不匹配,最多匹配1次,相當(dāng)于 0, 1?,+?,表達(dá)式盡量只匹配1次,最多可匹配任意次,相當(dāng)于 1, ?,*?,表達(dá)式盡量不匹配,最多可匹配任意次,相當(dāng)于 0, ?,“勉強(qiáng)模式”限定符: 在限定符之后添加問(wèn)號(hào)(?),則使限定符成為“勉強(qiáng)模式”。勉強(qiáng)模式

7、的限定符,總是盡可能少的匹配。如果之后的表達(dá)式匹配失敗,勉強(qiáng)模式也可以盡可能少的再匹配一些,以使整個(gè)表達(dá)式匹配成功。,說(shuō)明,限定符,m, n+,m, +,表達(dá)式盡可能重復(fù)n次,至少重復(fù)m次。,表達(dá)式盡可能的多匹配,至少重復(fù)m次。,?+,表達(dá)式盡可能匹配1次,也可以不匹配,相當(dāng)于 0, 1+,+,表達(dá)式盡可能的多匹配,至少匹配1次,相當(dāng)于 1, +,*+,表達(dá)式盡可能的多匹配,最少可以不匹配,相當(dāng)于 0, +,“占有模式”限定符: 在限定符之后添加加號(hào)(+),則使限定符成為“占有模式”。占有模式的限定符,總是盡可能多的匹配。與“貪婪模式”不同的是,即使之后的表達(dá)式匹配失敗,“占有模式”也不會(huì)“讓

8、出”自己能夠匹配的字符。,轉(zhuǎn)義字符 Q.E 使用 Q 開(kāi)始,E 結(jié)束,可使中間的標(biāo)點(diǎn)符號(hào)失去特殊意義,將中間的字符作為普通字符。 例如: Q(a+b)*3E 可匹配文本 “(a+b)*3”。,因?yàn)檎齽t表達(dá)式是一個(gè)很龐雜的體系,所以我僅例舉些入門的概念,更多的請(qǐng)參閱相關(guān)書(shū)籍及自行摸索。,b 一個(gè)單詞的邊界B 一個(gè)非單詞的邊界G 前一個(gè)匹配的結(jié)束 為限制開(kāi)頭java 條件限制為以Java為開(kāi)頭字符$為限制結(jié)尾java$ 條件限制為以java為結(jié)尾字符. 條件限制除n以外任意一個(gè)單獨(dú)字符java. 條件限制為java后除換行外任意兩個(gè)字符 加入特定限制條件a-z 條件限制在小寫a to z范圍中一個(gè)

9、字符A-Z 條件限制在大寫A to Z范圍中一個(gè)字符a-zA-Z 條件限制在小寫a to z或大寫A to Z范圍中一個(gè)字符,0-9 條件限制在小寫0 to 9范圍中一個(gè)字符0-9a-z 條件限制在小寫0 to 9或a to z范圍中一個(gè)字符0-9a-z 條件限制在小寫0 to 9或a to z范圍中一個(gè)字符(交集) 中加入后加再次限制條件a-z 條件限制在非小寫a to z范圍中一個(gè)字符A-Z 條件限制在非大寫A to Z范圍中一個(gè)字符a-zA-Z 條件限制在非小寫a to z或大寫A to Z范圍中一個(gè)字符0-9 條件限制在非小寫0 to 9范圍中一個(gè)字符0-9a-z 條件限制在非小寫0

10、to 9或a to z范圍中一個(gè)字符0-9a-z 條件限制在非小寫0 to 9或a to z范圍中一個(gè)字符(交集)在 限制條件為特定字符出現(xiàn)0次以上時(shí),可以使用*J* 0個(gè)以上J.* 0個(gè)以上任意字符,J.*D J與D之間0個(gè)以上任意字符 在限制條件為特定字符出現(xiàn)1次以上時(shí),可以使用+J+ 1個(gè)以上J.+ 1個(gè)以上任意字符J.+D J與D之間1個(gè)以上任意字符 在限制條件為特定字符出現(xiàn)有0或1次以上時(shí),可以使用?JA? J或者JA出現(xiàn) 限制為連續(xù)出現(xiàn)指定次數(shù)字符aJ2 JJJ3 JJJ 文字a個(gè)以上,并且a,J3, JJJ,JJJJ,JJJJJ,?(3次以上J并存),文字個(gè)以上,b個(gè)以下a,bJ

11、3,5 JJJ或JJJJ或JJJJJ兩者取一|J|A J或AJava|Hello Java或Hello ()中規(guī)定一個(gè)組合類型比如,我查詢index中間的數(shù)據(jù),可寫作+href=?(*)?*(.+?)在使用Ppile函數(shù)時(shí),可以加入控制正則表達(dá)式的匹配行為的參數(shù):Pattern Ppile(String regex, int flag),flag的取值范圍如下: Pattern.CANON_EQ 當(dāng)且僅當(dāng)兩個(gè)字符的正規(guī)分解(canonical decomposition)都完全相同的情況下,才認(rèn)定匹配。比如用了這個(gè)標(biāo)志之后,表達(dá)式au030A會(huì)匹配?。默認(rèn)情況下,不考慮規(guī) 范相等性(canon

12、ical equivalence)。 Pattern.CASE_INSENSITIVE(?i) 默認(rèn)情況下,大小寫不明感的匹配只適用于US-ASCII字符集。這個(gè)標(biāo)志能讓表達(dá)式忽略大小寫進(jìn)行匹配。要想對(duì)Unicode字符進(jìn)行大小不明感的匹 配,只要將UNICODE_CASE與這個(gè)標(biāo)志合起來(lái)就行了。 Pattern.COMMENTS(?x) 在這種模式下,匹配時(shí)會(huì)忽略(正則表達(dá)式里的)空格字符,(譯者注:不是指表達(dá)式里的s,而是指表達(dá)式里的空格,tab,回車之類)。注釋從#開(kāi)始,一直到這行結(jié)束??梢酝ㄟ^(guò)嵌入式的標(biāo)志來(lái)啟用Unix行模式。 Pattern.DOTALL(?s) 在這種模式下,表達(dá)式

13、.可以匹配任意字符,包括表示一行的結(jié)束符。默認(rèn)情況下,表達(dá)式.不匹配行的結(jié)束符。Pattern.MULTILINE (?m) 在這種模式下,和$分別匹配一行的開(kāi)始和結(jié)束。此外,仍然匹配字符串的開(kāi)始,$也匹配字符串的結(jié)束。默認(rèn)情況下,這兩個(gè)表達(dá)式僅僅匹配字符串的開(kāi)始和結(jié)束。Pattern.UNICODE_CASE (?u) 在這個(gè)模式下,如果你還啟用了CASE_INSENSITIVE,2020年7月31日星期五12時(shí)28分45秒,標(biāo)志,那么它會(huì)對(duì)Unicode字符進(jìn)行大小寫不明感的匹配。默認(rèn)情況下,大小寫不敏感的匹配只適用于US-ASCII字符集。 Pattern.UNIX_LINES(?d)

14、在這個(gè)模式下,只有n才被認(rèn)作一行的中止,并且與.,以及$進(jìn)行匹配。 拋開(kāi)空泛的概念,下面寫出幾個(gè)簡(jiǎn)單的Java正則用例:比如,在字符串包含驗(yàn)證時(shí)/查找以Java開(kāi)頭,任意結(jié)尾的字符串Pattern pattern = Ppile(Java.*);Matcher matcher = pattern.matcher(Java不是人);boolean b= matcher.matches(); /當(dāng)條件滿足時(shí),將返回true,否則返回falseSystem.out.println(b);,以多條件分割字符串時(shí)Pattern pattern = Ppile(, |+);String strs = pa

15、ttern.split(Java Hello World Java,Hello,World|Sun);for (int i=0;istrs.length;i+) System.out.println(strsi); 文字替換(首次出現(xiàn)字符)Pattern pattern = Ppile(正則表達(dá)式);Matcher matcher = pattern.matcher(正則表達(dá)式 Hello World,正則表達(dá)式 Hello World);/替換第一個(gè)符合正則的數(shù)據(jù)System.out.println(matcher.replaceFirst(Java);,文字替換(全部)Pattern pa

16、ttern = Ppile(正則表達(dá)式);Matcher matcher = pattern.matcher(正則表達(dá)式 Hello World,正則表達(dá)式 Hello World);/替換第一個(gè)符合正則的數(shù)據(jù)System.out.println(matcher.replaceAll(Java); 文字替換(置換字符)Pattern pattern = Ppile(“正則表達(dá)式”);Matcher matcher = pattern.matcher(“正則表達(dá)式 Hello World,正則表達(dá)式 Hello World ”);StringBuffer sbr = new StringBuff

17、er();while (matcher.find() matcher.appendReplacement(sbr, “Java”);,matcher.appendTail(sbr);System.out.println(sbr.toString(); 驗(yàn)證是否為郵箱地址String email=“w.-+(w-+.)+w-+”;String str=”;Pattern pattern = Ppile(email,Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(str);System.out.println(matcher.

18、matches(); 比較嚴(yán)格的: email=(0-9a-zA-Z(-.w*0-9a-zA-Z)*(0-9a-zA-Z)+(-w*0-9a-zA-Z)*.)+a-zA-Z2,9)$ 去除html標(biāo)記 Pattern pattern = Ppile(, Pattern.DOTALL);,Matcher matcher = pattern.matcher(主頁(yè));String string = matcher.replaceAll();System.out.println(string); 查找html中對(duì)應(yīng)條件字符串Pattern pattern = Ppile(href=(.+?);Matc

19、her matcher = pattern.matcher(主頁(yè));if(matcher.find()System.out.println(matcher.group(1); 截取http:/地址/截取urlPattern pattern = Ppile(http:/|https:/)1w.-/:+);,Matcher matcher = pattern.matcher(dsdsdsfdf); StringBuffer buffer = new StringBuffer();while(matcher.find() buffer.append(matcher.group(); buffer.a

20、ppend(rn); System.out.println(buffer.toString(); 替換指定中文字String str = Java目前的發(fā)展史是由0年-1年;String object=new String0,1995,new String1,2007;,System.out.println(replace(str,object); public static String replace(final String sourceString,Object object) String temp=sourceString; for(int i=0;iobject.length;i

21、+) String result=(String)objecti; Pattern pattern = Ppile(result0); Matcher matcher = pattern.matcher(temp); temp=matcher.replaceAll(result1); return temp;,讀取頁(yè)面鏈接和內(nèi)容: public String newsListRegExp = +href=?( *)?*(.+?) ; newsListRegExp =+hrefs*=*s*(s|+)*(; public void getLinks(String content) java.uti

22、l.regex.Pattern pattern=java.util.regex.Ppile(newsListRegExp, java.util.regex.Pattern.CASE_INSENSITIVE); java.util.regex.Matcher matcher=pattern.matcher(content); while(matcher.find() String link=matcher.group(1); String text=matcher.group(2); System.out.println(link+text); ,Java正則的功用還有很多,事實(shí)上只要是字符處理

23、,就沒(méi)有正則做不到的事情存在。 (當(dāng)然,正則解釋時(shí)較耗時(shí)間就是了!),二、 HTMLParser使用詳解,HTMLParser使用詳解(1)- 初始化Parser,在研究搜索引擎的開(kāi)發(fā)中,對(duì)于HTML網(wǎng)頁(yè)的處理是核心的一個(gè)環(huán)節(jié)。網(wǎng)上有很多開(kāi)源的代碼,對(duì)于Java來(lái)說(shuō),HTMLParser是比較著名并且得到廣泛應(yīng)用的一個(gè)。 HTMLParser的主頁(yè)是 ,最后的更新是2006年9月的1.6版。不過(guò)沒(méi)關(guān)系,HTML的內(nèi)容已經(jīng)很久沒(méi)有大的變化了,HTMLParser處理起來(lái)基本沒(méi)有任何問(wèn)題。,HTMLParser的核心模塊是org.htmlparser.Parser類,這個(gè)類實(shí)際完成了對(duì)于HTML頁(yè)

24、面的分析工作。這個(gè)類有下面幾個(gè)構(gòu)造函 數(shù): 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 ParserExc

25、eption;public Parser (Lexer lexer);public Parser (URLConnection connection) throws ParserException;和一個(gè)靜態(tài)類 public static Parser createParser (String html, String charset);,對(duì)于大多數(shù)使用者來(lái)說(shuō),使用最多的是通過(guò)一個(gè)URLConnection或者一個(gè)保存有網(wǎng)頁(yè)內(nèi)容的字符串來(lái)初始化Parser,或者使用靜態(tài)函數(shù)來(lái)生成一個(gè)Parser對(duì)象。 ParserFeedback的代碼很簡(jiǎn)單,是針對(duì)調(diào)試和跟蹤分析過(guò)程的,一般不需要改變。而使用

26、Lexer則是一個(gè)相對(duì)比較高級(jí)的話題,放到以后再討論吧。 這里比較有趣的一點(diǎn)是,如果需要設(shè)置頁(yè)面的編碼方式的話,不使用Lexer就只有靜態(tài)函數(shù)一個(gè)方法了。 對(duì)于大多數(shù)中文頁(yè)面來(lái)說(shuō),好像這是應(yīng)該用得比較多的一個(gè)方法。,HTMLParser使用詳解(2)- Node內(nèi)容,HTMLParser將解析過(guò)的信息保存為一個(gè)樹(shù)的結(jié)構(gòu)。Node是信息保存的數(shù)據(jù)類型基礎(chǔ)。 請(qǐng)看Node的定義:public interface Node extends Cloneable; Node中包含的方法有幾類: 對(duì)于樹(shù)型結(jié)構(gòu)進(jìn)行遍歷的函數(shù),這些函數(shù)最容易理解: Node getParent ():取得父節(jié)點(diǎn)NodeLis

27、t getChildren ():取得子節(jié)點(diǎn)的列表,Node getFirstChild ():取得第一個(gè)子節(jié)點(diǎn)Node getLastChild ():取得最后一個(gè)子節(jié)點(diǎn) Node getPreviousSibling ():取得前一個(gè)兄弟(不好意思,英文是兄弟姐妹,直譯太麻煩而且不符合習(xí)慣,對(duì)不起女同胞了)Node getNextSibling ():取得下一個(gè)兄弟節(jié)點(diǎn) 取得Node內(nèi)容的函數(shù): String getText ():取得文本String toPlainTextString():取得純文本信息。 String toHtml () :取得HTML信息(原始HTML)String

28、 toHtml (boolean verbatim):取得HTML信息(原始HTML)String toString ():取得字符串信息(原始HTML)Page getPage ():取得這個(gè)Node對(duì)應(yīng)的Page對(duì)象,int getStartPosition ():取得這個(gè)Node在HTML頁(yè)面中的起始位置int getEndPosition ():取得這個(gè)Node在HTML頁(yè)面中的結(jié)束位置用于Filter過(guò)濾的函數(shù): void collectInto (NodeList list, NodeFilter filter):基于filter的條件對(duì)于這個(gè)節(jié)點(diǎn)進(jìn)行過(guò)濾,符合條件的節(jié)點(diǎn)放到lis

29、t中。 用于Visitor遍歷的函數(shù): void accept (NodeVisitor visitor):對(duì)這個(gè)Node應(yīng)用visitor用于修改內(nèi)容的函數(shù),這類用得比較少: void setPage (Page page):設(shè)置這個(gè)Node對(duì)應(yīng)的Page對(duì)象void setText (String text):設(shè)置文本void setChildren (NodeList children):設(shè)置子節(jié)點(diǎn)列表,其他函數(shù): void doSemanticAction ():執(zhí)行這個(gè)Node對(duì)應(yīng)的操作(只有少數(shù)Tag有對(duì)應(yīng)的操作)Object clone ():接口Clone的抽象函數(shù)。 主要注意

30、一下,getText,toPlainTextString ,toHtml 區(qū)別 String a=貓撲hi來(lái)點(diǎn)不一樣 ; Parser p=Parser.createParser(a, UTF-8); try for(NodeIterator it= p.elements();it.hasMoreNodes();) Node node=it.nextNode() ; System.out.println(node.getText()+$+node.toPlainTextString()+$+node.toHtml(); catch (ParserException e) / TODO Auto

31、-generated catch block e.printStackTrace(); 輸出: div id=hi$貓撲hi$貓撲hi a class=link href= $來(lái)點(diǎn)不一樣$來(lái)點(diǎn)不一樣,下面是用于測(cè)試的HTML文件: 白澤居- 白澤居-白澤居- 白澤居-,toPlainTextString是把用戶可以看到的內(nèi)容都包含了。有趣的有兩點(diǎn),一是標(biāo)簽中的Title內(nèi)容是在plainText中的,可能在標(biāo)題中可見(jiàn)的也算可見(jiàn)吧。 另外就是象前面說(shuō)的,HTML內(nèi)容中的換行符什么的,也都成了plainText,這個(gè)邏輯上好像有點(diǎn)問(wèn)題。另外可能大家發(fā)現(xiàn)toHtml,toHtml(true)和toH

32、tml(false)的結(jié)果沒(méi)什么區(qū)別。實(shí)際也是這樣的,如果,跟蹤HTMLParser的代碼就可以發(fā)現(xiàn),Node的子類是AbstractNode,其中實(shí)現(xiàn)了toHtml()的代碼,直接調(diào)用toHtml(false),而AbstractNode的三個(gè)子類RemarkNode,TagNode和TextNode中,toHtml(boolean verbatim)的實(shí)現(xiàn)中,都沒(méi)有處理verbatim參數(shù),所以三個(gè)函數(shù)的結(jié)果是一模一樣的。 如果你不需要實(shí)現(xiàn)你自己的什么特殊處理,簡(jiǎn)單使用toHtml就可以了。,HTML的Node類繼承關(guān)系如下圖這個(gè)是從別的文章Copy的):,AbstractNodes是No

33、de的直接子類,也是一個(gè)抽象類。它的三個(gè)直接子類實(shí)現(xiàn)是RemarkNode,用于保存注釋。在輸出結(jié)果的toString部分中可以看到有一個(gè)Rem (3456,2,3566,13): 這是注釋,就是一個(gè)RemarkNode。TextNode也很簡(jiǎn)單,就是用戶可見(jiàn)的文字信息。 TagNode是最復(fù)雜的,包含了HTML語(yǔ)言中的所有標(biāo)簽,而且可以擴(kuò)展(擴(kuò)展 HTMLParser 對(duì)自定義標(biāo)簽的處理能力 )。TagNode包含兩類,一類是簡(jiǎn)單的Tag,實(shí)際就是不能包含其他Tag的標(biāo)簽,只能做葉子節(jié)點(diǎn)。另一類是CompositeTag,就是可以包含其他Tag,是分支節(jié)點(diǎn)。,遍歷了網(wǎng)頁(yè)的內(nèi)容以后,以樹(shù)(森林

34、)結(jié)構(gòu)保存了結(jié)果。HTMLParser訪問(wèn)結(jié)果內(nèi)容的方法有兩種。使用Filter和使用Visitor。 (一)Filter類 顧名思義,F(xiàn)ilter就是對(duì)于結(jié)果進(jìn)行過(guò)濾,取得需要的內(nèi)容。HTMLParser在org.htmlparser.filters包之內(nèi)一共定義了16個(gè)不同的Filter,也可以分為幾類。,HTMLParser使用詳解(3)- 通過(guò)Filter訪問(wèn)內(nèi)容,判斷類Filter: TagNameFilterHasAttributeFilterHasChildFilterHasParentFilterHasSiblingFilterIsEqualFilter 邏輯運(yùn)算Filter:

35、 AndFilterNotFilterOrFilterXorFilter,其他Filter: NodeClassFilterStringFilterLinkStringFilterLinkRegexFilterRegexFilterCssSelectorNodeFilter 所有的Filter類都實(shí)現(xiàn)了org.htmlparser.NodeFilter接口。這個(gè)接口只有一個(gè)主要函數(shù):boolean accept (Node node); 各個(gè)子類分別實(shí)現(xiàn)這個(gè)函數(shù),用于判斷輸入的Node是否符合這個(gè)Filter的過(guò)濾條件,如果符合,返回true,否則返回false。,(二)判斷類Filter H

36、TMLParser使用入門(2)- Node內(nèi)容 ,自己添加import部分)public static void main(String args) try Parser parser = new Parser( (HttpURLConnection) (new URL(:8080/HTMLParserTester.html).openConnection() ); / 這里是控制測(cè)試的部分,后面的例子修改的就是這個(gè)地方。 NodeFilter filter = new TagNameFilter (DIV); NodeList nodes = parser.e

37、xtractAllNodesThatMatch(filter);,if(nodes!=null) for (int i = 0; i nodes.size(); i+) Node textnode = (Node) nodes.elementAt(i); message(getText:+textnode.getText(); message(=); catch( Exception e ) e.printStackTrace(); 輸出結(jié)果:getText:div id=top_main,=getText:div id=logoindex=可以看出文件中兩個(gè)Div節(jié)點(diǎn)都被取出了。下面可以針對(duì)

38、這兩個(gè)DIV節(jié)點(diǎn)進(jìn)行操作 2.2 HasChildFilter 下面讓我們看看HasChildFilter。剛剛看到這個(gè)Filter的時(shí)候,我想當(dāng)然地認(rèn)為這個(gè)Filter返回的是有Child的Tag。直接初始化了一個(gè)NodeFilter filter = new HasChildFilter();,結(jié)果調(diào)用NodeList nodes = parser.extractAllNodesThatMatch(filter);的時(shí)候HasChildFilter內(nèi)部直接發(fā)生NullPointerException。讀了一下HasChildFilter的代碼,才發(fā)現(xiàn),實(shí)際HasChildFilter是返回

39、有符合條件的子節(jié)點(diǎn)的節(jié)點(diǎn),需要另外一個(gè)Filter作為過(guò)濾子節(jié)點(diǎn)的參數(shù)。 缺省的構(gòu)造函數(shù)雖然可以初始化,但是由于子節(jié)點(diǎn)的Filter是null,所以使用的時(shí)候發(fā)生了Exception。 從這點(diǎn)來(lái)看,HTMLParser的代碼還有很多可以優(yōu)化的的地方。呵呵。,修改代碼: NodeFilter innerFilter = new TagNameFilter (DIV);NodeFilter filter = new HasChildFilter(innerFilter);NodeList nodes = parser.extractAllNodesThatMatch(filter);輸出結(jié)果: g

40、etText:body = getText:div id=top_main= 可以看到,輸出的是兩個(gè)有DIV子Tag的Tag節(jié)點(diǎn)。(body有子節(jié)點(diǎn)DIV top_main,top_main有子節(jié)點(diǎn)logoindex。,注意HasChildFilter還有一個(gè)構(gòu)造函數(shù):public HasChildFilter (NodeFilter filter, boolean recursive) 如果recursive是false,則只對(duì)第一級(jí)子節(jié)點(diǎn)進(jìn)行過(guò)濾。比如前面的例子,body和top_main都是在第一級(jí)的子節(jié)點(diǎn)里就有DIV節(jié)點(diǎn),所以匹配上了。如果我們用下面的方法調(diào)用:NodeFilter f

41、ilter = new HasChildFilter( innerFilter, true ); 輸出結(jié)果: getText:html xmlns=/1999/xhtml=getText:body = getText:div id=top_main=,可以看到輸出結(jié)果中多了一個(gè)html xmlns=/1999/xhtml,這個(gè)是整個(gè)HTML頁(yè)面的節(jié)點(diǎn)(根節(jié)點(diǎn)),雖然這個(gè)節(jié)點(diǎn)下直接沒(méi)有DIV節(jié)點(diǎn),但是它的子節(jié)點(diǎn)body下面有DIV節(jié)點(diǎn),所以它也被匹配上了。 2.3 HasAttributeFilter HasAttributeFil

42、ter有3個(gè)構(gòu)造函數(shù):public HasAttributeFilter ();public HasAttributeFilter (String attribute);public HasAttributeFilter (String attribute, String value);這個(gè)Filter可以匹配出包含制定名字的屬性,或者制定屬性為指定值的節(jié)點(diǎn)。還是用例子說(shuō)明比較容易。,調(diào)用方法1: NodeFilter filter = new HasAttributeFilter();NodeList nodes = parser.extractAllNodesThatMatch(filte

43、r); 輸出結(jié)果: 什么也沒(méi)有輸出。調(diào)用方法2: NodeFilter filter = new HasAttributeFilter( id );NodeList nodes = parser.extractAllNodesThatMatch(filter);,輸出結(jié)果: getText:div id=top_main=getText:div id=logoindex= 調(diào)用方法3: NodeFilter filter = new HasAttributeFilter( id, logoindex );NodeList nodes = parser.extractAllNodesThatMa

44、tch(filter);輸出結(jié)果: getText:div id=logoindex= 很簡(jiǎn)單吧。呵呵,2.4 其他判斷列Filter HasParentFilter和HasSiblingFilter的功能與HasChildFilter類似,大家自己試一下就應(yīng)該了解了。IsEqualFilter的構(gòu)造函數(shù)參數(shù)是一個(gè)Node:public IsEqualFilter (Node node) mNode = node; accept函數(shù)也很簡(jiǎn)單:public boolean accept (Node node) return (mNode = node);不需要過(guò)多說(shuō)明了。,(三)邏輯運(yùn)算Filt

45、er (四)其他Filter: HTMLParser使用入門(2)- Node內(nèi)容 中我們已經(jīng)了解了Node的不同類型,這個(gè)Filter就可以針對(duì)類型進(jìn)行過(guò)濾。測(cè)試代碼: NodeFilter filter = new NodeClassFilter(RemarkNode.class); NodeList nodes = parser.extractAllNodesThatMatch(filter); 輸出結(jié)果: getText:這是注釋= 可以看到只有RemarkNode(注釋)被輸出了。,4.2 StringFilter 這個(gè)Filter用于過(guò)濾顯示字符串中包含制定內(nèi)容的Tag。注意是可顯

46、示的字符串,不可顯示的字符串中的內(nèi)容(例如注釋,鏈接等等)不會(huì)被顯示。 修改一下例子代碼: 白澤居-title-, 白澤居-字符串1- 白澤居-鏈接文本- 白澤居-字符串2-,測(cè)試代碼: NodeFilter filter = new StringFilter(); NodeList nodes = parser.extractAllNodesThatMatch(filter); 輸出結(jié)果: getText:白澤居-title-= getText: 白澤居-字符串1-=getText:白澤居-鏈接文本-=,getText: 白澤居-字符串2-= 可以看到包含title,兩個(gè)內(nèi)容字符串和鏈接的文

47、本字符串的Tag都被輸出了,但是注釋和鏈接Tag本身沒(méi)有輸出。 4.3 LinkStringFilter 這個(gè)Filter用于判斷鏈接中是否包含某個(gè)特定的字符串,可以用來(lái)過(guò)濾出指向某個(gè)特定網(wǎng)站的鏈接。測(cè)試代碼: NodeFilter filter = new LinkStringFilter(); NodeList nodes = parser.extractAllNodesThatMatch(filter);,輸出結(jié)果: getText:a href= 4.4 其他幾個(gè)Filter 其他幾個(gè)Filter也是根據(jù)字符串對(duì)不同的域進(jìn)行判斷,與前面這些的區(qū)別主要就是支持正則表達(dá)式。這個(gè)不在本文的討

48、論范圍以內(nèi),大家可以自己實(shí)驗(yàn)一下。 前面介紹的都是簡(jiǎn)單的Filter,只能針對(duì)某種單一類型的條件進(jìn)行過(guò)濾。HTMLParser支持對(duì)于簡(jiǎn)單類型的Filter進(jìn)行組合,從而實(shí)現(xiàn)復(fù)雜的條件。原理和一般編程語(yǔ)言的邏輯運(yùn)算是一樣的。,3.1 AndFilter AndFilter可以把兩種Filter進(jìn)行組合,只有同時(shí)滿足條件的Node才會(huì)被過(guò)濾。 測(cè)試代碼: NodeFilter filterID = new HasAttributeFilter( “id” );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filte

49、r = new AndFilter(filterID, filterChild);輸出結(jié)果:getText:div id=“l(fā)ogoindex”=,3.2 OrFilter 把前面的AndFilter換成OrFilter測(cè)試代碼: NodeFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new OrFilter(filterID, filterChild); 輸出結(jié)果: getText:div id=to

50、p_main= getText:div id=logoindex=,3.3 NotFilter 把前面的AndFilter換成NotFilter測(cè)試代碼: NodeFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new NotFilter(new OrFilter(filterID, filterChild); 輸出結(jié)果: getText:!DOCTYPE html PUBLIC -/W3C/DTD XH

51、TML 1.0 Transitional/EN /TR/xhtml1/DTD/xhtml1-transitional.dtd=getText:,=getText:head=getText:meta http-equiv=Content-Type content=text/html; charset=gb2312=getText:title =getText:白澤居-=getText:/title= getText:/head,=getText:=getText:html xmlns=/1999/xhtml=getText: =ge

52、tText:body =getText:=getText:,=getText: = getText:這是注釋= getText: 白澤居- =getText:a href=getText:白澤居-=getText:/a,=getText: =getText:/div=getText: 白澤居- = getText:/div= getText:,= getText:/body= getText: =getText:/html=getText:=除了前面3.2中輸出的幾個(gè)Tag,其余的Tag都在這里了。,3.4 XorFilter 把前面的AndFilter換成NotFilter測(cè)試代碼: Nod

53、eFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new XorFilter(filterID, filterChild); 輸出結(jié)果: getText:div id=top_main= 4.1 NodeClassFilter 這個(gè)Filter用于判斷節(jié)點(diǎn)類型是否是某個(gè)特定的Node類型。在,2.1 TagNameFilter TabNameFilter是最容易理解的一個(gè)Filter,根據(jù)Tag的名字進(jìn)行

54、過(guò)濾。 下面是用于測(cè)試的HTML文件: 白澤居-, 白澤居-白澤居- 白澤居- ,HTMLParser遍歷了網(wǎng)頁(yè)的內(nèi)容以后,以樹(shù)(森林)結(jié)構(gòu)保存了結(jié)果。HTMLParser訪問(wèn)結(jié)果內(nèi)容的方法有兩種。 使用Filter和使用Visitor。 下面介紹使用Visitor訪問(wèn)內(nèi)容的方法。 4.1 NodeVisitor 從簡(jiǎn)單方面的理解,F(xiàn)ilter是根據(jù)某種條件過(guò)濾取出需要的Node再進(jìn)行處理。Visitor則是遍歷,HTMLParser使用詳解(4)- 通過(guò)Visitor訪問(wèn),內(nèi)容樹(shù)的每一個(gè)節(jié)點(diǎn),對(duì)于符合條件的節(jié)點(diǎn)進(jìn)行處理。實(shí)際的結(jié)果異曲同工,兩種不同的方法可以達(dá)到相同的結(jié)果。下面是一個(gè)最常見(jiàn)的NodeVisitro的例子。 測(cè)試代碼: public static void main(String args) try Parser parser = new Parser( (HttpURLConnection) (new URL(:8080/HTMLParserTester.html).openConnection() );,NodeVisitor visitor = new NodeVisitor( false, false ) public void visitTag(Tag tag) message(This is Tag:+ta

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論