2017-10-27 17 views
0

私はPythonで単純なWebクローラーを構築しています。私は〜50kのウェブサイトを通過しなければならないでしょう。私はいくつかのマルチスレッドでプロセスをスピードアップしたいと思います。複数のスレッドのバッチを処理する方法は?

私はスレッドのメタオブジェクトとして、各ウェブサイトを通じてクロールするクローラのクラスを定義しています

Crawler(Thread): 
    def __init__(self, url, depth, wait): 
... 

はその後、main関数では、私は、URLの完全なリストから10件のURLのバッチを反復処理し、各URLのクローラオブジェクトを作成します。

for i in range(index, math.ceil(len(urls)/10)): 
     jobs = [] 
     for url in urls[i * 10:(i + 1) * 10]: 
      s = Crawler(url) 
      s.setDaemon(True) 
      s.start() 
      jobs.append(s) 

     for j in jobs: 
      j.join() 

問題は、各バッチについて、すべてのスレッドが終了するまで待つ必要があることです。これは、私が持っているとき、100ページの9つのウェブサイト、10,000ページの1つのウェブサイトしかないと不十分です。9つのウェブサイトは数分で完了しますが、10,000ページの大きなウェブサイトは1時間待たなければなりません。次のバッチに進む前に終了します。

物を最適化するには、10個のクローラスレッドで開始し、クローラスレッドが終了するたびにリストが完了するまで次のURLを含む新しいクローラを作成することをお勧めします。

私は長さが10を下回ったが、それは少しハック聞こえるたびに新しいスレッドを追加し、私は参加する()を取り除くとthreading.enumerateの長さにわたってwhileループを持っている可能性が考えています。

私はPythonのQueueを調べていましたが、https://docs.python.org/3/library/queue.htmlの例から判断すると、まだ.join()に依存していて、キュー内のすべてのスレッドが実行されるのを待つ必要があります。

"イベントリスナー"のようなものをスレッドに追加する方法はありますか?スレッドが終了するとスレッドリストを新しいスレッドで更新できますか?

答えて

0

おそらくキューをもう一度見てください。バッチごとに結合する必要はありません。

すべての50K Webサイトをキューに入れることができます。私はおそらくjobsと呼びますが、スレッドの数は通常workersのように限られています。各作業者は、キューからアイテムを取得し、処理し、完了するまでキューからアイテムを引き続き取り出します。何を意味するのかは様々です。 1つの提案は、各ワーカーの待ち行列にNoneを入れ、Noneを見た後で各ワーカーを停止させることです。しかし、あなたが使うことができる他の信号があります。その後、すべてのワーカースレッドが終了するのを待つためにjoinを使用できます。その場合、ワーカーはデーモンである必要はありません。例えば

(あなたはURLごとに別のスレッドを作成したいとは思わないでしょう):

from threading import Queue, Thread 

def crawl_worker(q): 
    while True: 
    url = q.get() 
    if url is None: 
     break 
    # do something with url 

url_queue = Queue() 

# populate the queue 
for url in urls: 
    url_queue.put(url) 

num_workers = 10 

workers = [ 
    Thread(target=crawl_worker, args=(url_queue)) 
    for _ in range(num_workers) 
] 

# add a None signal for each worker 
for worker in workers: 
    url_queue.put(None) 

# start all workers 
for worker in workers: 
    worker.start() 

# wait for all workers to finish 
for worker in workers: 
    worker.join() 

# we're done now 

それに代わるものがあります。あなたが実際に運動としてそれを見ていないが、何かをしたい場合は、私はお勧めしますhttps://scrapy.org/

関連する問題