3

最近、URL に画像をダウンロードするための小さなクローラーに取り組んでいます。

f.open()/f.write() で urllib2 の openurl() を使用します。

コード スニペットは次のとおりです。

# the list for the images' urls
imglist = re.findall(regImg,pageHtml)

# iterate to download images
for index in xrange(1,len(imglist)+1):
    img = urllib2.urlopen(imglist[index-1])
    f = open(r'E:\OK\%s.jpg' % str(index), 'wb')
    print('To Read...')

    # potential timeout, may block for a long time
    # so I wonder whether there is any mechanism to enable retry when time exceeds a certain threshold
    f.write(img.read())
    f.close()
    print('Image %d is ready !' % index)

上記のコードでは、 img.read() が長時間ブロックされる可能性があります。この問題の下で、画像の URL 操作を再試行/再オープンしたいと考えています。

また、上記のコードの効率的な観点にも関心があります。ダウンロードする画像の数が多少多い場合は、スレッド プールを使用してダウンロードする方がよいようです。

助言がありますか?前もって感謝します。

ps img オブジェクトの read() メソッドがブロックを引き起こす可能性があることを発見したため、タイムアウト パラメータを urlopen() に追加するだけでは役に立たないようです。しかし、ファイル オブジェクトには read() のタイムアウト バージョンがないことがわかりました。これに関する提案はありますか?どうもありがとう 。

4

4 に答える 4

2

urllib2.urlopentimeout、すべてのブロッキング操作 (接続の構築など) に使用されるパラメーターがあります。

このスニペットは、私のプロジェクトの 1 つから取得されます。一度に複数のファイルをダウンロードするには、スレッド プールを使用します。使用しますurllib.urlretrieveが、ロジックは同じです。はタプルurl_and_path_listのリスト、は生成されるスレッドの数、はファイル システムに既に存在する場合はファイルのダウンロードをスキップします。(url, path)num_concurrentskip_existing

def download_urls(url_and_path_list, num_concurrent, skip_existing):
    # prepare the queue
    queue = Queue.Queue()
    for url_and_path in url_and_path_list:
        queue.put(url_and_path)

    # start the requested number of download threads to download the files
    threads = []
    for _ in range(num_concurrent):
        t = DownloadThread(queue, skip_existing)
        t.daemon = True
        t.start()

    queue.join()

class DownloadThread(threading.Thread):
    def __init__(self, queue, skip_existing):
        super(DownloadThread, self).__init__()
        self.queue = queue
        self.skip_existing = skip_existing

    def run(self):
        while True:
            #grabs url from queue
            url, path = self.queue.get()

            if self.skip_existing and exists(path):
                # skip if requested
                self.queue.task_done()
                continue

            try:
                urllib.urlretrieve(url, path)
            except IOError:
                print "Error downloading url '%s'." % url

            #signals to queue job is done
            self.queue.task_done()
于 2012-12-06T16:28:10.237 に答える
1

大量のドキュメントをクロールする方法は、一定サイズのチャンクをクロールしてダンプするバッチプロセッサを使用することです。

たとえば100Kドキュメントの既知のバッチをクロールするとします。スレッドプールによってダウンロードされる、たとえば1000ドキュメントの一定サイズのチャンクを生成するロジックをいくつか持つことができます。チャンク全体がクロールされると、データベースに一括挿入できます。そして、さらに1000のドキュメントなどに進みます。

このアプローチに従うことで得られる利点:

  • スレッドプールがクロール速度を高速化するという利点があります。

  • ある意味でフォールトトレラントであり、最後に失敗したチャンクから続行できます。

  • 優先度に基づいてチャンクを生成することができます。つまり、最初にクロールする重要なドキュメントです。したがって、バッチ全体を完了できない場合に備えて。重要なドキュメントが処理され、重要度の低いドキュメントは後で次の実行で取得できます。

于 2012-12-06T16:36:12.183 に答える
1

urllib2.urlopen()で接続を作成するときに、タイムアウト パラメータを指定できます。

ドキュメントで説明されているように:

オプションの timeout パラメーターは、接続試行などのブロック操作のタイムアウトを秒単位で指定します (指定されていない場合は、グローバルなデフォルトのタイムアウト設定が使用されます)。これは、実際には HTTP、HTTPS、および FTP 接続でのみ機能します。

これにより、最大待機時間を管理し、発生した例外をキャッチできます。

于 2012-12-06T16:29:12.347 に答える