Web サイトからデータを取得し、結果をデータベースにダンプする Python 2.7 プログラムがあります。コンシューマ プロデューサー モデルに従い、threading モジュールを使用して記述されています。
楽しみのために、新しいasyncioモジュール (3.4 以降)を使用してこのプログラムを書き直したいのですが、これを適切に行う方法がわかりません。
最も重要な要件は、プログラムが同じ Web サイトから順番にデータを取得する必要があることです。たとえば、' http://a-restaurant.com 'という URL の場合、最初に' http://a-restaurant.com/menu/0 'を取得し、次に' http://a-restaurant.com/menu/ ' を取得する必要があります。 1 '、次に' http://a-restaurant.com/menu/2 '、... 順番にフェッチされない場合、Web サイトはページの配信を完全に停止し、0 から開始する必要があります。
ただし、別の Web サイト ( 「http://another-restaurant.com」 ) の別のフェッチは、同時に実行できます (実行する必要があります) (他のサイトにも順次制限があります)。
threading モジュールは、Web サイトごとに個別のスレッドを作成でき、各スレッドで 1 つのページの読み込みが完了するまで待ってから別のページを取得できるため、これに適しています。
これは、スレッド化バージョン (Python 2.7) から大幅に簡略化されたコード スニペットです。
class FetchThread(threading.Threading)
def __init__(self, queue, url)
self.queue = queue
self.baseurl = url
...
def run(self)
# Get 10 menu pages in a sequantial order
for food in range(10):
url = self.baseurl + '/' + str(food)
text = urllib2.urlopen(url).read()
self.queue.put(text)
...
def main()
queue = Queue.Queue()
urls = ('http://a-restaurant.com/menu', 'http://another-restaurant.com/menu')
for url in urls:
fetcher = FetchThread(queue, url)
fetcher.start()
...
そして、これが私がasyncioでそれをやろうとした方法です(3.4.1で):
@asyncio.coroutine
def fetch(url):
response = yield from aiohttp.request('GET', url)
response = yield from response.read_and_close()
return response.decode('utf-8')
@asyncio.coroutine
def print_page(url):
page = yield from fetch(url)
print(page)
l = []
urls = ('http://a-restaurant.com/menu', 'http://another-restaurant.com/menu')
for url in urls:
for food in range(10):
menu_url = url + '/' + str(food)
l.append(print_page(menu_url))
loop.run_until_complete(asyncio.wait(l))
そして、すべてを順不同でフェッチして出力します。まあ、それがそれらのコルーチンの全体的なアイデアだと思います。aiohttp を使用せずに urllib でフェッチする必要がありますか? しかし、最初のレストランのフェッチは、他のレストランのフェッチをブロックしますか? 私はこれを完全に間違って考えているだけですか?(これは、順番に取得するための単なるテストです。キューの部分にはまだ到達していません。)