【问题标题】:HTML::Treebuilder - Parse between parentsHTML::Treebuilder - 父母之间的解析
【发布时间】:2011-04-21 23:03:50
【问题描述】:

伙计们,

关于 HTML::Treebuilder 的信息太多了,我很惊讶我找不到答案,希望我不仅仅是错过了它。

我要做的只是在父节点之间解析,所以给定一个像这样的 html 文档

<html>
<body>
   <a id="111" name="111"></a>
   <p>something</p>
   <p>something</p>
   <p>something</p>
   <a href=xxx">something</a>
   <a id="222" name="222"></a>
   <p>something</p>
   <p>something</p>
   <p>something</p>
   ....
 </body>
 </html>

我希望能够获取关于第一个锚标签 (111) 的信息,然后处理 3 p 标签,然后获取下一个锚标签 (222),然后处理那些 p 标签等。

很容易找到每个锚标签

use HTML::TreeBuilder;
my $tree = HTML::TreeBuilder->new();
$tree->parse_file("index-01.htm");
foreach my $atag ( $tree->look_down( '_tag', 'a' ) ) {
    if ($atag->attr('id')) {
        # Found 'a' tag, now process the p tags until the next 'a'
    }
}

但是一旦我找到了那个标签,我该如何获取所有的 p 标签直到下一个锚点?

TIA!!

【问题讨论】:

    标签: perl html-parsing


    【解决方案1】:

    HTML::TreeBuilder 版本

    #!/usr/bin/perl
    
    use strict; use warnings;
    use HTML::TreeBuilder;
    
    my $tree = HTML::TreeBuilder->new;
    
    $tree->parse_file(\*DATA);
    $tree->elementify;
    $tree->objectify_text;
    
    foreach my $atag ( $tree->look_down( '_tag', 'a' ) ) {
        if ($atag->attr('id')) {
            printf "Found %s\n", $atag->as_XML;
            process_p( $atag );
        }
    }
    
    sub process_p {
        my ($tag) = @_;
        while ( defined( $tag ) and defined( my $next = $tag->right ) ) {
            last if lc $next->tag eq 'a';
            if ( lc $next->tag eq 'p') {
                $next->deobjectify_text;
                print $next->as_text, "\n";
            }
            $tag = $next;
        }
    }
    
    __DATA__
    <html>
    <body>
       <a id="111" name="111"></a>
       <p>something</p>
       <p>something</p>
       <p>something</p>sometext
       <a href=xxx">something</a>
       <a id="222" name="222"></a>
       <p>something</p>
       <p>something</p>
       <p>something</p>
     </body>
     </html>
    

    输出:

    Found <a id="111" name="111"></a>
    
    something
    something
    something
    Found <a id="222" name="222"></a>
    
    something
    something
    something
    

    HTML::TokeParser::简单版

    #!/usr/bin/perl
    
    use strict; use warnings;
    use HTML::TokeParser::Simple;
    
    my $parser = HTML::TokeParser::Simple->new(\*DATA);
    
    while ( my $tag = $parser->get_tag('a') ) {
        next unless $tag->get_attr('id');
        printf "Found %s\n", $tag->as_is;
        process_p($parser);
    }
    
    sub process_p {
        my ($parser) = @_;
        while ( my $next = $parser->get_token ) {
            if ( $next->is_start_tag('a') ) {
                $parser->unget_token($next);
                return;
            }
            elsif ( $next->is_start_tag('p') ) {
                print $parser->get_text('/p'), "\n";
            }
        }
        return;
    }
    

    输出:

    Found <a id="111" name="111">
    something
    something
    something
    Found <a id="222" name="222">
    something
    something
    something
    

    【讨论】:

    • 感谢思南,这几乎是完美的。我刚刚注意到 html 中的一个问题,HTML 中的一些“

      something

      ”标签实际上看起来像“

      something

      sometext”。当我尝试运行上述内容时,我得到“无法通过包 sometext 定位对象方法“标签””。
    • 有什么方法可以检查出现的“sometext”,并且能够继续没有错误?蒂亚!!
    • 这让事情变得很麻烦。那是因为字符串没有包裹在HTML::Element 中。我会在几分钟后发布解决方案。
    • @Chris 完成!但是,我开始认为HTML::TokeParser::Simple 可能更适合这项任务。
    • 嗯,我仍然遇到同样的错误,现在唯一的区别是我收到“$text->attr('text')”是未初始化值的警告。你认为我应该使用 TokeParser::Simple 吗?我认为标签外的文本也可能有问题,但我会试一试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    相关资源
    最近更新 更多