2011-06-24 39 views
3

ああ、私はまた別の質問があります。彼(私の上司)は、これらのリンクから読んで、それらのページのそれぞれからいくつかの詳細を取得し、その情報のすべてをxmlファイルに解析して、後で読むことができると主張します。向上LWP :: SimpleはPerlのパフォーマンス

だから、私はそうのようにかなり単純にこれを設定することができますこのページで多分5のリンクがあった場合

#!/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. 

    } 
} 

は、これはおそらくOKでしょう。しかし、私は〜600リンクから読み込み、これらのページのそれぞれから情報を取得しようとしています。だから言うまでもなく、私の方法は長い時間がかかります...私は正直なところ、どれくらいの時間がかかっているのか分かりません。

私は、必要に応じて情報を取得するだけのものを書くことを考えました(たとえば、必要なリンクから情報を参照するJavaアプリケーション)...しかし、これは受け入れられないようですだから私は皆さんに頼んでいます:)

このプロセスを改善する方法はありますか?

答えて

5

get()を連続して実行するのではなく、簡単なコードを犠牲にして、速度の向上が見込まれます。

Parallel::ForkManagerは私が開始する場所である(とさえLWP ::そのドキュメントの簡単なget()例を含みます)が、他の選択肢をたっぷりかなり時代遅れLWP::Parallel::UserAgent含め、CPANに発見されるがあります。

+0

これは私が探していたものです。ありがとうございます。他の答えも有用でした。皆さんありがとうございました:) – Aelfhere

+0

@Aelfhere、私はForkManagerの問題を解決する前に、それを削除する予定でした。 – ikegami

2

WWW::Mechanizeは仕事の素晴らしい作品がで開始すると、あなたはモジュールを見ているならば、私もWeb::Scraper

両方が、私は提供されたリンクのドキュメントを持っていて、すぐに軌道に乗るに役立つはずことをお勧めしたいです。

0

ネットワークからの応答を待っている間に、http取得要求がブロックされている可能性があります。 asynchronous http libraryを使用し、役立つかどうかを確認してください。

4

サーバから複数の項目を取り出して速やかに取得するには、TCPキープアライブを使用します。簡略化したLWP::Simpleを削除し、通常LWP::UserAgentkeep_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 
0
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 ([email protected]) { 
    $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

あなたの問題は、より多くのCPU集中型のI/O集中型よりもされて廃棄されます。ここではほとんどの人があなたにもっとCPUを使うよう提案していますが、私はPerlが "グルー"言語として使われているという大きな利点を示すようにしようとします。 誰もがLibxml2が優れたXML/HTMLパーサーであることに同意します。また、libcurlはすばらしいダウンロードエージェントです。 しかし、Perlユニバースでは、多くのスクレイパーはLWP :: UserAgentとHTML :: TreeBuilder :: XPath(これはHTML :: TokeParserに似ていますが、XPathに準拠しています)に基づいています。 そのケースでは、libcurlを/ libxml2のを経由してダウンロードしてHTMLの構文解析を処理するために、ドロップイン交換用モジュールを使用することができます。

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

を私はちょうど私が使用されるいくつかのスクレーパーでこれらの3行を付加することで平均5倍の速度増加を見ました維持する。 しかし、あなたはHTML :: TokeParserを使っているので、代わりにWeb :: Scraper :: LibXMLを試してみることをお勧めします(LWP :: Protocol :: Net :: CurlとLWP :: Simpleの両方に影響を与えます)ウェブ::スクレーパー)。

関連する問題