Scrapy源码阅读记录
因为爬虫需求比较特殊(毕设要做社交网络相关的内容),网上的博客写的都比较拉,互相抄来抄去,找不到有用的东西,只好去啃源码。
主要围绕着scrapy.core
包,具体流程就是从爬虫运行的顺序开始分析,各个从上至下基本上是按顺序来的。
爬虫启动
这部分没找到详细的流程,大致是执行了scrapy.cmdline
的execute
方法。
Crawler类
职责
这个类负责初始启动scrapy的2个部件,包括engine、用户自定义的spider
此外还提供一个CrawlRunner类给用户做参考,让用户可以自定义爬虫爬取的调度方法
主要方法
-
构造方法
从settings.py读取各种有关设置,并通过反射设置日志、统计数据。
-
crawl方法
@defer.inlineCallbacks def crawl(self, *args, **kwargs): assert not self.crawling, "Crawling already taking place" self.crawling = True try: self.spider = self._create_spider(*args, **kwargs) self.engine = self._create_engine() #初始化start_requests为当前任务的spider的start_requests方法 start_requests = iter(self.spider.start_requests()) #engine启动 yield self.engine.open_spider(self.spider, start_requests) yield defer.maybeDeferred(self.engine.start) except Exception: # In Python 2 reraising an exception after yield discards # the original traceback (see https://bugs.python.org/issue7563), # so sys.exc_info() workaround is used. # This workaround also works in Python 3, but it is not needed, # and it is slower, so in Python 3 we use native `raise`. if six.PY2: exc_info = sys.exc_info() self.crawling = False if self.engine is not None: yield self.engine.close() if six.PY2: six.reraise(*exc_info) raise def _create_spider(self, *args, **kwargs): #从命令、配置文件等中创建对应的spider(对应命令scrapy crawl xxxSpider) return self.spidercls.from_crawler(self, *args, **kwargs) def _create_engine(self): #创建engine对象 return ExecutionEngine(self, lambda _: self.stop())
Engine类
职责
这个类负责各种调度,包括request的出入、response的出入等。
主要方法
-
构造方法
设置了crawler(这里的crawler就是上面提到过的Crawler类对象的引用)和engine的状态,以及从settings.py读取设置来生成相应的scheduler的配置(注意是配置,scheduler对应的队列啥的还没配套)、downloader,以及处理parse函数响应返回的Item和Request的Scraper类对象
-
open_spider方法
@defer.inlineCallbacks def open_spider(self, spider, start_requests=(), close_if_idle=True): assert self.has_capacity(), "No free spider slot when opening %r" % \ spider.name logger.info("Spider opened", extra={ 'spider': s