前面几篇文章主要是分析改错,这篇文章来分析下,这个爬虫是怎么运作的。核心就在crawling.py文件中,这个文件的代码稍微有点乱,不是很容易看明白,下面把重要代码贴不出:
#初始化
self.q = Queue(loop=self.loop)
....
self.q.put_nowait((url, max_redirect))
....
def fetch(self, url, max_redirect):
...
self.q.put_nowait((link, self.max_redirect))
...
def work(self):
"""Process queue items forever."""
while True:
url, max_redirect = yield from self.q.get()
yield from self.fetch(url, max_redirect)
self.q.task_done()
....
def crawl(self):
"""Run the crawler until all finished."""
workers = [asyncio.Task(self.work(), loop=self.loop)
for _ in range(self.max_tasks)]
self.t0 = time.time()
yield from self.q.join()
self.t1 = time.time()
for w in workers:
w.cancel()
核心调度过程就是上面的代码,通过crawl()方法启动——创建Task——把work()方法加入创建的Task——在work()方法中获取初始化地址并开始抓取。
关于队列Queue的用法,见下文:
Python之asyncio.Queue
上图代码中,稍微难理解的是crawl()方法中,有句:
...
yield from self.q.join()
...
这是一句突然冒出来的代码,它的作用是等待queue中所有的数据被处理(由queue.task_done()通知),而work()方法里面正好是调用task_done()的地方,所以q.join()的作用就是等待work()方法中的所有task_done()调用完成。