1

Python マルチプロセッシング モジュールを使用して Web サイトをスクレイピングしています。現在、この Web サイトには 100,000 ページを超えるページがあります。私がやろうとしているのは、取得した 500 ページごとに別のフォルダーに入れることです。問題は、新しいフォルダーを正常に作成しても、スクリプトが以前のフォルダーにしかデータを入力しないことです。コードは次のとおりです。

global a = 1

global b = 500

def fetchAfter(y):

       global a

       global b

       strfile = "E:\\A\\B\\" + str(a) + "-" + str(b) + "\\" + str(y) + ".html"

       if (os.path.exists( os.path.join( "E:\\A\\B\\" + str(a) + "-" + str(b) + "\\", str(y) + ".html" )) == 0):

                f = open(strfile, "w")


if __name__ == '__main__':

       start = time.time()
       for i in range(1,3):
              os.makedirs("E:\\Results\\Class 9\\" + str(a) + "-" + str(b))

              pool = Pool(processes=12)
              pool.map(fetchAfter, range(a,b))
              pool.close()
              pool.join()
              a = b
              b = b + 500

       print time.time()-start
4

3 に答える 3

1

ワーカー関数が何をすべきかを決定するために取得した単一の引数のみに依存することが最善です。これは、呼び出されるたびに親プロセスから取得する唯一の情報だからです。この引数は、ほぼすべての Python オブジェクト (タプル、辞書、リストを含む) にすることができるため、ワーカーに渡す情報の量が実際に制限されることはありません。

したがって、2タプルのリストを作成します。各 2 タプルは、(1) 取得するファイルと (2) それを格納するディレクトリで構成する必要があります。そのタプルのリストを にフィードしmap()、リッピングします。

使用するプロセスの数を指定することが役立つかどうかはわかりません。プールは通常、CPU のコアと同じ数のプロセスを使用します。これは通常、すべてのコアを最大化するのに十分です。:-)

ところで、一度だけ電話する必要がありますmap()。そして、map()すべてが完了するまでブロックするため、 を呼び出す必要はありませんjoin()

編集:以下のサンプルコードを追加しました。

import multiprocessing
import requests
import os

def processfile(arg):
    """Worker function to scrape the pages and write them to a file.

    Keyword arguments:
    arg -- 2-tuple containing the URL of the page and the directory
           where to save it.
    """
    # Unpack the arguments
    url, savedir = arg

    # It might be a good idea to put a random delay of a few seconds here, 
    # so we don't hammer the webserver!

    # Scrape the page. Requests rules ;-)
    r = requests.get(url)
    # Write it, keep the original HTML file name.
    fname = url.split('/')[-1]
    with open(savedir + '/' + fname, 'w+') as outfile:
        outfile.write(r.text)

def main():
    """Main program.
    """
    # This list of tuples should hold all the pages... 
    # Up to you how to generate it, this is just an example.
    worklist = [('http://www.foo.org/page1.html', 'dir1'), 
                ('http://www.foo.org/page2.html', 'dir1'), 
                ('http://www.foo.org/page3.html', 'dir2'), 
                ('http://www.foo.org/page4.html', 'dir2')]
    # Create output directories
    dirlist = ['dir1', 'dir2']
    for d in dirlist:
        os.makedirs(d)
    p = Pool()
    # Let'er rip!
    p.map(processfile, worklist)
    p.close()

if __name__ == '__main__':
    main()
于 2012-08-23T20:28:54.133 に答える
0

マルチプロセッシングは、その名前が示すように、個別のプロセスを使用します。で作成したプロセスは、の元の値にPoolアクセスできず、メインプログラムで500を追加します。この前の質問を参照してください。ab

a最も簡単な解決策は、 (渡すbことfetchAfterに加えて)渡すようにコードをリファクタリングすることですy

于 2012-08-23T19:25:33.713 に答える
0

これを実装する1つの方法は次のとおりです。

#!/usr/bin/env python
import logging
import multiprocessing as mp
import os
import urllib

def download_page(url_path):
    try:
        urllib.urlretrieve(*url_path)
        mp.get_logger().info('done %s' % (url_path,))
    except Exception as e:
        mp.get_logger().error('failed %s: %s' % (url_path, e))

def generate_url_path(rootdir, urls_per_dir=500):
    for i in xrange(100*1000):
        if i % urls_per_dir == 0: # make new dir
           dirpath = os.path.join(rootdir, '%d-%d' % (i, i+urls_per_dir))
           if not os.path.isdir(dirpath):
              os.makedirs(dirpath) # stop if it fails
        url = 'http://example.com/page?' + urllib.urlencode(dict(number=i))
        path = os.path.join(dirpath, '%d.html' % (i,))
        yield url, path

def main():
    mp.log_to_stderr().setLevel(logging.INFO)

    pool = mp.Pool(4) # number of processes is unrelated to number of CPUs
                      # due to the task is IO-bound
    for _ in pool.imap_unordered(download_page, generate_url_path(r'E:\A\B')):
        pass

if __name__ == '__main__':
   main()

複数の引数とコードについては、Pythonマルチプロセッシングpool.mapも参照してください。PythonでHTTPを高速化する方法から、
httplibとマルチプロセッシングを使用した基本的なhttp認証をブルートフォースし
ますか?

于 2012-08-23T21:52:11.083 に答える