一、介绍CrawlSpider
CrawlSpider其实是Spider的一个子类,除了继承到Spider的特性和功能外,还派生除了其自己独有的更加强大的特性和功能。其中最显著的功能就是”LinkExtractors链接提取器“。Spider是所有爬虫的基类,其设计原则只是为了爬取start_url列表中网页,而从爬取到的网页中提取出的url进行继续的爬取工作使用CrawlSpider更合适。
源码:
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)
文档:Spiders — Scrapy 2.9.0 documentation
二、框架搭建
1.创建scrapy框架工程 scrapy startproject Meitou 2.进入工程目录 cd Meitou 3.创建爬虫文件 scrapy genspider -t crawl 爬虫任务名称 爬取的范围域 scrapy genspider -t crawl crawl_yjin xx.com 此指令对比以前指令多了"-t crawl",表示创建的爬虫文件是基于CrawlSpider这个类的,而不再是Spider这个基类。 4.启动爬虫文件 scrapy crawl crawl_yjin --nolog
(一)、查看生成的爬虫文件 :
Rule(规则): 规范url构造请求对象的规则
LinkExtractor(链接提取器):规范url的提取范围
CrawlSpider:是一个类模板,继承自Spider,功能就更加的强大
(二)、查看LinkExtractor源码:
LinkExtractor 链接提取器
作用:提取response中符合规则的链接。
主要参数含义:
LinkExtractor:规范url提取可用的部分 allow=(): 满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。 deny=(): 与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。 allow_domains=():允许的范围域 deny_domains=(): 不允许的范围域 restrict_xpaths=(): 使用xpath表达式,和allow共同作用过滤链接(只选到节点,不选到属性) tags=('a', 'area'): 指定标签 attrs=('href',): 指定属性
(三)、查看Rule源码:
Rule : 规则解析器。根据链接提取器中提取到的链接,根据指定规则提取解析器链接网页中的内容
Rule (LinkExtractor(allow=r"Items/"), callback="parse_item", follow=True)
主要参数含义:
- - link_extractor为LinkExtractor,用于定义需要提取的链接
- - callback参数:当link_extractor获取到链接时参数所指定的值作为回调函数
- - callback参数使用注意: 当编写爬虫规则时,请避免使用parse作为回调函数。于CrawlSpider使用parse方法来实现其逻辑,如果您覆盖了parse方法,crawlspider将会运行失败
- - follow:指定了根据该规则从response提取的链接是否需要跟进。 当callback为None,默认值为True
- - process_links:主要用来过滤由link_extractor获取到的链接
- - process_request:主要用来过滤在rule中提取到的request
rules=( ):指定不同规则解析器。一个Rule对象表示一种提取规则。
(四)、CrawlSpider整体爬取流程:
(a) 爬虫文件首先根据起始url,获取该url的网页内容
(b) 链接提取器会根据指定提取规则将步骤a中网页内容中的链接进行提取
(c) 规则解析器会根据指定解析规则将链接提取器中提取到的链接中的网页内容根据指定的规则进行解析
(d) 将解析数据封装到item中,然后提交给管道进行持久化存储
三、基于CrawlSpider使用
(1)spider爬虫文件代码
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class CrawlYjinSpider(CrawlSpider):
name = "crawl_yjin"
allowed_domains = ["xiachufang.com"]
start_urls = ["https://www.xiachufang.com/category/40073/"] # 起始url (分类列表的小吃)
# 创建一个Rule对象(也创建一个LinkExtractor对象)
rules = (
# 菜单详情地址
# https://www.xiachufang.com/recipe/106909278/
# https://www.xiachufang.com/recipe/1055105/
Rule(LinkExtractor(allow=r".*?/recipe/\d+/$"), callback="parse_item", follow=False),
)
# 解析菜单详情
def parse_item(self, response):
# 不需要手动构造item对象
item = {}
# print(response.url)
# 图片链接,名称,评分,多少人做过,发布人
item['imgs'] = response.xpath('//div/img/@src').get()
#去除空格和\n
item['title']=''.join(response.xpath('//div/h1/text()').get()).replace(' ','').replace('\n','')
item['score']=response.xpath('//div[@class="score float-left"]/span[@class="number"]/text()').extract_first()
item['number']=response.xpath('//div[@class="cooked float-left"]/span[@class="number"]/text()').get()
item['author']=''.join(response.xpath('//div[@class="author"]/a/img/@alt').get()).replace('的厨房','')
# print(item)
return item
(2)数据保存>>pipelines管道文件
import json
from itemadapter import ItemAdapter
class MeitouPipeline:
"""处理items对象的数据"""
def __init__(self):
self.file_=open('xcf-1.json','w',encoding='utf-8')
print('文件打开了。。。')
def process_item(self, item, spider):
"""item接收爬虫器丢过来的items对象"""
py_dict=dict(item) # 先把携带键值对数据items对象转成字典
#dict转换成json数据
json_data=json.dumps(py_dict,ensure_ascii=False)+",\n"
#写入
self.file_.write(json_data)
print("写入数据...")
return item
def __del__(self):
self.file_.close() #关闭
print('文件关闭了....')
(3) settings相关设置 >>settings.py设置文件
# 全局用户代理,默认是被注释了,不生效
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# 设置下载延时
DOWNLOAD_DELAY = 1
#开启管道
ITEM_PIPELINES = {
"Meitou.pipelines.MeitouPipeline": 300,
}
(4)运行程序 >>scrapy crawl crawl_yjin --nolog
查看保存的json文件