我有一个 Python 2.7 程序,它从网站中提取数据并将结果转储到数据库中。它遵循消费者生产者模型,并使用线程模块编写。
只是为了好玩,我想使用新的asyncio模块(从 3.4 开始)重写这个程序,但我不知道如何正确地做到这一点。
最关键的要求是程序必须按顺序从同一网站获取数据。例如,对于 url ' http://a-restaurant.com ',它应该首先得到' http://a-restaurant.com/menu/0 ',然后是 ' http://a-restaurant.com/menu/ 1 ',然后' http://a-restaurant.com/menu/2 ',...如果它们没有被提取以使网站完全停止提供页面,那么您必须从 0 开始。
然而,另一个网站( ' http://another-restaurant.com ' )的另一个获取可以(并且应该)同时运行(其他网站也有连续限制)。
线程模块非常适合这个,因为我可以为每个网站创建单独的线程,并且在每个线程中它可以等待一个页面完成加载,然后再获取另一个页面。
这是线程版本(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 获取吗?但是第一家餐厅的抓取是否会阻止其他餐厅的抓取?我只是在想这完全错误吗?(这只是一个尝试按顺序获取东西的测试。还没有到队列部分。)