- class CrawlSpider(Spider):
- rules = ()
- def __init__(self, *a, **kw):
- super(CrawlSpider, self).__init__(*a, **kw)
- self._compile_rules()
- #首先调用 parse() 来处理 start_urls 中返回的 response 对象
- #parse() 则将这些 response 对象传递给了_parse_response() 函数处理, 并设置回调函数为 parse_start_url()
- #设置了跟进标志位 True
- #parse 将返回 item 和跟进了的 Request 对象
- def parse(self, response):
- return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
- #处理 start_url 中返回的 response, 需要重写
- def parse_start_url(self, response):
- return []
- def process_results(self, response, results):
- return results
- #从 response 中抽取符合任一用户定义'规则'的链接, 并构造成 Resquest 对象返回
- def _requests_to_follow(self, response):
- if not isinstance(response, htmlResponse):
- return
- seen = set()
- #抽取之内的所有链接, 只要通过任意一个'规则', 即表示合法
- for n, rule in enumerate(self._rules):
- links = [l for l in rule.link_extractor.extract_links(response) if l not in seen]
- #使用用户指定的 process_links 处理每个连接
- if links and rule.process_links:
- links = rule.process_links(links)
- #将链接加入 seen 集合, 为每个链接生成 Request 对象, 并设置回调函数为_repsonse_downloaded()
- for link in links:
- seen.add(link)
- #构造 Request 对象, 并将 Rule 规则中定义的回调函数作为这个 Request 对象的回调函数
- r = Request(url=link.url, callback=self._response_downloaded)
- r.meta.update(rule=n, link_text=link.text)
- #对每个 Request 调用 process_request() 函数该函数默认为 indentify, 即不做任何处理, 直接返回该 Request.
- yield rule.process_request(r)
- #处理通过 rule 提取出的连接, 并返回 item 以及 request
- def _response_downloaded(self, response):
- rule = self._rules[response.meta['rule']]
- return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)
- #解析 response 对象, 会用 callback 解析处理他, 并返回 request 或 Item 对象
- def _parse_response(self, response, callback, cb_kwargs, follow=True):
- #首先判断是否设置了回调函数 (该回调函数可能是 rule 中的解析函数, 也可能是 parse_start_url 函数)
- #如果设置了回调函数 (parse_start_url()), 那么首先用 parse_start_url() 处理 response 对象,
- #然后再交给 process_results 处理返回 cb_res 的一个列表
- if callback:
- #如果是 parse 调用的, 则会解析成 Request 对象
- #如果是 rule callback, 则会解析成 Item
- 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
- #如果需要跟进, 那么使用定义的 Rule 规则提取并返回这些 Request 对象
- if follow and self._follow_links:
- #返回每个 Request 对象
- for request_or_item in self._requests_to_follow(response):
- yield request_or_item
- def _compile_rules(self):
- def get_method(method):
- if callable(method):
- return method
- elif isinstance(method, basestring):
- 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)
- def set_crawler(self, crawler):
- super(CrawlSpider, self).set_crawler(crawler)
- self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)
来源: https://www.cnblogs.com/jiangzijiang/p/8480896.html