2

各ページが次々とダウンロードされるのを待つのではなく、データベースから URL を取得し、Web ページを同時にダウンロードして高速化できるスクリプトを Python で作成したいと考えています。

このスレッドによると、Python は、同じスクリプトを複数回起動するのを防ぐGlobal Interpreter Lockと呼ばれるもののため、これを許可していません。

Twisted フレームワークの学習に時間を費やす前に、上記で行う必要があることを行うためのより簡単な方法がないことを確認したいと思います。

ヒントをありがとう。

4

5 に答える 5

9

GIL について心配する必要はありません。あなたの場合、それは問題ではありません。

必要なことを行う最も簡単な方法は、 threadingモジュールとASPNのスレッド プール実装の 1 つを使用して、スレッド プールを作成することです。そのプールの各スレッドは、httplibを使用して Web ページをダウンロードできます。

もう 1 つのオプションは、PyCURLモジュールを使用することです。これは並列ダウンロードをネイティブでサポートしているため、自分で実装する必要はありません。

于 2009-09-29T11:52:32.423 に答える
7

GIL を使用すると、スレッドを使用してプロセッサの負荷分散を効果的に行うことができなくなります。これはプロセッサの負荷分散ではなく、1 回の IO 待機でダウンロード全体が停止するのを防ぐため、ここでは GIL は関係ありません。*)

したがって、同時にダウンロードする複数のプロセスを作成するだけです。threading モジュールまたは multiprocessing モジュールでそれを行うことができます。

*) ええと...ギガビット接続があり、問題が実際にネットよりも先にプロセッサが過負荷になる場合を除きます。しかし、ここでは明らかにそうではありません。

于 2009-09-29T12:17:17.870 に答える
2

urllib & threading (またはmultiprocessing ) パッケージには、必要な「スパイダー」を実行するために必要なものがすべて含まれています。

あなたがしなければならないことは、DBからURLを取得し、各URLに対してURLを取得するスレッドまたはプロセスを開始することです.

例として(データベースのURLの取得を見逃しています):

#!/usr/bin/env python
import Queue
import threading
import urllib2
import time

hosts = ["http://yahoo.com", "http://google.com", "http://amazon.com",
    "http://ibm.com", "http://apple.com"]

queue = Queue.Queue()

class ThreadUrl(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            #grabs host from queue
            host = self.queue.get()

            #grabs urls of hosts and prints first 1024 bytes of page
            url = urllib2.urlopen(host)
            print url.read(1024)

            #signals to queue job is done
            self.queue.task_done()

start = time.time()
def main():

    #spawn a pool of threads, and pass them queue instance
    for i in range(5):
        t = ThreadUrl(queue)
        t.setDaemon(True)
        t.start()

    #populate queue with data
    for host in hosts:
        queue.put(host)

    #wait on the queue until everything has been processed
    queue.join()

main()
print "Elapsed Time: %s" % (time.time() - start)
于 2009-09-29T14:43:24.780 に答える
2

私は最近、この同じ問題を解決しました。考慮すべきことの 1 つは、一部の人々は、サーバーが停止することを快く思わず、停止する IP アドレスをブロックするということです。私が聞いた標準的な礼儀は、ページ リクエスト間の間隔は約 3 秒ですが、これは柔軟です。

複数の Web サイトからダウンロードする場合は、URL をドメインごとにグループ化し、それぞれに 1 つのスレッドを作成できます。次に、スレッドで次のようなことができます。

for url in urls:
    timer = time.time()
    # ... get your content ...
    # perhaps put content in a queue to be written back to 
    # your database if it doesn't allow concurrent writes.
    while time.time() - timer < 3.0:
        time.sleep(0.5)

場合によっては、応答を取得するだけで 3 秒かかることがありますが、それについて心配する必要はありません。

確かに、1 つのサイトからのみダウンロードしている場合、これはまったく役に立ちませんが、ブロックされないようにすることはできます。

私のマシンは、約 200 のスレッドを処理してから、それらを管理するオーバーヘッドによってプロセスが遅くなりました。最終的には、毎秒 40 ~ 50 ページ程度になりました。

于 2009-09-29T12:38:07.853 に答える
0

ダウンロードはIOであり、ノンブロッキングソケットまたはツイストを使用して非同期で実行できます。これらのソリューションはどちらも、スレッド化やマルチプロセッシングよりもはるかに効率的です。

于 2009-09-29T11:57:11.307 に答える