2013-04-07 10 views
2

저는 벡터 공간 모델을 사용하여 기본 검색 엔진을 만들고 있는데이 URL은 500 개의 URL을 반환하는 크롤러이며 콘텐츠에서 SGML 태그를 제거합니다. 그러나 매우 느립니다 (URL을 검색하는 데만 30 분 이상 소요됩니다). 코드를 어떻게 최적화 할 수 있습니까? URL을 시작하는 예제로 wikipedia.org를 삽입했습니다.웹 크롤러 최적화

use warnings; 

use LWP::Simple; 
use LWP::UserAgent; 
use HTTP::Request; 
use HTTP::Response; 
use HTML::LinkExtor; 

my $starting_url = 'http://en.wikipedia.org/wiki/Main_Page'; 
my @urls = $starting_url; 
my %alreadyvisited; 
my $browser = LWP::UserAgent->new(); 
$browser->timeout(5); 
my $url_count = 0; 

while (@urls) 
{ 
    my $url = shift @urls; 
    next if $alreadyvisited{$url}; ## check if already visited 

    my $request = HTTP::Request->new(GET => $url); 
    my $response = $browser->request($request); 

    if ($response->is_error()) 
    { 
     print $response->status_line, "\n"; ## check for bad URL 
    } 
    my $contents = $response->content(); ## get contents from URL 
    push @c, $contents; 
    my @text = &RemoveSGMLtags(\@c); 
    #print "@text\n"; 

    $alreadyvisited{$url} = 1; ## store URL in hash for future reference 
    $url_count++; 
    print "$url\n"; 

    if ($url_count == 500) ## exit if number of crawled pages exceed limit 
    { 
     exit 0; 
    } 


    my ($page_parser) = HTML::LinkExtor->new(undef, $url); 
    $page_parser->parse($contents)->eof; ## parse page contents 
    my @links = $page_parser->links; 

    foreach my $link (@links) 
    { 
      $test = $$link[2]; 
      $test =~ s!^https?://(?:www\.)?!!i; 
      $test =~ s!/.*!!; 
      $test =~ s/[\?\#\:].*//; 
      if ($test eq "en.wikipedia.org") ## check if URL belongs to unt domain 
      { 
       next if ($$link[2] =~ m/^mailto/); 
       next if ($$link[2] =~ m/s?html?|xml|asp|pl|css|jpg|gif|pdf|png|jpeg/); 
       push @urls, $$link[2]; 
      } 
    } 
    sleep 1; 
} 


sub RemoveSGMLtags 
{ 
    my ($input) = @_; 
    my @INPUTFILEcontent = @$input; 
    my $j;my @raw_text; 
    for ($j=0; $j<$#INPUTFILEcontent; $j++) 
    { 
     my $INPUTFILEvalue = $INPUTFILEcontent[$j]; 
     use HTML::Parse; 
     use HTML::FormatText; 
     my $plain_text = HTML::FormatText->new->format(parse_html($INPUTFILEvalue)); 
     push @raw_text, ($plain_text); 
    } 
    return @raw_text; 
} 
+0

잘 모르겠습니다. 필자는 perl에 익숙하지 않고 효율적인 코드를 작성하는 법을 배우고 있습니다. – user2154731

+0

'en.wikipedia.org'의 * 전체 *를 다운로드하려고합니다. Wikipedia가 전혀 마음에 들지 않을 가능성을 제외하고는 30 분 이내에 달성 할 수 있다면 그것은 성취라고 할 수 있습니다. 이와 같은 일을하는 것에 대해 두 번 생각하고, 귀하가하는 사이트의 서비스 약관을 신중히 검토하십시오. 대부분의 사람들은 자신의 데이터를 이와 같이 남용하지 않기를 원할 것입니다. – Borodin

+0

사실, 저는 대학 웹 사이트를 크롤링해야합니다. 미안, 그걸 잊어 버렸어. 이 URL을 예로 든 것입니다. – user2154731

답변

5
  • 항상use strict

  • 결코이 서브 루틴에 앰퍼샌드 &를 사용

  • 사용 URI이 URL을에게

를 조작 호출

거기에 sleep 1이 있습니다. 사이트를 너무 많이 망치는 것을 피하는 것이 좋습니다. 그러나 거의 모든 웹 기반 응용 프로그램의 병목 현상은 인터넷 자체이므로 사이트에서 더 많은 것을 요청하지 않고도 프로그램을 더 빠르게 만들 수는 없습니다. 즉, sleep을 제거하고 서버에 병렬 요청 (예 : LWP::Parallel::RobotUA)을 사용하는 것입니다. 그게 너가 가야 할 길이야?

+0

수면을 제거하면 코드가 훨씬 빨라집니다. 병렬 요청을 사용하여 시도합니다. – user2154731

+0

또 다른 중요한 문제는 코드를 프로파일 링했는지 알 수 있습니다. HTML :: FormatText-> new-> format (parse_html (입력 한 모든 줄에 대신 한 번 호출 할 수있을 때마다 –

3

모든 URL 구문 분석 및 추출을 처리하는 WWW :: Mechanize를 사용하십시오. 당신이 다루는 모든 링크 구문 분석보다 훨씬 쉽습니다. 그것은 당신이하고있는 일을 위해 특별히 만들어졌으며, LWP :: UserAgent의 하위 클래스이기 때문에 모든 LWP :: UserAgent를 WWW :: Mechanize로 변경할 수 있어야합니다. 모든 링크 추출을 위해, 당신은이 작업을 수행 할 수 있습니다 :

my $mech = WWW::Mechanize->new(); 
$mech->get('someurl.com'); 
my @links = $mech->links; 

다음 @links는 WWW : : 기계화 : : 링크 개체의 배열입니다.

+0

감사합니다.하지만 패키지가 결여되어 있고 설치 권한이없는 서버에서 최종 코드를 실행해야하므로 Mechanize를 사용할 수 없습니다. – user2154731

+2

@ user2154731 : [Perl 모듈을 자신의 홈 디렉토리] (http://stackoverflow.com/questions/251705/how-can-i-use-a-new-perl-module-without-install-permissions). 그냥 WWW :: Mechanize. –