zoukankan      html  css  js  c++  java
  • 【转】HTMLParser使用详解(4) 通过Visitor访问内容

    HTMLParser遍历了网页的内容以后,以树(森林)结构保存了结果。HTMLParser访问结果内容的方法有两种。使用Filter和使用Visitor。
    下面介绍使用Visitor访问内容的方法。

    4.1 NodeVisitor
    从简单方面的理解,Filter是根据某种条件过滤取出需要的Node再进行处理。Visitor则是遍历内容树的每一个节点,对于符合条件的节点进行处理。实际的结果异曲同工,两种不同的方法可以达到相同的结果。
    下面是一个最常见的NodeVisitro的例子。
    测试代码:
        public static void main(String[] args) {
            try{
                Parser parser = new Parser( (HttpURLConnection) (new URL("http://127.0.0.1:8080/HTMLParserTester.html")).openConnection() );

                NodeVisitor visitor = new NodeVisitor( false, false ) {
                    public void visitTag(Tag tag) {
                       message("This is Tag:"+tag.getText());
                    }
                    public void visitStringNode (Text string)    {
                         message("This is Text:"+string);
                    }
                    public void visitRemarkNode (Remark remark)  {
                         message("This is Remark:"+remark.getText());
                    }
                    public void beginParsing () {
                        message("beginParsing");
                    }
                    public void visitEndTag (Tag tag){
                        message("visitEndTag:"+tag.getText());
                    }
                    public void finishedParsing () {
                        message("finishedParsing");
                    }
                };

                parser.visitAllNodesWith(visitor);
            }
            catch( Exception e ) {    
                e.printStackTrace();
            }
        }
    输出结果:
    beginParsing
    This is Tag:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    This is Text:Txt (121[0,121],123[1,0]): \n
    This is Text:Txt (244[1,121],246[2,0]): \n
    finishedParsing

    可以看到,开始遍历所以的节点以前,beginParsing先被调用,然后处理的是中间的Node,最后在结束遍历以前,finishParsing被调用。因为我设置的 recurseChildren和recurseSelf都是false,所以Visitor没有访问子节点也没有访问根节点的内容。中间输出的两个\n就是我们在HTMLParser使用详解(1)- 初始化Parser 中讨论过的最高层的那两个换行。

    我们先把recurseSelf设置成true,看看会发生什么。
    NodeVisitor visitor = new NodeVisitor( false, true) {
    输出结果:
    beginParsing
    This is Tag:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    This is Text:Txt (121[0,121],123[1,0]): \n
    This is Tag:head
    This is Text:Txt (244[1,121],246[2,0]): \n
    This is Tag:html xmlns="http://www.w3.org/1999/xhtml"
    finishedParsing
    可以看到,HTML页面的第一层节点都被调用了。

    我们再用下面的方法调用看看:
    NodeVisitor visitor = new NodeVisitor( true, false) {
    输出结果:
    beginParsing
    This is Tag:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    This is Text:Txt (121[0,121],123[1,0]): \n
    This is Tag:meta http-equiv="Content-Type" content="text/html; charset=gb2312"
    This is Text:Txt (204[1,81],229[1,106]): 白泽居-title-www.baizeju.com
    visitEndTag:/title
    visitEndTag:/head
    This is Text:Txt (244[1,121],246[2,0]): \n
    This is Text:Txt (289[2,43],291[3,0]): \n
    This is Text:Txt (298[3,7],300[4,0]): \n
    This is Text:Txt (319[4,19],322[5,1]): \n\t
    This is Text:Txt (342[5,21],346[6,2]): \n\t\t
    This is Remark:这是注释 白泽居-www.baizeju.com
    This is Text:Txt (378[6,34],408[8,0]): \n\t\t白泽居-字符串1-www.baizeju.com\n
    This is Text:Txt (441[8,33],465[8,57]): 白泽居-链接文本-www.baizeju.com
    visitEndTag:/a
    This is Text:Txt (469[8,61],472[9,1]): \n\t
    visitEndTag:/div
    This is Text:Txt (478[9,7],507[11,0]): \n\t白泽居-字符串2-www.baizeju.com\n
    visitEndTag:/div
    This is Text:Txt (513[11,6],515[12,0]): \n
    visitEndTag:/body
    This is Text:Txt (522[12,7],524[13,0]): \n
    visitEndTag:/html
    finishedParsing
    可以看到,所有的子节点都出现了,除了刚刚例子里面的两个最上层节点This is Tag:head和This is Tag:html xmlns="http://www.w3.org/1999/xhtml"。

    想让它们都出来,只需要
    NodeVisitor visitor = new NodeVisitor( true, true) {
    输出结果:
    beginParsing
    This is Tag:!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    This is Text:Txt (121[0,121],123[1,0]): \n
    This is Tag:head
    This is Tag:meta http-equiv="Content-Type" content="text/html; charset=gb2312"
    This is Tag:title
    This is Text:Txt (204[1,81],229[1,106]): 白泽居-title-www.baizeju.com
    visitEndTag:/title
    visitEndTag:/head
    This is Text:Txt (244[1,121],246[2,0]): \n
    This is Tag:html xmlns="http://www.w3.org/1999/xhtml"
    This is Text:Txt (289[2,43],291[3,0]): \n
    This is Tag:body
    This is Text:Txt (298[3,7],300[4,0]): \n
    This is Tag:div id="top_main"
    This is Text:Txt (319[4,19],322[5,1]): \n\t
    This is Tag:div id="logoindex"
    This is Text:Txt (342[5,21],346[6,2]): \n\t\t
    This is Remark:这是注释 白泽居-www.baizeju.com
    This is Text:Txt (378[6,34],408[8,0]): \n\t\t白泽居-字符串1-www.baizeju.com\n
    This is Tag:a href="http://www.baizeju.com"
    This is Text:Txt (441[8,33],465[8,57]): 白泽居-链接文本-www.baizeju.com
    visitEndTag:/a
    This is Text:Txt (469[8,61],472[9,1]): \n\t
    visitEndTag:/div
    This is Text:Txt (478[9,7],507[11,0]): \n\t白泽居-字符串2-www.baizeju.com\n
    visitEndTag:/div
    This is Text:Txt (513[11,6],515[12,0]): \n
    visitEndTag:/body
    This is Text:Txt (522[12,7],524[13,0]): \n
    visitEndTag:/html
    finishedParsing
    哈哈,这下调用清楚了,大家在需要处理的地方增加自己的代码好了。


    4.2 其他Visitor
    HTMLParser还定义了几个其他的Visitor。HtmlPage,NodeVisitor,ObjectFindingVisitor,StringFindingVisitor,TagFindingVisitor,TextExtractingVisitor,UrlModifyingVisitor,它们都是NodeVisitor的子类,实现了一些特定的功能。笔者个人的感觉是没什么用处,如果你需要什么特定的功能,还不如自己写一个,想在这些里面找到适合你需要的,化的时间可能更多。反正大家看看代码就发现,它们每个都没几行真正有效的代码。

  • 相关阅读:
    关于flume配置加载
    ListMultimap 容器
    HotSpotOverview.pdf
    芝麻西瓜
    念念不忘必有回响
    phpstrom代码格式化
    小总结
    Redis支持的数据类型
    如何通过phpstorm查看某一行代码的变更记录
    mysql自动添加时间
  • 原文地址:https://www.cnblogs.com/5tao/p/1859731.html
Copyright © 2011-2022 走看看