我正在尝试使用perl脚本解析html文件。我正在尝试用html标签p
grep所有文本。如果我查看源代码,数据将以这种格式写入。
<p>
指标都是特定于虚拟化的,并按优先顺序排列并按如下方式分组:</p>
以下是代码。
use HTML::TagParser();
use URI::Fetch;
//my @list = $html->getElementsByTagName( "p" );
foreach my $elem ( @list ) {
my $tagname = $elem->tagName;
my $attr = $elem->attributes;
my $text = $elem->innerText;
push (@array,"$text");
foreach $_ (@array) {
# print "$_\n";
print $html_fh "$_\n";
chomp ($_);
push (@array1, "$_");
}
}
}
$end = $#array1+1;
print "Elements in the array: $end\n";
close $html_fh;
我面临的问题是生成的输出是4.60 Mb,很多数组元素只是重复句子。我怎样才能避免这种重复?有没有其他有效的方法来grep我感兴趣的行。有人可以帮我解决这个问题吗?
答案 0 :(得分:3)
您看到重复行的原因是您要为其中的每个元素打印整个数组一次。
foreach my $elem ( @list ) {
my $tagname = $elem->tagName;
my $attr = $elem->attributes;
my $text = $elem->innerText;
push (@array,"$text"); # this array is printed below
foreach $_ (@array) { # This is inside the other loop
# print "$_\n";
print $html_fh "$_\n"; # here comes the print
chomp ($_);
push (@array1, "$_");
}
}
例如,如果您有一个数组"foo", "bar", "baz"
,它将打印:
foo # first iteration
foo # second
bar
foo # third
bar
baz
因此,要修复重复错误,请将第二个循环移到第一个循环之外。
其他一些说明:
您应该始终使用这两个编译指示:
use strict;
use warnings;
他们将提供比您可以做的任何其他单一事物更多的帮助。与修复错误相关的简短学习曲线可以弥补大大减少调试时间。
//my @list = $html->getElementsByTagName( "p" );
perl中的注释以#
开头。不确定这是否是拼写错误,因为你在下面使用这个数组。
foreach my $elem ( @list ) {
除非需要数组,否则无需将标记实际存储到数组中。仅在这种情况下,这是一个中间变量。您只需执行以下操作(请注意for
和foreach
完全相同):
for my $elem ($html->getElementsByTagName("p")) {
这些变量也是中间变量,其中两个未使用。
my $tagname = $elem->tagName;
my $attr = $elem->attributes;
my $text = $elem->innerText;
push (@array,"$text");
另请注意,您永远不必以这种方式引用变量。你可以这样做:
push @array, $elem->innerText;
foreach $_ (@array) {
默认情况下使用$_
变量,无需明确指定。
print $html_fh "$_\n";
chomp ($_);
push (@array1, "$_");
我不确定为什么你在打印之后chomp
变量,但在将它存储在另一个数组之前,但它似乎没有意义对我来说。此外,该另一个数组将包含与另一个数组完全相同的元素,仅重复。
$end = $#array1+1;
这是另一个中间变量,也可以简化。 $#
sigil将为您提供最后一个元素的索引,但是标量上下文中的数组本身将为您提供它的大小:
$end = @array1; # size = last index + 1
但你可以一次性做到这一点:
print "Elements in the array: " . @array1 . "\n";
请注意,在此使用连接运算符.
会强制执行数组上的标量上下文。如果您使用了逗号运算符,
,它将具有列表上下文,并且该数组将已扩展为其元素列表。这是通过上下文进行操作的典型方法。
close $html_fh;
不需要显式关闭文件句柄,因为它会在脚本结束时自动关闭。
答案 1 :(得分:2)
如果您使用Web::Scraper代替,您的代码会变得更简单和清晰(只要您能够构建CSS选择器或XPath查询):
#!/usr/bin/env perl
use strict;
use warnings qw(all);
use URI;
use Web::Scraper;
my $result = scraper {
process 'p',
'paragraph[]' => 'text';
}->scrape(URI->new('http://www.perl.org/'));
for my $test (@{$result->{paragraph}}) {
print "$test\n";
}
print "Elements in the array: " . (scalar @{$result->{paragraph}});
答案 2 :(得分:2)
以下是另一种获取<p>
代码之间所有内容的方法,这次使用Mojo::DOM
项目的Mojolicious
部分。
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10; # say
use Mojo::DOM;
my $html = <<'END';
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<div>Should not find this</div>
<p>Paragraph 3</p>
END
my $dom = Mojo::DOM->new($html);
my @paragraphs = $dom->find('p')->pluck('text')->each;
say for @paragraphs;