【问题标题】:locating div with paragraph in perl with HTML::TreeBuilder使用 HTML::TreeBuilder 在 perl 中使用段落定位 div
【发布时间】:2013-08-18 15:45:42
【问题描述】:

我正在尝试找出在 Perl 中使用 HTML::TreeBuilder 从 XML 文件中的某些 HTML 中提取几段文本的最佳方法。

我使用$tree->address(或者我认为)让它工作,直到我意识到并非所有条目的顺序都相同。

如果不检查列表中的每一项,似乎每个条目都有几个<div> 元素,但<div> 中只有一个有<p> 元素。并且<div> 都没有类,这会使这变得容易。

我尝试了几种不同的方法,因此似乎没有任何方法可以提取我想要的文本。我查看了几个不同的示例,但没有一个与我正在寻找的内容非常接近。

如果有这样的工作就好了:

$bodyText = $tree->look_down( '_tag' => 'div' => 'p' );

但这给了我错误:

param list to look_down ends in a key!

无论如何,也许有人可以帮我指出正确的方向,我一直在寻找整夜,现在我的脑痛。

谢谢!

约翰

【问题讨论】:

  • 您能添加一个 HTML 的 sn-p 示例吗?

标签: perl html tree builder


【解决方案1】:

对于HTML::TreeBuilder 的普通形式,最好使用代码引用作为look_down 的标准来完成。将为树中通过所有先前条件的每个节点调用子例程,如果子例程返回真值,则将保留一个节点。

这个程序展示了它的用途。匿名子例程使用 grep 检查传递给它的节点的子节点,计算所有具有p 标记的元素。然后数组@divs 包含所有具有p 子元素的div 元素。您可能希望确保 @divs 只包含一个元素。

use strict;
use warnings;

use feature 'say';

use HTML::TreeBuilder;

my $doc = HTML::TreeBuilder->new_from_content(<<__HTML__);
<div>content</div>
<div>content</div>
<div><p>paragraph</p></div>
<div>content</div>
<div>content</div>
__HTML__

my @divs = $doc->look_down(
  _tag => 'div', 
  sub { grep { ref eq 'HTML::Element' and  $_->tag eq 'p' } $_[0]->content_list }
);

say scalar @divs, " found:\n";
say $divs[0]->as_HTML('<>&', '  ');

输出

1 found:

<div>
  <p>paragraph</div>

但是,使用增强的HTML::TreeBuilder::XPath 会更加简洁,它允许使用 XPath 表达式来处理数据。这允许将look_down 替换为findnodes 调用:

my @divs = $doc->findnodes('//div[p]');

结果和上面的代码是一样的。

【讨论】:

  • 尝试您的第一个示例,我收到以下错误:Can't call method "isa" without a package or object reference at ... 但不知道为什么?
  • @JohnB:我很抱歉。我忘了你不能在空字符串上调用isa。我已经修好了。
【解决方案2】:

您的错误信息是有道理的。 look_down 方法需要一个散列(当然是一个列表)。你给它三个元素,所以最后一个是键。请记住,=&gt; 也称为 fat comma,只是编写, 的一种更易读的方式。不过,这有点奇怪的错误消息。

你需要做的是先解析&lt;div&gt;s,然后再解析&lt;p&gt;s。您不能使用 HTML::TreeBuilder 一次性完成。您将从第一个 foreach 获得每个 &lt;div&gt;s 的 HTML::Element 对象。让他们look_down&lt;p&gt;s。

use strict;
use warnings;
use feature qw( say );
use HTML::TreeBuilder 5 -weak;

my $tree = HTML::TreeBuilder->new_from_content(<DATA>);
foreach my $e ($tree->look_down(_tag => 'div')) {
  foreach my $f ($e->look_down(_tag => 'p')) {
    say $f->as_text;
  }
}

__DATA__
<html>
<body>
<div>foo</div>
<div><p>hello world</p></div>
<div>foo2</div>
<div>foo3</div>
<div><p>hello again</p></div>
</body>
</html>

【讨论】:

    【解决方案3】:

    我建议为此使用 XPath

    use strict;
    use warnings;
    use feature qw( say );
    use HTML::TreeBuilder::XPath;
    
    my $tree = HTML::TreeBuilder->new_from_content(<DATA>);
    foreach my $e ( $tree->findnodes('//div/p') ) {
    
        say $e->as_text;
    }
    
    __DATA__
    <html>
    <body>
    <div>foo</div>
    <div><p>hello world</p></div>
    <div>foo2</div>
    <div>foo3</div>
    <div><p>hello again</p></div>
    </body>
    </html>
    

    【讨论】:

      【解决方案4】:
      use Web::Query 'wq';
      print wq("<html><div><p>I'm trapped under a hat</p></div><div /><div /><div /><div /><div />")
              ->find('div p')->text;
      

      【讨论】:

      • 非常整洁。不过,一个解释会很好。 ;-)
      猜你喜欢
      • 2012-01-23
      • 2014-02-22
      • 2015-12-07
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 2021-04-30
      相关资源
      最近更新 更多