此代码的目的是解析HTML文件,并返回包装有具有data-reader
属性的标签的内容。
这可以按需工作,但是我也想获取关联的HTML标签,但是我不知道如何在抓取数据中返回它。
这可能吗?
#!/usr/bin/perl -T
use strict;
use warnings;
use Web::Scraper;
my $html = do { local $/; <DATA> };
my $s = scraper {
process '*', 'links[]' => '@data-reader';
process '*', 'content[]' => 'text';
};
my $res = $s->scrape($html);
for my $i (0 .. @{ $res->{links} } ) {
if ($res->{links}[$i]) {
print "<??>$res->{content}[$i]</??>\n";
}
}
exit;
__DATA__
<h1 data-reader="on">Hello <em>world</em></h1>
<h2>This is subheading</h2>
<h3 style="color:#000;" data-reader="on" class="phead">Paragraph Heading</h3>
输出:
<??>Hello world</??>
<??>Paragraph Heading</??>
答案 0 :(得分:4)
#!/usr/bin/perl
use strict;
use warnings;
use Web::Scraper;
use HTML::Entities;
my $html = do { local $/; <DATA> };
my $s = scraper {
process '[data-reader]', 'list[]' => {
tag => sub { $_->tag },
content => 'TEXT',
};
result 'list';
};
my $results = $s->scrape($html);
for my $part (@$results) {
print "<$part->{tag}>" . encode_entities($part->{content}) . "</$part->{tag}>\n";
}
__DATA__
<h1 data-reader="on">Hello <em>world</em></h1>
<h2>This is subheading</h2>
<h3 style="color:#000;" data-reader="on" class="phead">Paragraph Heading</h3>
输出:
<h1>Hello world</h1>
<h3>Paragraph Heading</h3>
作为提取程序规范传递原始子例程的功能似乎没有记载,但是
所以我对使用它并不感到难过。
我正在将$part->{content}
重新编码为HTML,以避免在某些情况下发生问题,例如
<div data-reader="on"><script>alert(42)</script></div>
如果您只打印$part->{content}
,它会给您<script>alert(42)</script>
,这可能不是您想要的。
详细信息:
my $s = scraper {
process '[data-reader]', 'list[]' => {
tag => sub { $_->tag },
content => 'TEXT',
};
result 'list';
};
scraper
接受一段代码并将其包装在一个对象中。每次调用此对象的scrape
方法时,都会运行代码块。从理论上讲,您可以在该处执行任何操作,但唯一明智的操作是调用process
和result
。
process
接受三个(或更多)参数。第一个参数是CSS(或以//
或id(
开头的XPath)选择器。在这种情况下([data-reader]
,我们将选择所有具有data-reader
属性的元素。
其余参数为键/值对。 scraper
提供了一个隐式上下文(也称为“存储”),它只是放置结果的哈希。 “ key”参数指定提取结果应放在哪个哈希键下。如果“键”自变量以[]
结尾,则将其删除并且该值不是单个结果,而是对结果数组的引用。
在这里,我们将list[]
用作“ key”参数,这意味着我们将在隐藏的list
键下累积结果。
“ value”参数指定我们要在密钥下存储的值。可能的值包括TEXT
(节点的文本值)和@foo
(所讨论元素的foo
属性的值)。
这里我们使用的是哈希引用,这意味着我们要构造一个嵌套的subhash。哈希的每个键/值对均如上所述进行解释。我们获得了tag
(包含由the tag
method返回的标签名)和content
(包含元素的文本值)的条目。
效果就像scrape
包含以下循环:
my %stash;
for my $node (@found_nodes) {
push @{$stash{list}}, {
tag => $node->tag,
content => get_plain_text_somehow($node),
};
}
通常scrape
返回存储,但是如果scrape块包含result
(必须是该块中的最后一条语句),则可以使它仅返回一个键(或者如果您通过result
的多个字符串(仅包含键子集的哈希)。也就是说,由于result 'list'
,而不是
return \%stash;
我们有效地获得了
return $stash{list};