2

perlスクリプトを使用してhtmlファイルを解析しようとしています。すべてのテキストを html tag で grep しようとしていますp。ソースコードを見ると、データはこの形式で書かれています。

<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する他の効率的な方法はありますか? 誰でもこの問題で私を助けることができますか?

4

3 に答える 3

3

代わりに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}});
于 2012-12-09T14:11:45.103 に答える
3

重複した行が表示される理由は、配列全体をその中の要素ごとに 1 回印刷しているためです。

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

したがって、重複エラーを修正するには、2 番目のループを最初のループの外に移動します。

その他の注意事項:

次の 2 つのプラグマを常に使用する必要があります。

use strict;
use warnings;

彼らは、あなたができる他のどの単一のことよりも多くの助けを提供します. 表示されるエラーの修正に関連する短い学習曲線は、デバッグに費やされる大幅な時間の短縮を補って余りあります。

//my @list = $html->getElementsByTagName( "p" );

perl のコメントは で始まり#ます。以下でこの配列を使用しているため、これがタイプミスかどうかはわかりません。

foreach my $elem ( @list ) {

配列が必要でない限り、実際にタグを配列に格納する必要はありません。これは、この場合のみの中間変数です。次のことを簡単に実行できます (forforeachはまったく同じであることに注意してください)。

for my $elem ($html->getElementsByTagName("p")) {

これらの変数も中間であり、そのうちの 2 つは未使用です。

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、この別の配列に格納する前に変数を ing している理由はわかりませんが、私には意味がないようです。また、この他の配列には、他の配列とまったく同じ要素が含まれますが、重複するだけです。

$end = $#array1+1;

これは別の中間変数であり、単純化することもできます。シジルは最後の要素の$#インデックスを提供しますが、スカラー コンテキストの配列自体はそのサイズを提供します。

$end = @array1;   # size = last index + 1

しかし、これを一度に行うことができます:

print "Elements in the array: " . @array1 . "\n";

ここで連結演算子を使用する.と、配列にスカラー コンテキストが適用されることに注意してください。コンマ演算子を使用した場合,、リスト コンテキストがあり、配列はその要素のリストに展開されます。これは、コンテキストによって操作する典型的な方法です。

close $html_fh;

ファイル ハンドルはスクリプトの終了時に自動的に閉じられるため、明示的に閉じる必要はありません。

于 2012-12-09T08:12:36.073 に答える
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;
于 2012-12-09T16:01:03.313 に答える