HTMLParser 過濾Filter




HTMLParser遍歷了網頁的內容以後,以樹(森林)結構保存了結果。HTMLParser訪問結果內容的方法有兩種。使用Filter和使用Visitor。

(一)Filter類
顧名思義,Filter就是對於結果進行過濾,取 得需要的內容。HTMLParser在org.htmlparser.filters 包之內一共定義了16個不同的Filter,也可以分爲幾類。
判斷類Filter:
TagNameFilter
HasAttributeFilter
HasChildFilter
HasParentFilter
HasSiblingFilter
IsEqualFilter
邏輯運算Filter:
AndFilter
NotFilter
OrFilter
XorFilter
其他Filter:
NodeClassFilter
StringFilter
LinkStringFilter
LinkRegexFilter
RegexFilter
CssSelectorNodeFilter

所 有的Filter類都實現了org.htmlparser.NodeFilter接口。這個 接口只有一個主要函數:
boolean accept (Node node);
各個子類分別實現這個函數,用於判斷輸入的Node是否 符合這個Filter的過濾條件,如果符合,返回true,否則返回false。

(二)判斷類Filter
2.1 TagNameFilter
TabNameFilter是最容 易理解的一個Filter,根據Tag的名字進行過濾。

下面是用於 測試的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>
測試代碼:(這裏只列出了Main函數,全部代碼請參考
 HTMLParser使用入門(2)- Node內容,自己添加import部分)
public static void main(String[] args) {
       
        try{
            Parser parser = new Parser( (HttpURLConnection) (new URL("http://127.0.0.1:8080/HTMLParserTester.html")).openConnection() );
       
            // 這裏是控制測試的部分,後面的例子修改的就是這個地方。
            NodeFilter filter = new TagNameFilter ("DIV");
            NodeList nodes = parser.extractAllNodesThatMatch(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();
        }
    }
輸出結果:
getText:div id="top_main"
=================================================
getText:div id="logoindex"
=================================================
可以看出文件中兩個Div節點都被取出了。下面可以針對這兩個DIV節 點進行操作

2.2 HasChildFilter
下 面讓我們看看HasChildFilter。剛剛看到這個Filter的時候,我想當然地認爲這個Filter返回的是有Child的Tag。直接初始化 了一個
NodeFilter filter = new HasChildFilter();
結果調用NodeList nodes = parser.extractAllNodesThatMatch(filter);的時候HasChildFilter內部直接發生 NullPointerException。讀了一下HasChildFilter的代碼,才發現,實際HasChildFilter是返回有符合條件的 子節點的節點,需要另外一個Filter作爲過濾子節點的參數。缺省的構造函數雖然可以初始化,但是由於子節點的Filter是null,所以使用的時候 發生了Exception。從這點來看,HTMLParser的代碼還有很多可以優化的的地 方。呵呵。

修改代碼:
NodeFilter innerFilter = new TagNameFilter ("DIV");
NodeFilter filter = new HasChildFilter(innerFilter);
NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:body
=================================================
getText:div id="top_main"
=================================================
可 以看到,輸出的是兩個有DIV子Tag的Tag節點。(body有子節點DIV "top_main","top_main"有子節點"logoindex"。

注意HasChildFilter還有一個構造函數:
public HasChildFilter (NodeFilter filter, boolean recursive)
如果recursive是 false,則只對第一級子節點進行過濾。比如前面的例子,body和top_main都是在第一級的子節點裏就有DIV節點,所以匹配上了。如果我們用 下面的方法調用:
NodeFilter filter = new HasChildFilter( innerFilter, true );
輸出結果:
getText:html xmlns="http://www.w3.org/1999/xhtml"
=================================================
getText:body
=================================================
getText:div id="top_main"
=================================================
可以 看到輸出結果中多了一個html xmlns="http://www.w3.org/1999/xhtml",這個是整個HTML頁面的節點(根節點),雖然這個節點下直接沒有DIV節 點,但是它的子節點body下面有DIV節點,所以它也被匹配上了。

2.3 HasAttributeFilter
HasAttributeFilter有3個構造函數:
public HasAttributeFilter ();
public HasAttributeFilter (String attribute);
public HasAttributeFilter (String attribute, String value);
這個Filter可以匹配出包含 制定名字的屬性,或者制定屬性爲指定值的節點。還是用例子說明比較容易。

調用方法1:
NodeFilter filter = new HasAttributeFilter();
NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:

什麼也沒有輸出。

調用方法 2:
NodeFilter filter = new HasAttributeFilter( "id" );
NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:div id="top_main"
=================================================
getText:div id="logoindex"
=================================================

調 用方法3:
NodeFilter filter = new HasAttributeFilter( "id", "logoindex" );
NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:div id="logoindex"
=================================================

很 簡單吧。呵呵

2.4 其他判斷列Filter
HasParentFilter 和HasSiblingFilter的功能與HasChildFilter類似,大家自己試一下就應該瞭解了。

IsEqualFilter 的構造函數參數是一個Node:
public IsEqualFilter (Node node) {
    mNode = node;
}
accept函數也很簡單:
public boolean accept (Node node)    {
    return (mNode == node);
}
不需要過多說明了。


(三)邏輯運算Filter
前面介紹的都是簡單的Filter,只能針對某種單一類型的條件進行過濾。HTMLParser支持對於簡單類型的Filter進行組合,從而實現複雜的條件。原理和一般編程語言 的邏輯運算是一樣的。
3.1 AndFilter

AndFilter 可以把兩種Filter進行組合,只有同時滿足條件的Node纔會被過濾。
測 試代碼:
NodeFilter filterID = new HasAttributeFilter( "id" );
NodeFilter filterChild = new HasChildFilter(filterA);
NodeFilter filter = new AndFilter(filterID, filterChild);
輸出 結果:
getText:div id="logoindex"
=================================================

3.2 OrFilter
把前面的AndFilter換成OrFilter
測試代碼:
NodeFilter filterID = new HasAttributeFilter( "id" );
NodeFilter filterChild = new HasChildFilter(filterA);
NodeFilter filter = new OrFilter(filterID, filterChild);
輸出結果:
getText:div id="top_main"
=================================================
getText:div id="logoindex"
=================================================

3.3 NotFilter
把前面的AndFilter換成 NotFilter
測試代碼:
NodeFilter filterID = new HasAttributeFilter( "id" );
NodeFilter filterChild = new HasChildFilter(filterA);
NodeFilter filter = new NotFilter(new OrFilter(filterID, filterChild));
輸出 結果:
getText:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
=================================================
getText:

=================================================
getText:head
=================================================
getText:meta http-equiv="Content-Type" content="text/html; charset=gb2312"
=================================================
getText:title
=================================================
getText: 白澤居-www.baizeju.com
=================================================
getText:/title
=================================================
getText:/head
=================================================
getText:

=================================================
getText:html xmlns="http://www.w3.org/1999/xhtml"
=================================================
getText:

=================================================
getText:body
=================================================
getText:

=================================================
getText:
       
=================================================
getText:
               
=================================================
getText:這是註釋
=================================================
getText:
                白澤居-www.baizeju.com

=================================================
getText:a href="http://www.baizeju.com"
=================================================
getText: 白澤居-www.baizeju.com
=================================================
getText:/a
=================================================
getText:
       
=================================================
getText:/div
=================================================
getText:
        白澤居-www.baizeju.com

=================================================
getText:/div
=================================================
getText:

=================================================
getText:/body
=================================================
getText:

=================================================
getText:/html
=================================================
getText:

=================================================

除 了前面3.2中輸出的幾個Tag,其餘的Tag都在這裏了。


3.4 XorFilter
把前面的AndFilter換成NotFilter
測試代碼:
NodeFilter filterID = new HasAttributeFilter( "id" );
NodeFilter filterChild = new HasChildFilter(filterA);
NodeFilter filter = new XorFilter(filterID, filterChild);
輸出結果:
getText:div id="top_main"
=================================================

(四)其他Filter:
4.1 NodeClassFilter
這個Filter用於判斷節點 類型是否是某個特定的Node類型。在
HTMLParser使用入門(2)- Node內容 中我們已經瞭解了Node的不同類型,這個Filter就可以針對類型進行過濾。
測試代碼:
            NodeFilter filter = new NodeClassFilter(RemarkNode.class);
            NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:這是註釋
=================================================
可 以看到只有RemarkNode(註釋)被輸出了。

4.2 StringFilter
這個Filter用於過濾顯示字符串中包含制定內容的Tag。注意是可顯示的字符串,不可顯示的字符串中 的內容(例如註釋,鏈接等等)不會被顯示。
修改一下例子代碼:
<!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>白澤居-title-www.baizeju.com</title>& lt;/head>
<html xmlns="http://www.w3.org/1999/xhtml">
<body >
<div id="top_main">
    <div id="logoindex">
        <!--這是註釋 白澤居-www.baizeju.com -->
        白澤居-字符串1-www.baizeju.com
<a href="http://www.baizeju.com">白澤居-鏈接文本-www.baizeju.com</a>
    </div>
    白澤居-字符串2-www.baizeju.com
</div>
</body>
</html>

測試代碼:

            NodeFilter filter = new StringFilter("www.baizeju.com");
            NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:白澤居-title-www.baizeju.com
=================================================
getText:
                白澤居-字符串1-www.baizeju.com

=================================================
getText: 白澤居-鏈接文本-www.baizeju.com
=================================================
getText:
        白澤居-字符串2-www.baizeju.com

=================================================
可 以看到包含title,兩個內容字符串和鏈接的文本字符串的Tag都被輸出了,但是註釋和鏈接Tag本身沒有輸出。

4.3 LinkStringFilter
這個Filter用於判斷鏈接 中是否包含某個特定的字符串,可以用來過濾出指向某個特定網站的鏈接。
測試 代碼:
            NodeFilter filter = new LinkStringFilter("www.baizeju.com");
            NodeList nodes = parser.extractAllNodesThatMatch(filter);
輸出結果:
getText:a href="http://www.baizeju.com"
=================================================

4.4 其他幾個Filter
其他幾個Filter也是根據字符串對不 同的域進行判斷,與前面這些的區別主要就是支持正則表達式。這個不在本文的討論範圍以內,大家可以自己實驗一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章