HTMLParser使用详解(3)- 通过Filter访问内容

来源:互联网 发布:mac上的word软件 编辑:程序博客网 时间:2024/05/22 18:19


 HTMLParser使用详解(3)- 通过Filter访问内容


2009-03-12 19:45:10
 标签:HTMLParser Java   [推送到技术圈] 
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也是根据字符串对不同的域进行判断,与前面这些的区别主要就是支持正则表达式。这个不在本文的讨论范围以内,大家可以自己实验一下。



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 美国生完孩子做飞机婴儿怎么办 会计专硕复试英语面试不好怎么办 被打过狂犬疫苗的狗咬了怎么办 保姆和雇主带孩子玩受伤了怎么办 银行流水造假拒签10年怎么办 老师进修被学校扣工资该怎么办 老婆性格太倔结婚一年想离婚怎么办 天正打图窗户线条太粗怎么办 孩子在幼儿园不敢跟老师说话怎么办 温州教育准考证号密码忘了怎么办 高等继续教育网打不开课程怎么办 安运继续教育的登录密码忘了怎么办 金蝶k3账套管理打不开了怎么办 仁和会计课堂app不能用怎么办 光大银行已经下卡了终审被拒怎么办 过了上诉期和申诉期该怎么办 北外大四学生要实习半年课程怎么办 电脑发给手机的文件过期了怎么办 农民给土地卖了30年后怎么办 家长发家长群作业太多老师怎么办 在考试中心补不了四级成绩怎么办 微信登录密码不记得了怎么办 欠农民工工资不给怎么办老板说没钱 国外期刊催问稿件不理睬怎么办 老公离不开老婆也离不开小三怎么办 出轨被老婆发现还和小三联系怎么办 老公出轨后回家老婆不想原谅怎么办 小三和原配打架都住院了怎么办 毕业太多年查不到学历认证怎么办 没有做税种核定开了票怎么办 在学信网上查不到学历信息怎么办 学信网手机号换了密码忘了怎么办 学信网手机号换了密码也忘了怎么办 学信网上学习形式是星号怎么办 新手机号已被注册微店买家怎么办 微信号被冻结了里面的钱怎么办 不懂公司产品却要接待老外怎么办 上菜时发现桌面摆不下新菜怎么办 超市买到过期产品商家不赔尝怎么办 皇帝成长计划2俘虏的士兵怎么办 晚上楼上有挪桌子的声音怎么办