(五)Scrapy的抓取流程——Scheduler
程序员文章站
2022-04-11 08:02:45
...
在Engine中,是通过Engine实例化的slot对象进行对scheduler对象的初始化,和任务状态的记录。
# engine.py中ExecutionEngine的crawl方法
def crawl(self, request, spider):
assert spider in self.open_spiders, \
"Spider %r not opened when crawling: %s" % (spider.name, request)
self.schedule(request, spider)
self.slot.nextcall.schedule()# 这里的schedule调用的是_next_request方法
# _next_request中调用_next_request_from_scheduler,取出request并下载
# engine.py中ExecutionEngine的schedule方法
def schedule(self, request, spider):
self.signals.send_catch_log(signal=signals.request_scheduled,
request=request, spider=spider)
if not self.slot.scheduler.enqueue_request(request):
self.signals.send_catch_log(signal=signals.request_dropped,
request=request, spider=spider)
Scheduler的功能就是对请求的调度,包括过滤,请求的入队和出队操作。也正是因为原始Scheduler是基于内存的调度,所以并不支持分布式。而request请求就是通过enqueue_request方法进入调度器的调度队列。
在engine中,scheduler进行了from_crawler的初始化和open。
(1)from_crawler
通过load_project方法导入配置文件中指定的scheduler类,调用类方法from_crawler定义了过滤器和队列返回新生成的scheduler实例。
在默认设置文件里可以看到这些队列默认使用什么类。memory是基于内存的deque,disk则是通过文件进行存储,优先级队列是直接使用自带的queuelib中的PriorityQueue实现。
SCHEDULER = 'scrapy.core.scheduler.Scheduler'
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleLifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.LifoMemoryQueue'
SCHEDULER_PRIORITY_QUEUE = 'queuelib.PriorityQueue'
(2)open
open方法中对队列进行了初始化,self.mqs是优先级队列对象基于内存,self.dqs是基于文件的队列。然后会开启调度器的过滤器(这儿注释可以返回一个deferred对象,无具体实现)。
(3)enqueue_request
本章最开始engine.py中ExecutionEngine的schedule方法就对enqueue_request进行了调用。经过过滤条件后,将request放入scheduler的队列中。
(4)next_request
最开始的代码块中提到的engine中的_next_request_from_scheduler就是调用该方法,从队列中取出request
在取出request之后,下一步就是对请求的下载。