6.Downloader下载器
Downloader包含了从调度器调取url之后到scraper获取返回的网页内容之前的所有步骤,关系到网页如何下载,网络通信/HTTP协议/服务器等一系列知识,是最复杂的一部分内容。
Downloader初始化
在之前Crawler.crawl()创建ExecutionEngine执行引擎的时候,就已经初始化了Downloader对象。此对象在配置中定义,默认为:
scrapy/settings/default_settings.py:
DOWNLOADER = 'scrapy.core.downloader.Downloader'
scrapy/core/downloader/init.py:
class Downloader(object):
def __init__(self, crawler):
self.settings = crawler.settings
self.signals = crawler.signals
self.slots = {
}
self.active = set()
self.handlers = DownloadHandlers(crawler)
self.total_concurrency = self.settings.getint('CONCURRENT_REQUESTS')
self.domain_concurrency = self.settings.getint('CONCURRENT_REQUESTS_PER_DOMAIN')
self.ip_concurrency = self.settings.getint('CONCURRENT_REQUESTS_PER_IP')
self.randomize_delay = self.settings.getbool('RANDOMIZE_DOWNLOAD_DELAY')
self.middleware = DownloaderMiddlewareManager.from_crawler(crawler)
self._slot_gc_loop = task.LoopingCall(self._slot_gc)
self._slot_gc_loop.start(60)
关键对象有4个:slots,active,DownloadHandlers,DownloaderMiddlewareManager以及一些配置选项。
Downloader:slots对象
这个slots是一个存储Slot对象的字典,key是request对应的域名,值是一个Slot对象。
Slot对象用来控制一种Request下载请求,通常这种下载请求是对于同一个域名。
这个Slot对象还控制了访问这个域名的并发度,下载延迟控制,随机延时等,主要是为了控制对一个域名的访问策略,一定程度上避免流量过大被封IP。
scrapy/core/downloader/init.py#Downloader:
def _get_slot(self, request, spider):
key = self._get_slot_key(request, spider)
if key not in self.slots:
conc = self.ip_concurrency if self.ip_concurrency else self.domain_concurrency
conc, delay = _get_concurrency_delay(conc, spider, self.settings)
self.slots[key] = Slot(conc, delay, self.randomize_delay)
return key, self.slots[key]
def _get_slot_key(self, request, spider):
if 'download_slot' in request.meta:
return request.meta['download_slot']
key = urlparse_cached(request).hostname or ''
if self.ip_concurrency:
key = dnscache.get(key, key)
return key
对于一个request,先调用’_get_slot_key’获取request对应的key,’_get_slot_key’函数中,可以通过给request的meta中添加’download_slot’来控制request的key值,这样增加了灵活性。如果没有定制request的key,则key值来源于request要访问的域名。
另外对于request对应的域名也增加了缓存机制:urlparse_cached,dnscahe。
同时也通过slots集合达到了缓存的目的,对于同一个域名的访问策略可以通过slots获取而不用每次都解析配置。
然后根据key从slots里取对应的Slot对象,如果还没有,则构造一个新的对象。
这个Slot对象有3个参数,并发度,延迟时间和随机延迟。
Downloader:active对象
active是一个活动集合,用于记录当前正在下载的request集合。
Downloader:DownloadHandlers对象
是一个DownloadHandlers对象,它控制了许多handlers,对于不同的下载协议使用不同的handlers。
默认支持handlers如下:
scrapy/settings/default_settings.py:
DOWNLOAD_HANDLERS_BASE = {
'data': 'scrapy.core.downloader.handlers.datauri.DataURIDownloadHandler',
'file': 'scrapy.core.downloader.handlers.file.FileDownloadHandler',
'http': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
'http