我正在使用WWW::Mechanize
和HTML::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;
}
}
}
答案 0 :(得分: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
}
}
答案 1 :(得分: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 :(得分:2)
当你匹配你想要的东西时,从while循环退出,否则它会一直循环。
while ( $tag = $stream->get_tag('td') ) {
if( $tag->[1]{class} eq 'dateStamp' ) {
$dt = $stream->get_trimmed_text('/td');
...
...
last;
}
}
答案 3 :(得分:1)
您将$comid
传递给您的函数。在while循环中,首先设置$info
,然后将其与$comid
进行比较。如果两个值匹配,则退出该函数。如果不匹配,请发送电子邮件。
电子邮件发送完毕后,循环继续,并处理下一个标记。当您下次比较$info
和$comid
时,我猜他们将会有所不同,因为您已转到下一个标记。因此,将发送另一封电子邮件。
我不知道这是否是预期的行为 - 您是打算为表中的每个更新发送一封电子邮件,还是只有一封电子邮件,如果表中有任何更新?如果您只需要发送一封电子邮件,无论有多少更新,只需在发送第一封电子邮件后退出循环 - 按照manu_v的建议。
我还会考虑重构您的代码以使其更强大 - 所有get_tag
调用看起来都有点脆弱。查看其他答案以获取有关如何执行此操作的建议。
答案 4 :(得分:1)
听起来我觉得循环终止比使用TokeParser更具问题。听起来你的循环即使在你得到你正在寻找的值之后也会继续迭代。
您可能希望执行以下操作:
While($x) {
.
.
.
last if ($foundWhatINeeded)
}