3

我正在使用WWW::MechanizeHTML::TokeParser解析网站以获取更新。我无法在网站上提供任何详细信息,因为它需要登录。该网站基本上有一个数据表。我只是解析 html 直到我到达表格的第一行,检查它是否是我最后一次抓取的值,如果没有发送邮件。当我在现有表条目上对其进行测试时,这非常有效,除非发生实际更新时,抓取不会在我最后一次抓取时停止。它一直发送邮件,直到表用完并无限期地重复。我无法弄清楚发生了什么。我知道没有网站,没有多少人可以验证,但无论如何我都会发布我的代码。我会很感激关于可能出错的想法。

代码:

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 ($@);  

    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('abc@def.com');
        $message->Cc('abc@def.com;abc@def.com');
        my $hd = "$name - $info";  
        $message->Subject($hd);
        $message->Body(" ");
        $message->Attach($link);
        $message->send;
    }
}
}    
4

5 回答 5

6

对于这类任务,我更喜欢使用HTML::TableExtract。它非常易于使用:

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
    }
}
于 2011-06-20T07:47:50.900 回答
2

有时,网站会发生变化。我经常使用 Web::Scraper。可以使用 XPath 编写获取元素。

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
于 2011-06-20T10:02:20.563 回答
2

当您匹配到您要查找的内容时退出 while 循环,否则它会继续循环。

 while ( $tag = $stream->get_tag('td') ) {
    if( $tag->[1]{class} eq 'dateStamp' ) {
        $dt = $stream->get_trimmed_text('/td');
                    ...
                    ... 
        last;
    }
}
于 2011-06-22T08:14:43.373 回答
1

你传递$comid给你的函数。在您的 while 循环中,您首先设置$info,然后将其与$comid. 如果两个值匹配,则退出该函数。如果它们不匹配,则发送电子邮件。

发送电子邮件后,循环继续,并处理下一个标签。当您下次比较$info$comid时,我猜它们会有所不同,因为您已经转到下一个标签。因此将发送另一封电子邮件。

我不知道这是否是预期的行为 - 您是否打算为表格中的每个更新发送一封电子邮件,或者如果表格有任何更新则只发送一封电子邮件?如果您只需要发送一封电子邮件,无论有多少更新,那么只需在发送第一封电子邮件后退出循环 - 正如 manu_v 所建议的那样。

我还会考虑重构您的代码,使其更加健壮 - 所有get_tag调用似乎都有点脆弱。查看其他答案以获取有关如何执行此操作的建议。

于 2011-06-22T08:49:25.480 回答
1

对我来说,这更像是循环终止的问题,而不是 TokeParser 的问题。听起来您的循环即使在您获得所需的值之后仍在继续迭代。

您可能想要执行以下操作:

While($x) {

  .
  .
  .
  last if ($foundWhatINeeded)
}
于 2011-06-23T14:35:28.677 回答