学科分类
目录
网络爬虫

CrawlSpider类的工作原理

接下来,我们通过分析CrawlSpider类的实现代码,来探寻CrawlSpider自动爬取全站网页的原理。因为CrawlSpider继承了Spider,所以具有Spider的所有函数,此外,它还定义了自己的若干属性和方法。CrawlSpider类的新属性名为rules。

rules属性表示一个包含一个或多个Rule对象的列表。每个rule对爬取网站的动作定义了特定表现。Rule对象在后续会进行介绍。如果多个rule匹配了同一个链接,则根据它们在本属性中定义的顺序,使用第一个rule。

CrawlSpider类还定义了若干方法,这些方法的名称和说明如表1所示。

表1 CrawlSpider类的方法

名称 说明
初始化方法 负责初始化,并调用了_compile_rules方法。
parse 该方法进行了重写,在实现体中直接调用方法_parse_response,并把parse_start_url方法作为处理response的方法。
parse_start_url 该方法的主要作用是处理parse返回的response,比如提取出需要的数据等。该方法需要返回item、request或者它们的可迭代对象。
_requests_to_follow 该方法的作用是从response中解析出目标url,并将其包装成request请求。该请求的回调方法是_response_downloaded,这里为request的meta值添加了rule参数,该参数的值是这个url对应rule在rules中的下标。
_response_downloaded 该方法是方法_requests_to_follow的回调方法,其作用就是调用_parse_response方法,处理下载器返回的response,设置response的处理方法为rule.callback方法。
_parse_response 该方法将resposne交给参数callback代表的方法去处理,然后处理callback方法的requests_or_item。再根据rule.follow and spider._follow_links来判断是否继续采集,如果继续那么就将response交给_requests_to_follow方法,根据规则提取相关的链接。spider._follow_links的值是从settings的CRAWLSPIDER_FOLLOW_LINKS值获取到的。
_compile_rules 这个方法的作用就是将rule中的字符串表示的方法改成实际的方法,方便以后使用。

当CrawlSpider爬虫运行时,首先由start_requests方法(继承自Spider类)对start_urls中的每一个url发起请求(使用make_requests_from_url方法,继承自Spider类)。网页请求发出后返回的Response会被parse方法接收。在Spider里面的parse需要我们定义,但CrawlSpider类里使用了parse方法来解析响应,其代码如下所示。

  def parse(self, response):
     return self._parse_response(response, self.parse_start_url,
     cb_kwargs={}, follow=True)

从上述代码可知,CrawlSpider类的parse方法直接调用了_parse_response方法。

_parse_response方法用于处理response对象,它根据有无callback,follow和self.follow_links执行不同的操作,其源代码如下所示。

def _parse_response(self, response, callback, cb_kwargs, follow=True):
  #如果传入了callback,使用这个callback解析页面并获取解析得到的reques或item
     if callback:
       cb_res = callback(response, **cb_kwargs) or ()
       cb_res = self.process_results(response, cb_res)
       for requests_or_item in iterate_spider_output(cb_res):
         yield requests_or_item
  # 其次判断有无follow,用_requests_to_follow解析响应是否有符合要求的link。
     if follow and self._follow_links:
       for request_or_item in self._requests_to_follow(response):
         yield request_or_item

其中_ requests_to_follow方法又会获取link_extractor解析页面得到的link(link_extractor.extract_links(response)),对url进行加工(process_links,需要自定义),对符合的link发起Request。使用.process_request(需要自定义)处理响应。_requests_to_follow方法的源代码如下所示。

def _requests_to_follow(self, response):
     if not isinstance(response, HtmlResponse):
       return
     seen = set()
     for n, rule in enumerate(self._rules):
       links = [lnk for lnk in rule.link_extractor.extract_links(response)
            if lnk not in seen]
       if links and rule.process_links:
         links = rule.process_links(links)
       for link in links:
         seen.add(link)
         r = self._build_request(n, link)
         yield rule.process_request(r)

在_requests_to_follow方法中,使用了set类型来记录提取出的链接,这是因为set类型本身就有去重的功能。

那么CrawlSpider如何获取rules呢?

CrawlSpider类会在 _ _ init_ _ 方法中调用_ compile_rules方法,然后在其中浅拷贝rules中的各个Rule获取要用于回调(callback),要进行处理的链接(process_links)和要进行的处理请求(process_request)。_compile_rules方法的源码如下所示。

def _compile_rules(self):
     def get_method(method):
       if callable(method):
         return method
       elif isinstance(method, six.string_types):
         return getattr(self, method, None)
     self._rules = [copy.copy(r) for r in self.rules]
     for rule in self._rules:
       rule.callback = get_method(rule.callback)
       rule.process_links = get_method(rule.process_links)
       rule.process_request = get_method(rule.process_request)

通过分析CrawlSpider类的源码,我们知道了CrawlSpider类的工作原理,对理解和使用CrawlSpider类都大有裨益。

点击此处
隐藏目录