2015-01-16 3 views
2

나는 수천 건의 요청을 만들기 위해 CURL을 사용하고 있습니다. 내 코드에서는 쿠키를 특정 값으로 설정 한 다음 페이지의 값을 읽습니다.효율적으로 수천 개의 말풍선을 만들 수 있습니다.

그래서
#!/usr/bin/perl 
my $site = "http://SITENAME/?id="; 
my $cookie_name = "cookienum123"; 
print $fh "#\t\tValue\n"; 
for my $i ('1'..'10000') { 
    my $output = `curl -s -H "Cookie: $cookie_name=$i" -L $site$i | grep -Eo "[0-9]+"`; 
    print "$i\t\t$output\n"; 
} 

1에서 10000에, 나는 그 값에 cookienum123를 설정하고 페이지에서 전체 응답 읽고있다 : 여기 내 코드입니다. 그런 다음 grep을 사용하여 #을 추출합니다. 지금 코드는 잘 작동하지만 더 빠르고 효율적인 방법이 있는지 궁금합니다.

이 작업은 Perl 스크립트로 수행 할 필요가 없습니다 (Windows 배치 파일, Unix 쉘 스크립트 등도 사용할 수 있음).

편집 1 월 18 일 : 덧붙여 "원하는 답변에는 수천 개의 컬 요청을 동시에 실행하는 방법이 포함되어야하지만 현재 실행중인 속도보다 빠르게 실행해야합니다. 결국 단일 파일에 출력을 쓰지 만 순서는 중요하지 않습니다. " 아래의 주석 중 일부는 포크을 언급하지만 내 코드에 어떻게 적용해야할지 모르겠다. 나는 이것이 Perl의 첫 번째 프로그램이기 때문에 Perl을 처음 사용하는 사람이다.

+0

한 번에 20 개씩 여러 어린이에게 분기하는 것은 어떨까요? 한 번에 여러 번 실행할 수 있습니까? – TheJester1977

+6

Net :: Curl :: Multi를 사용하면 컬 라이브러리에 병렬 요청을 할 수 있습니다. 물론 Parallel :: ForkManager도 다중'curl' 프로세스를 망치고 있습니다 – ikegami

+0

@ TheJester1977 어떻게 여러개의 자식에게 포크를 걸 수 있습니까? – Bijan

답변

1

여기에있는 것은 당황스럽고 평행 한 문제입니다. 스레드 간 종속성이나 통신이 필요 없기 때문에 병렬 처리에 유용합니다.

펄 스레딩이나 포킹에서이 작업을 수행하는 두 가지 주요 방법이 있습니다. 일반적으로은 수행중인 작업에 대해 스레드 기반 병렬 처리를 제안합니다. 이것은 선택의 문제이지만 정보를 대조하는 데 더 적합하다고 생각합니다.

#!/usr/bin/perl 

use strict; 
use warnings; 

use threads; 
use Thread::Queue; 

my $numthreads = 20; 

my $site  = "http://SITENAME/?id="; 
my $cookie_name = "cookienum123"; 

my $fetch_q = Thread::Queue->new(); 
my $collate_q = Thread::Queue->new(); 


#fetch sub sits in a loop, takes items off 'fetch_q' and runs curl. 
sub fetch { 
    while (my $target = $fetch_q->dequeue()) { 
     my $output = 
      `curl -s -H "Cookie: $cookie_name=$target" -L $site$target | grep -Eo "[0-9]+"`; 
     $collate_q->enqueue($output); 
    } 
} 

#one instance of collate, which exists to serialise the output from fetch. 
#writing files concurrently can get very messy and build in race conditions. 
sub collate { 
    open(my $output_fh, ">", "results.txt") or die $!; 
    print {$output_fh} "#\t\tValue\n"; 

    while (my $result = $collate_q->dequeue()) { 
     print {$output_fh} $result; 
    } 
    close($output_fh); 
} 


## main bit: 

#start worker threads 
my @workers = map { threads->create(\&fetch) } 1 .. $numthreads; 

#collates results. 
my $collater = threads->create(\&collate); 

$fetch_q->enqueue('1' .. '10000'); 
$fetch_q->end(); 

foreach my $thr (@workers) { 
    $thr->join(); 
} 

#end collate_q here, because we know all the fetchers are 
#joined - so no more results will be generated. 
#queue will then generate 'undef' when it's empty, and the thread will exit. 
$collate_q->end; 

#join will block until thread has exited, e.g. all results in the queue 
#have been 'processed'. 
$collater->join; 

이렇게하면 병렬로 실행되는 20 개의 작업자 스레드가 생성되고 파일로 끝날 때 결과가 수집됩니다. 또는 Parallel::ForkManager과 비슷한 작업을 수행 할 수도 있지만 데이터 지향 작업의 경우 개인적으로 스레딩을 선호합니다.

'정렬'하위를 사용하여 데이터 정렬, 정렬 등 모든 데이터를 후 처리 할 수 ​​있습니다.

curlgrep을 시스템 호출로 사용하는 것이 이상적이지는 않습니다. 나는 그대로두고 왔지만, LWP을보고 펄에서 텍스트 처리를 처리 할 것을 제안합니다. 그것.

+0

작은 것이 하나 있는데, $ 결과 만 파일에 출력합니다. 같은 라인에 $ target을 어떻게 출력합니까? – Bijan

+1

원본 스레드에서 인쇄하고 싶은 내용을 모두 대기열에 추가하십시오. '$ collate_queue -> enqueue ("Target : $ target Output $ output \ n");'예를 들면 다음과 같습니다. – Sobrique

+0

한가지 더 말하자면'Term :: ProgressBar'를 사용하여 진행 상황이 얼마나 완료되었는지 추적 할 수 있습니까? 이전 예제를 통해이 작업을 수행했지만, 스레드를 사용하고 있기 때문에 다른 것을 상상할 수 있습니다. – Bijan

1

나는 다음과 같이 당신이 원하는 것은 10000 개의 동시 요청으로 서버를 슬래 밍하는 것이 매우 예의라고 생각하지 않는다. 사실 주어진 URL의 ID를 처리하여 사이트의 데이터를 수집하는 것은 매우 우호적이지 않습니다. 나는 다음을 테스트하지는 않았지만 거기에서 99 %의 방법을 사용해야한다 (어딘가에서 구문/사용 오류 일 수 있음).

더 많은 정보를 원하시면 참조 :

행운을 빕니다!

#!/usr/bin/perl 

use warnings; 
use strict; 

use Mojo::UserAgent; 
use Mojo::IOLoop; 

my $site = 'http://SITENAME/?id='; 
my $cookie_name = 'cookienum123'; 

#open filehandle and write file header 
open my $output_fh, q{>}, 'results.txt' 
    or die $!; 
print {$output_fh} "#\t\tValue\n"; 


# Use Mojo::UserAgent for concurrent non-blocking requests 
my $ua = Mojo::UserAgent->new; 


#create your requests 
for my $i (1..10000) { 

    #build transaction 
    my $tx = $ua->build_tx(GET => "$site$i"); 

    #add cookie header 
    $tx->req->cookies({name => $cookie_name, value => $i}); 

    #start "GET" with callback to write to file 
    $tx = $ua->start($tx => sub { 
     my ($ua, $mojo) = @_; 
     print {$output_fh} $i . "\t\t" . $mojo->res->dom->to_string; 
    }); 
} 

# Start event loop if necessary 
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; 


#close filehandle 
close $output_fh; 
관련 문제