2011-06-20 12 views
3

私はWWW::MechanizeHTML::TokeParserを使用して、更新のためにウェブサイトを解析しています。私はログインが必要なので、ウェブサイトの詳細を与えることはできません。ウェブサイトには基本的にデータテーブルがあります。私はテーブルの最初の行に着くまでhtmlを解析しています。メールを送信しない場合は、最後のスクレイプの値を確認してください。これは、実際の更新が行われたときに擦り傷が私の最後の擦り傷で止まらないことを除いて、私が既存のテーブルエントリでそれをテストするとき、完全にうまく動作します。テーブルが使い果たされてこれが無期限に繰り返されるまで、メールを送信し続けます。私は何が起こっているのか理解できません。私は誰もがウェブサイトなしで確認することはできませんが、私はとにかく自分のコードを投稿している知っている。私は間違っているかもしれないことについてのアイデアを感謝します。Perl:ウェブサイトのスクレイピングで予期しない動作が発生する

コード:私はHTML::TableExtractを使用することを好むタスクのこの種の

sub func{ 
    my ($comid, $mechlink) = @_; 

    my $mechanize = WWW::Mechanize->new(
     noproxy => 0, 
     stack_depth => 5, 
     autocheck => 1 
    ); 

    $mechanize->proxy(https => undef); 
    eval{ 
      my $me = $mechanize->get($mechlink); 
      $me->is_success or die $me->status_line; 
    }; 
    return $comid if ([email protected]); 

    my $stream = HTML::TokeParser->new(\$mechanize->{content}) or die $!; 

    while ($tag = $stream->get_tag('td')) { 
    if($tag->[1]{class} eq 'dateStamp') { 
     $dt = $stream->get_trimmed_text('/td'); 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $name = $stream->get_trimmed_text('/td') if($tag->[1]{class} eq 'Name'); 
     return $comid unless($tag->[1]{class} eq 'Name'); 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $info = $stream->get_trimmed_text('/td'); 
     print "$name?\n"; 
     return $retval if($info eq $comid); 
     print "You've Got Mail! $info $comid\n"; 
     $tcount++; 
     $retval = $info if($tcount == 1); 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $tag = $stream->get_tag; 
     $link = "http://www.abc.com".$tag->[1]{href} if ($tag->[0] eq 'a'); 
     my $outlook = new Mail::Outlook(); 
     my $message = $outlook->create(); 
     $message->To('[email protected]'); 
     $message->Cc('[email protected];[email protected]'); 
     my $hd = "$name - $info"; 
     $message->Subject($hd); 
     $message->Body(" "); 
     $message->Attach($link); 
     $message->send; 
    } 
} 
}  
+0

はあなたのwhileループのコードを含めることができます。

あなたのような何かをしたいことがあります。これは事態が悪くなる可能性が高いです。 – Mike

+0

ログから詳細を確認できるように、アプリケーションログを追加することをお勧めします。さらに、メール送信カウンタと制御された停止も良いです。私はそのようなプログラムから数百回の電子メールを送ってきました。そして、私はそれがいかに迷惑になるかを知っています。 – weismat

+0

ループにコードを追加しました。メール送信カウンタの問題点は、まず、スクラップからスクラップまでどれだけの更新が予想されるかわかりません。第二に、私は制限を入れても、私は同じスクリプトを60秒ごとに実行するので、次の繰り返しは再びメールを送信し始めます – Aks

答えて

6

。非常に使いやすいです:

use HTML::TableExtract; 
$te = HTML::TableExtract->new(headers => [qw(header1 header2)]); 
$te->parse($html); 
foreach $ts ($te->tables) { 
    foreach $row ($ts->rows) { 
     my ($field1, $field2) = @$row; 
     # Your code here 
    } 
} 
2

時々、サイトに変更があります。私はしばしばWeb :: Scraperを使います。 XPathでget要素に書き込むことができます。

use Web::Scraper; 
use URI; 

my $uri = URI->new("http://...."); 
my $entries = scraper { 
    process 'id("content")/div[@class="section"]', 'news[]' => scraper { 
     process 'h2', title => 'TEXT'; 
     process 'p', body => 'TEXT'; 
    }; 
}; 

# if you have instance of WWW::Mechanize, set like following. 
# $entries->user_agent($mech); 

my $res = $entries->scrape($uri); 
for my $entry (@{$res->{news}}) { 
    # use $entry->title or $entry->body 
} 
# language: lang-perl 
2

探しているものと一致するときはwhileループを終了します。それ以外の場合はループし続けます。

while ($tag = $stream->get_tag('td')) { 
    if($tag->[1]{class} eq 'dateStamp') { 
     $dt = $stream->get_trimmed_text('/td'); 
        ... 
        ... 
     last; 
    } 
} 
+0

...私は最後の擦り傷に達したときに戻ります... – Aks

1

あなたの機能には$comidを渡します。 whileループでは、最初に$infoと設定し、これを$comidと比較します。 2つの値が一致する場合は、その関数を終了します。一致しない場合は、電子メールを送信します。

電子メールが送信されると、ループが続行され、次のタグが処理されます。次に$info$comidを比較すると、次のタグに移動したときとは違うと思います。したがって、別の電子メールが送信されます。

これは意図した動作であるかどうかわかりません。テーブルの更新ごとに1つの電子メールを送信する予定ですか、テーブルが更新されている場合は1つの電子メールだけですか?メールが1つだけ送信される必要がある場合は、更新回数にかかわらず、最初のメールが送信された後にループを終了します(manu_vの示唆どおり)。

コードをリファクタリングして、より堅牢なものにすることもできます。すべてのget_tagコールは少し軽薄であるようです。これを行う方法に関する提案については、他の答えを確認してください。

+0

その各更新ごとに1つの電子メール。ありがとう – Aks

+1

私はあなたのコードを正しく理解している場合、あなたの関数に渡された値( '$ comid')をテーブル(' $ info')の値と比較します。テーブルの値が更新されている場合は、新しい値を覚えておく必要があります。これにより、次回のスキャンで値を比較できるようになります。あなたがそれをしないと、テーブル値( '$ info')と古い値(' $ comid')を常に比較しています。これは常に古くなり、電子メールが送られます。更新された値がどこにどのように格納されているのかわかりません。 '$ comid'だけを返します。これは最初に関数に渡した値です。 – Mike

+0

スキャンしているテーブルのHTMLを投稿することもできます。データが機密である場合は、実際の値をダミー値で置き換えることができます。 – Mike

1

これは、TokeParserを使用する場合よりもループ終了の問題であると私には聞こえます。あなたが探している価値を得た後でさえ、あなたのループが繰り返し続けているように思えます。 - あなたはアップデートをチェックビット

While($x) { 

    . 
    . 
    . 
    last if ($foundWhatINeeded) 
} 
関連する問題