3

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

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

如果不仔细检查列表中的每个项目,似乎每个条目都有几个<div>元素,但只有一个<div>'s 中有<p>元素。并且没有一个<div>'s 有课程,这会使这很容易。

我尝试了几种不同的方法,因此似乎没有任何方法可以提取我想要的文本。我看过几个不同的例子,但没有一个真的与我正在寻找的足够接近。

如果这样的事情有效,那就太好了:

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

但这给了我错误:

param list to look_down ends in a key!

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

谢谢!

约翰

4

4 回答 4

3

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

该程序显示了它的用途。匿名子例程使用 grep 检查传递给它的节点的子节点,计算所有具有p标记的元素。然后该数组@divs包含所有div具有p子元素的元素。您可能希望确保@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]');

结果与上面的代码相同。

于 2013-08-17T13:33:31.460 回答
2

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

你需要做的是<div>先解析s,然后再解析<p>s。您不能使用 HTML::TreeBuilder 一次性完成。<div>您将从第一个 s 中获得每个 s 的HTML::Element 对象foreach。让他们look_down<p>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>
于 2013-08-17T12:34:14.583 回答
2

我建议为此使用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>
于 2013-08-17T13:30:03.217 回答
0
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;
于 2013-08-17T12:24:32.053 回答