龙卷风:AsyncHttpClient.fetch从迭代器?

2024-04-19 04:48:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试编写一个网络爬虫的东西,并希望尽快发出HTTP请求。tornado's AsyncHttpClient似乎是一个不错的选择,但是我看到的所有示例代码(例如https://stackoverflow.com/a/25549675/1650177)基本上都是在一个巨大的URL列表上调用AsyncHttpClient.fetch,让tornado对它们进行排队并最终发出请求。在

但是如果我想处理一个无限长(或非常大的)来自文件或网络的url列表呢?我不想把所有的网址都载入内存。在

google了一下,但似乎找不到从迭代器AsyncHttpClient.fetch的方法。不过,我确实找到了一种使用gevent:http://gevent.org/gevent.threadpool.html#gevent.threadpool.ThreadPool.imap来做我想做的事情的方法。在龙卷风中有没有类似的方法?在

我想到的一个解决方案是,在一个fetch操作完成后,只对这么多的url进行排队,然后添加逻辑来排队,但我希望有一个更干净的解决方案。在

任何帮助或建议将不胜感激!在


Tags: 方法代码网络httpurl示例列表gevent
1条回答
网友
1楼 · 发布于 2024-04-19 04:48:26

我会用一个队列和多个worker来完成这个任务,在https://github.com/tornadoweb/tornado/blob/master/demos/webspider/webspider.py上进行

import tornado.queues
from tornado import gen
from tornado.httpclient import AsyncHTTPClient
from tornado.ioloop import IOLoop

NUM_WORKERS = 10
QUEUE_SIZE = 100
q = tornado.queues.Queue(QUEUE_SIZE)
AsyncHTTPClient.configure(None, max_clients=NUM_WORKERS)
http_client = AsyncHTTPClient()

@gen.coroutine
def worker():
    while True:
        url = yield q.get()
        try:
            response = yield http_client.fetch(url)
            print('got response from', url)
        except Exception:
            print('failed to fetch', url)
        finally:
            q.task_done()

@gen.coroutine
def main():
    for i in range(NUM_WORKERS):
        IOLoop.current().spawn_callback(worker)
    with open("urls.txt") as f:
        for line in f:
            url = line.strip()
            # When the queue fills up, stop here to wait instead
            # of reading more from the file.
            yield q.put(url)
    yield q.join()

if __name__ == '__main__':
    IOLoop.current().run_sync(main)

相关问题 更多 >