улучшение LWP :: Простая производительность Perl - PullRequest
3 голосов
/ 25 июня 2011

Увы, у меня есть еще один вопрос:

Мне было поручено прочитать веб-страницу и извлечь ссылки с этой страницы (легко с HTML :: TokeParser).Затем он (мой начальник) настаивает на том, чтобы я прочитал по этим ссылкам и взял некоторые детали с каждой из этих страниц, а затем проанализировал ВСЮ эту информацию в файле XML, который впоследствии можно будет прочитать.

Итак, я могуустановите это довольно просто, например, так:

#!/usr/bin/perl -w

use     strict;
use     LWP::Simple; 
require HTML::TokeParser; 

$|=1;                        # un buffer

my $base = 'http://www.something_interesting/';
my $path = 'http://www.something_interesting/Default.aspx';
my $rawHTML = get($path); # attempt to d/l the page to mem

my $p = HTML::TokeParser->new(\$rawHTML) || die "Can't open: $!";

open (my $out, "> output.xml") or die;

while (my $token = $p->get_tag("a")) {

    my $url = $token->[1]{href} || "-";

    if ($url =~ /event\.aspx\?eventid=(\d+)/) {
        ( my $event_id = $url ) =~ s/event\.aspx\?eventid=(\d+)/$1/;
        my $text = $p->get_trimmed_text("/a");
        print $out $event_id,"\n";
        print $out $text,"\n";

        my $details = $base.$url;
        my $contents = get($details);

        # now set up another HTML::TokeParser, and parse each of those files.

    }
}

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

Я хотел просто написать что-то, что толькополучает информацию по мере необходимости (например, Java-приложение, которое ищет информацию по нужной ссылке) ... однако, это кажется неприемлемым, поэтому я обращаюсь к вам, ребята:)

Есть ли способ улучшить этот процесс?

Ответы [ 6 ]

5 голосов
/ 25 июня 2011

Вероятно, вы увидите увеличение скорости - за счет менее простого кода - если вы выполните свои get() с параллельно, а не последовательно.

Parallel :: ForkManager - это то место, с которого я бы начал (и даже включает пример LWP :: Simple get() в своей документации), но есть множество других альтернатив, которые можно найти на CPAN , включая довольно датированный LWP :: Parallel :: UserAgent .

4 голосов
/ 25 июня 2011

Если вы хотите извлечь более одного элемента с сервера и сделать это быстро, используйте TCP Keep-Alive. Отбросьте упрощенный LWP::Simple и используйте обычный LWP::UserAgent с опцией keep_alive. Это настроит кэш подключения, поэтому вы не будете тратить время на подключение TCP при получении большего количества страниц с одного хоста.

use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;

my @urls = @ARGV or die 'URLs!';
my %opts = ( keep_alive => 10 ); # cache 10 connections
my $ua = LWP::UserAgent->new( %opts );
for ( @urls ) {
        my $req = HEAD $_;
        print $req->as_string;
        my $rsp = $ua->request( $req );
        print $rsp->as_string;
}

my $cache = $ua->conn_cache;
my @conns = $cache->get_connections;
# has methods of Net::HTTP, IO::Socket::INET, IO::Socket
2 голосов
/ 25 июня 2011

WWW :: Mechanize - отличная работа для начала, и если вы смотрите на модули, я бы также предложил Web :: Scraper

У обоих есть документы по указанным мною ссылкам, и они должны помочь вам быстро начать работу.

0 голосов
/ 26 ноября 2012

Ваша проблема заключается в том, что утилизация требует больше ресурсов процессора, чем интенсивного ввода-вывода. Хотя большинство людей здесь предложили бы вам использовать больше ЦП, я постараюсь показать большое преимущество использования Perl в качестве «связующего» языка. Все согласны с тем, что Libxml2 является отличным парсером XML / HTML. Кроме того, libcurl является отличным агентом загрузки. Однако во вселенной Perl многие скреберы основаны на LWP :: UserAgent и HTML :: TreeBuilder :: XPath (который похож на HTML :: TokeParser, хотя и совместим с XPath). В этом случае вы можете использовать вставные модули замены для обработки загрузок и анализа HTML через libcurl / libxml2:

use LWP::Protocol::Net::Curl;
use HTML::TreeBuilder::LibXML;
HTML::TreeBuilder::LibXML->replace_original();

Я увидел увеличение скорости в среднем в 5 раз, просто добавив эти 3 строки в несколько скребков, которые я поддерживал. Но, поскольку вы используете HTML :: TokeParser, я бы рекомендовал вам вместо этого попробовать Web :: Scraper :: LibXML (плюс LWP :: Protocol :: Net :: Curl, который влияет как на LWP :: Simple и Web :: Scraper).

0 голосов
/ 28 июня 2011
use strict;
use warnings;

use threads;  # or: use forks;

use Thread::Queue qw( );

use constant MAX_WORKERS => 10;

my $request_q  = Thread::Queue->new();
my $response_q = Thread::Queue->new();

# Create the workers.
my @workers;
for (1..MAX_WORKERS) {
   push @workers, async {
      while (my $url = $request_q->dequeue()) {
         $response_q->enqueue(process_request($url));
      }
   };
}

# Submit work to workers.
$request_q->enqueue(@urls);

# Signal the workers they are done.    
for (1..@workers) {
   $request_q->enqueue(undef);
}

# Wait for the workers to finish.
$_->join() for @workers;

# Collect the results.
while (my $item = $response_q->dequeue()) {
   process_response($item);
}
0 голосов
/ 25 июня 2011

Существует большая вероятность, что он блокирует запрос http get, ожидая ответа от сети. Используйте асинхронную библиотеку http и посмотрите, поможет ли это.

...