Perl: непредвиденное поведение при просмотре веб-сайтов - PullRequest
3 голосов
/ 20 июня 2011

Я использую 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;
    }
}
}    

Ответы [ 5 ]

6 голосов
/ 20 июня 2011

Для таких задач я предпочитаю использовать 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
    }
}
2 голосов
/ 22 июня 2011

Выход из цикла while, когда вы нашли то, что искали, в противном случае он продолжает цикл.

 while ( $tag = $stream->get_tag('td') ) {
    if( $tag->[1]{class} eq 'dateStamp' ) {
        $dt = $stream->get_trimmed_text('/td');
                    ...
                    ... 
        last;
    }
}
2 голосов
/ 20 июня 2011

Иногда на сайте происходят изменения.Я часто использую 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
1 голос
/ 23 июня 2011

Мне кажется, что это больше проблема с завершением цикла, чем с TokeParser.Похоже, ваш цикл продолжает повторяться даже после того, как вы получите искомое значение.

Возможно, вы захотите сделать что-то вроде:

While($x) {

  .
  .
  .
  last if ($foundWhatINeeded)
}
1 голос
/ 22 июня 2011

Вы передаете $comid своей функции. В цикле while вы сначала устанавливаете $info, а затем сравниваете его с $comid. Если два значения совпадают, вы выходите из функции. Если они не совпадают, вы отправляете электронное письмо.

Как только письмо отправлено, цикл продолжается и обрабатывает следующий тег. Когда вы в следующий раз сравните $info и $comid, я думаю, что они будут другими, поскольку вы перешли к следующему тегу. Поэтому будет отправлено другое письмо.

Я не знаю, является ли это предполагаемым поведением - вы намереваетесь отправить одно электронное письмо для каждого обновления в таблице или только одно электронное письмо, если были какие-либо обновления в таблице? Если вам просто нужно отправить одно электронное письмо, независимо от того, сколько обновлений было, тогда просто выйдите из цикла после того, как первое электронное письмо было отправлено - как предложено manu_v.

Я бы также посмотрел на рефакторинг вашего кода, чтобы он был более надежным - все вызовы get_tag кажутся немного неубедительными. Ознакомьтесь с другими ответами на предложения о том, как это сделать.

...