Хотя было вернуться к себе на рабочие место, но природное любопытство пересилило и я решил пойти посмотреть, что твориться у оптимизаторов. Оказалось, все просто - на экранах мельтешили окна, все были ужасно заняты, а дым шел от клавиатур - плавилась пластмасса от такой нагрузки!
Когда мне наконец-то удалось привлечь к себе внимание, выяснил, что для какого-то исследования оптимизатором надо было закачать несколько десятков тысяч web страниц. Что за исследования и где они взяли этот список url я уточнять не стал, просто пожелал им плодотворной работы, а сам запомнил где лежит этот список url.
Да, придется ликвидировать причину дымa, - подумал я на обратной дороге. Нет, оптимизаторов я ликвидировать не собирался, просто решил им сделать скриптик, которых закачает все эти странички, тем более, что у меня уже был опыт работы с модулем LWP::Parallel::UserAgent.
Задача сводилась к тому, чтобы по мере обработки читать с файла новые url, асинхронно запрашивать страницы и записывать HTTP ответы в файлы. Конечно можно было все сделать последовательно, но уж больно много времени потребовалось бы на это.
Как оказалось, для организации такого конвейера более подходит модуль HTTP::Async, а не LWP::Parallel::UserAgent.
Вот примерный код, который использовался для этого (работа с файлами опущена):
use HTTP::Message 1.57;
use HTTP::Request;
use HTTP::Async;
my @urls = (
'http://www.perl.com',
'http://www.perl.org',
'http://perlmonks.org',
'http://www.pm.org',
'http://kiev.pm.org',
'http://www.parrot.org',
'http://www.parrotcode.ks.ua',
);
my $async = HTTP::Async->new;
my $max_connects = 3;
my $cnt = @urls > $max_connects ? $max_connects : @urls;
add_request() foreach (1 .. $cnt);
while ( my $res = $async->wait_for_next_response ) {
if($res->is_success()) {
print "Succeeded for '", $res->request->url, "'\n";
# print $res->content, "\n";
}
add_request();
}
sub add_request {
my $url = shift @urls or return;
my $req = HTTP::Request->new(GET => $url,
['User-Agent' => "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)"]);
$async->add($req);
}
В это пример первоначально создается $max_connects запросов и по мере их завершения, создаются все новые и новые.
Все очень просто. Но опять у меня проснулась любопытство: а нельзя это все таки для такой конвейерной обработки приспособить модуль LWP::Parallel::UserAgent?
Оказалось можно. Для этого просто нужно переопределить события on_return и on_failure:
$SIG{PIPE} = 'IGNORE';
use LWP::Parallel::UserAgent;
my @urls = (
'http://www.perl.com',
'http://www.perl.org',
'http://perlmonks.org',
'http://www.pm.org',
'http://kiev.pm.org',
'http://www.parrot.org',
'http://www.parrotcode.ks.ua',
);
my $ua = LWP::Parallel::UserAgent->new();
$ua->agent("Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)");
$ua->nonblock(1);
my $max_connects = 3;
my $cnt = @urls > $max_connects ? $max_connects : @urls;
add_request() foreach (1 .. $cnt);
sub add_request {
my $url = shift @urls or return;
my $req = HTTP::Request->new(GET => $url);
$ua->register($req);
}
{
no warnings;
sub LWP::Parallel::UserAgent::on_return {
my ($self, $request, $response, $entry) = @_;
if($response->is_success()) {
print "Succeeded for '", $response->request->url, "'\n";
}
add_request();
}
sub LWP::Parallel::UserAgent::on_failure { add_request() }
}
my $entries = $ua->wait(3);
Что ж не так красиво, как при использовании HTTP::Async, но свою задачу этот код выполняет. Разве что очень не понравилась необходимость установить $SIG{PIPE} = 'IGNORE';
Ну вот и все история... :-) Да... давно это было... Но тем не-менее, кому-то может и пригодиться этот опыт и сейчас.
Копия: http://kiev.pm.org/node/253
1 комментарий:
хостинг спб хостинг http://hosting.miheeff.ru хостинг спб
Отправить комментарий