前言
Crawlspider是在scrapy普通Spider的基础上加入内部获取指定规则链接的功能,能有效提高我们获取页面中指定链接的效率。(咱也没测过效率,咱也不敢问),常用于 翻页,网页链接循环的采集任务。
scrapy_splash 是在scrapy框架中用来处理js动态渲染页面的第三方库。使用起来还是挺顺手的。
普通scrpy中使用scrpy_splash还是轻轻松松,干干单单的,将每次请求的scrapy.Request修改为SplashRequest,请求页面就会自动加载动态渲染后的页面,返回数据。
Crawlspider中将请求页面的方法进行了封装,我们的目的就是要找到这个封装的方法,修改为SplashRequest就行了。
Crawspider源码分析
Crawlspider是继承与Spider的对象,所以大体请求方法也是相同的,
1.调用start_requests()函数,请求start_urls中的链接。请求的响应传递给parse()函数。
Crawlspider对象中,对parse()方法进行了重写,所以在 爬虫任务spider中禁止定义同名的parse()函数。

我们的旅程也就从这里开始启程了。
parse()函数返回的是self._parse_response()函数的结果,同时传入 start_requests()的响应结果,以及一个self.parse_start_url,
cb_kwargs为空字典,follow是一个布尔值True。
self.parse_start_url参数的源码如下:

可以看到self.parse_start_url在默认值情况下返回的是一个空列表。
2.self._parse_response()函数的源码如下:

首先判断是否存在 callback,callback参数对应的是self.parse_start_url,第一次self.parse_start_url参数未赋值的情况下为空列表。
判断follow参数和self._follow_links是否同时存在。follow参数是个缺省参数,默认为True。
2.1 self._follow_links源码如下:

整个函数看起来是重写CrawlSpider父类的set_crawler()函数,我们的重点在下面。
代码意思理解为读取settings中的CRAWLSPIDER_FOLLOW_LINKS变量值。默认为True,意思就是如果不修改settings中的指定变量值的话,self._follow_links的值就为True。
self._parse_response()函数的条件成立,遍历self._requests_to_follow(response)函数的结果。
3. self._requests_to_follow(response)函数的源码如下:

首先判断响应对象response的类型,类型不是HtmlResponse的话直接返回空值。scrapy_splash生成的对象为SplashTextResponse对象,需要我们重写self._requests_to_follow()函数。
我们的重点是找到CrawlSpider代替手工每次发送的请求。可以看到,前面大部分的逻辑都是用来处理数据,生成新的links,
只有最后一步的遍历中,存在self._build_requests()函数貌似是跟request请求有关的。
4.self._build_requests()函数源码如下:

果然是scrapy的普通Request请求。请求的是我们的link规则中匹配到的url。同时拥有一个callback回调函数。
self._response_downloaded()函数源码如下:

又回到了self._parse_response(),重新来一遍流程,直到走完Rules元组中的所有rule规则。这就是最后一步了。
CrawlSpider源码的理解由于知识有限,大多数源码都只是靠猜测意思来完成,不影响主流请求的情况下,也没有深入了解。
希望没有误导各位小伙伴。(手动滑稽保命O(∩_∩)O哈哈~)
最后放上在实际应用中,CrawlSpider与scrapy_splash的结合使用实例。
CrawlSpider与scrapy_splash的使用实例
选择测试的链接为榆次区人民政府的新闻页面。在列表页中,加入了js的动态渲染。页面无法通过普通spider方法获取。
spider代码如下:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_splash import SplashRequest
from scrapy_splash import SplashTextResponse, SplashJsonResponse, SplashResponse
from scrapy.http import HtmlResponse
class BaiduSpider(CrawlSpider):
name = 'baidu' # 忽略这个任务名称
# allowed_domains = ['baidu.com']
start_urls = ['http://www.yuci.gov.cn/index.html']
rules = (
Rule(LinkExtractor(
restrict_xpaths="//div[@class='bd']/div[@class='conWrap']/div/ul/li[last()]/a[contains(text(),'查看更多')]"),
callback='parse_item',follow=True),
Rule(LinkExtractor(restrict_xpaths="//ul[@class='wz_list']/li//a"), callback='parses_item'),
)
def start_requests(self):
for url in self.start_urls:
print("进入首页")
print(url)
yield scrapy.Request(url)
def _build_request(self, rule, link):
print("进入下")
# print(link.url)
# print(link.text)
r = SplashRequest(url=link.url, callback=self._response_downloaded, args={"wait": 0.5})
r.meta.update(rule=rule, link_text=link.text)
return r
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)
# print("奈斯")
print(len(links))
for link in links:
# print(link)
seen.add(link)
# print("啊哈")
r = self._build_request(n, link)
yield rule.process_request(r)
def parse_item(self, response):
i = {}
print("进入列表页")
print(response)
return i
def parses_item(self, response):
# print("进入详情页")
name = response.xpath("//h1/text()").extract()
print(name)
return ""
首页页面是正常页面,我们在start_requests()函数中使用普通的scrapy.Reuqest()请求。
列表页中页面为JS页面,重写self._build_request()函数,修改请求方法为SplashRequest()。
最终请求结果如下:

如果我们不重新self._build_request()函数,使用CrawlSpider默认的方法,则发送的为普通Request()请求,无法获取结果。
注意: 重写self._requests_to_follow()函数,目的是为了解除对响应对象的限制,有两种方法:
1.如上面代码所展示的,只需要直接注释掉限制响应对象类型的代码即可。
2.添加允许通过的响应对象类型,比如我们使用的是splash方法,响应对象为SplashTextResponse,
重写self._requests_to_follow()函数,将响应对象类型限制修改为:
if not isinstance(response, (SplashTextResponse, SplashJsonResponse, SplashResponse, HtmlResponse)):
return
希望对各位小伙伴有一丢丢的帮助。
我是北房有佳人,咳咳。。。。
参考文章:
https://www.jb51.net/article/129351.htm
https://cuiqingcai.com/4725.html#comments
本文详细介绍了CrawlSpider的源码分析,包括start_requests()、_parse_response()、_requests_to_follow()和_build_requests()函数的工作流程。强调了在CrawlSpider中如何结合scrapy_splash处理动态渲染页面,并提供了实际应用示例,展示了如何在CrawlSpider中重写相关函数以使用SplashRequest进行请求。
1886

被折叠的 条评论
为什么被折叠?



