LWP :: Simple - как внедрить в него цикл [с живой демонстрацией] - PullRequest
0 голосов
/ 26 февраля 2011

добрый вечер дорогая община!

Я хочу обрабатывать несколько веб-страниц, вроде веб-паука / сканера.У меня есть несколько битов - но теперь мне нужно немного улучшить логику паука.Смотрите целевой URL-адрес http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50

Эта страница содержит более 6000 результатов!Ну как мне получить все результаты?Я использую модуль LWP :: simple, и мне нужны улучшенные аргументы, которые я могу использовать, чтобы получить все 6150 записей

Попытка: Вот первые 5 страниц URL:

http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=0 
http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=50 
http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=100 
http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=150 
http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=200

Мы видим, что атрибут "s" в URL начинается с 0 для страницы 1, а затем увеличивается на 50 для каждой последующей страницы.Мы можем использовать эту информацию для создания цикла:

my $i_first = "0"; 
my $i_last = "6100"; 
my $i_interval = "50"; 

for (my $i = $i_first; $i <= $i_last; $i += $i_interval) { 
     my $pageurl = "http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=$i"; 
     #process pageurl 
}

tadmc (очень поддерживающий пользователь) создал отличный скрипт, который выдает результаты в формате cvs.я встроил этот цикл в код: (Примечание - я предполагаю, что что-то пошло не так! См. размышления ниже ... с фрагментами кода и сообщениями об ошибках:

#!/usr/bin/perl
use warnings;
use strict;
use LWP::Simple;
use HTML::TableExtract;
use Text::CSV;

my $i_first = "0"; 
my $i_last = "6100"; 
my $i_interval = "50"; 

for (my $i = $i_first; $i <= $i_last; $i += $i_interval) { 
     my $pageurl = "http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=$i"; 
     #process pageurl 
}

my $html= get 'http://192.68.214.70/km/asps/schulsuche.asp?q=n&a=50';
$html =~ tr/r//d;     # strip the carriage returns
$html =~ s/&nbsp;/ /g; # expand the spaces

my $te = new HTML::TableExtract();
$te->parse($html);

my @cols = qw(
    rownum
    number
    name
    phone
    type
    website
);

my @fields = qw(
    rownum
    number
    name
    street
    postal
    town
    phone
    fax
    type
    website
);

my $csv = Text::CSV->new({ binary => 1 });

foreach my $ts ($te->table_states) {
    foreach my $row ($ts->rows) {

trim leading/trailing whitespace from base fields
        s/^s+//, s/\s+$// for @$row;

load the fields into the hash using a "hash slice"
        my %h;
        @h{@cols} = @$row;

derive some fields from base fields, again using a hash slice
        @h{qw/name street postal town/} = split /n+/, $h{name};
        @h{qw/phone fax/} = split /n+/, $h{phone};

trim leading/trailing whitespace from derived fields
        s/^s+//, s/\s+$// for @h{qw/name street postal town/};

        $csv->combine(@h{@fields});
        print $csv->string, "\n";
    }
} 

ТамБыли некоторые проблемы - я сделал ошибку, я думаю, что ошибка здесь:

for (my $i = $i_first; $i <= $i_last; $i += $i_interval) { 
 my $pageurl = "http://192.68.214.70/km/asps/schulsuche.asp?q=e&a=50&s=$i"; 
      #process pageurl 
    }

my $html= get 'http://192.68.214.70/km/asps/schulsuche.asp?q=n&a=50';
$html =~ tr/r//d;     # strip the carriage returns
$html =~ s/&nbsp;/ /g; # expand the spaces

Я записал какой-то двойной код. Мне нужно пропустить одну часть ... этуздесь

my $html= get 'http://192.68.214.70/km/asps/schulsuche.asp?q=n&a=50';
$html =~ tr/r//d;     # strip the carriage returns
$html =~ s/&nbsp;/ /g; # expand the spaces

см. результаты в командной строке:

martin@suse-linux:~> cd perl
martin@suse-linux:~/perl> perl bavaria_all_.pl
Possible unintended interpolation of %h in string at bavaria_all_.pl line 52.
Possible unintended interpolation of %h in string at bavaria_all_.pl line 52.
Global symbol "%h" requires explicit package name at bavaria_all_.pl line 52.
Global symbol "%h" requires explicit package name at bavaria_all_.pl line 52.
syntax error at bavaria_all_.pl line 59, near "/,"
Global symbol "%h" requires explicit package name at bavaria_all_.pl line 59.
Global symbol "%h" requires explicit package name at bavaria_all_.pl line 60.
Global symbol "%h" requires explicit package name at bavaria_all_.pl line 60.
Substitution replacement not terminated at bavaria_all_.pl line 63.
martin@suse-linux:~/perl> 

что вы думаете !? с нетерпением ждем от вас

кстати - смотрите код, , созданный tadmc , без какой-либо улучшенной логики spider .... Это работает очень и очень удобно - без каких-либо проблем: он выдает хороший форматированный вывод cvs !!

#!/usr/bin/perl
use warnings;
use strict;
use LWP::Simple;
use HTML::TableExtract;
use Text::CSV;

my $html= get 'http://192.68.214.70/km/asps/schulsuche.asp?q=n&a=50';
$html =~ tr/r//d;     # strip the carriage returns
$html =~ s/&nbsp;/ /g; # expand the spaces

my $te = new HTML::TableExtract();
$te->parse($html);

my @cols = qw(
    rownum
    number
    name
    phone
    type
    website
);

my @fields = qw(
    rownum
    number
    name
    street
    postal
    town
    phone
    fax
    type
    website
);

my $csv = Text::CSV->new({ binary => 1 });

foreach my $ts ($te->table_states) {
    foreach my $row ($ts->rows) {

trim leading/trailing whitespace from base fields
        s/^s+//, s/\s+$// for @$row;

load the fields into the hash using a "hash slice"
        my %h;
        @h{@cols} = @$row;

derive some fields from base fields, again using a hash slice
        @h{qw/name street postal town/} = split /n+/, $h{name};
        @h{qw/phone fax/} = split /n+/, $h{phone};

trim leading/trailing whitespace from derived fields
        s/^s+//, s/\s+$// for @h{qw/name street postal town/};

        $csv->combine(@h{@fields});
        print $csv->string, "\n";
    }
} 

Примечание: этот вышеупомянутый код работает хорошо - он выдает вывод в формате csv.

Ответы [ 2 ]

1 голос
/ 26 февраля 2011

Другой подход к достижению подкачки заключается в извлечении всех URL-адресов со страницы и определении URL-адресов пейджера.

... 
for (@urls) { 
    if (is_pager_url($_) and not exists $seen{$_}) {
         push @pager_url, $_; 
         $seen{$_}++; 
    }
}
... 

sub is_pager_url { 
    my ($url) = @_; 
    return 1 if $url =~ m{schulsuche.asp\?q=e\&a=\d+\&s=\d+};
}

Таким образом, вам не нужно иметь дело с приращением счетчиков или установкой общего количества страниц.Это также будет работать для разных значений a и s.Сохраняя% увиденного хэша, вы можете дешево избежать разграничения между предыдущей и следующей страницами.

1 голос
/ 26 февраля 2011

Отлично!Я ждал, чтобы вы выяснили, как самостоятельно получить несколько страниц!

1) поместите мой код в цикла получения страниц (переместите "}" вниздо конца).

2) $ html = get $ pageurl;# измените это, чтобы использовать ваш новый URL

3) поместите мою обратную косую черту туда, где она была у меня: tr / \ r // d;

...