【发布时间】:2014-06-16 15:05:33
【问题描述】:
我有一个 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) 的一个非常简化的代码 sn-p:
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 获取吗?但是第一家餐厅的抓取是否会阻止其他餐厅的抓取?我只是在想这完全错误吗? (这只是一个尝试按顺序获取内容的测试。还没有进入队列部分。)
【问题讨论】:
标签: python asynchronous python-asyncio