Scrapy框架之CrawlSpider
一、介绍
CrawlSpider是Spider的一个子类,除了继承到Spider的特性和功能外,还派生除了其自己独有的更加强大的特性和功能。
其中最显著的功能就是"LinkExtractors"链接提取器。Spider是所有爬虫的基类,其设计原则只是为了爬取start_url列表中网页,而从爬取到的网页中提取出的url进行继续的爬取工作使用CrawlSpider更合适。
CrawlSpider类定义了一些规则(rule)来提供跟进link的方便的机制,从爬取的网页中获取link并继续爬取。
二、创建步骤
1.创建scrapy工程:scrapy startproject projectName 2.创建爬虫文件:scrapy genspider -t crawl spiderName www.xxx.com --此指令对比之前的指令多了 "-t crawl",表示创建的爬虫文件是基于CrawlSpider这个类的,而不再是Spider这个基类。 3.启动项目:scrapy crawl spiderName
三、分析基于CrawlSpider生成的爬虫文件
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor # 导入CrawlSpider相关模块 from scrapy.spiders import CrawlSpider, Rule class QiubaiSpider(CrawlSpider): # 表示该爬虫程序是基于CrawlSpider类的 name = 'qiubai' # allowed_domains = ['https://www.qiushibaike.com/text/'] start_urls = ['https://www.qiushibaike.com/text/'] # LinkExtractor:链接提取器,用正则(xpath)定义需要爬取的url,从起始url对应的页面中提取符合要求的链接 # rules:定义"提取动作",rules中可以包含一个或多个Rule对象,在Rule对象中包含了LinkExtractor对象。 # callback:定义解析方法 # follow=True:将链接提取器继续作用到链接提取器提取出的链接所对应的页面中 rules = ( Rule(LinkExtractor(allow=r'/text/page/\d+/'), callback='parse_item', follow=True), ) def parse_item(self, response): i = {} #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract() #i['name'] = response.xpath('//div[@id="name"]').extract() #i['description'] = response.xpath('//div[@id="description"]').extract() return i
分析:
3.1 定义LinkExtractor的几种方法 LinkExtractor( allow=r'Items/',# 满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。 deny=xxx, # 满足正则表达式的则不会被提取。 restrict_xpaths=xxx, # 满足xpath表达式的值会被提取 restrict_css=xxx, # 满足css表达式的值会被提取 deny_domains=xxx, # 不会被提取的链接的domains。 ) 3.2 Rule:规则解析器。根据链接提取器中提取到的链接,根据指定规则提取解析器链接网页中的内容。 Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True) - 参数介绍: 参数1:指定链接提取器 参数2:指定规则解析器解析数据的规则(回调函数) 参数3:是否将链接提取器继续作用到链接提取器提取出的链接网页中。当callback为None,参数3的默认值为true。 3.3 rules=( ):指定不同规则解析器。rules中可以包含一个或多个Rule对象,一个Rule对象表示一种提取规则。 3.4 CrawlSpider整体爬取流程: a)爬虫文件首先根据起始url,获取该url的网页内容 b)链接提取器会根据指定提取规则将步骤a中网页内容中的链接进行提取 c)规则解析器会根据指定解析规则将链接提取器中提取到的链接中的网页内容根据指定的规则进行解析 d)将解析数据封装到item中,然后提交给管道进行持久化存储
四、爬取糗事百科文字板块的所有页码数据
1、settings.py USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' ROBOTSTXT_OBEY = False ITEM_PIPELINES = { 'qiubaiPro.pipelines.QiubaiproPipeline': 300, } 2、爬虫文件 # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from qiubaiPro.items import QiubaiproItem class QiubaiSpider(CrawlSpider): name = 'qiubai' # allowed_domains = ['https://www.qiushibaike.com/text/'] start_urls = ['https://www.qiushibaike.com/text/'] rules = ( # 爬取所有页码数 Rule(LinkExtractor(allow=r'/text/page/\d+/'), callback='parse_item', follow=True), # 这个是首页,首页与其他页码数不同,因此定义另一个正则去匹配 Rule(LinkExtractor(allow=r'/text/$'), callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('//div[@id="content-left"]/div') for div in div_list: # 定义item item = QiubaiproItem() # 爬取作者 author = div.xpath('.//div[@class="author clearfix"]/a/h2/text()') if author: author = author[0].extract() else: author = "匿名用户" # 爬取这个用户的段子的内容contents contents = div.xpath('.//div[@class="content"]/span/text()') # 遇到换行br就会生成一个Selector对象 content = ''.join([selector.extract().strip() for selector in contents]) # 将item提交至管道 item['author'] = author item['content'] = content yield item 3、items.py import scrapy class QiubaiproItem(scrapy.Item): # define the fields for your item here like: author = scrapy.Field() # 作者 content = scrapy.Field() # 内容 4、pipelines.py class QiubaiproPipeline(object): def __init__(self): self.fp = None def open_spider(self, spider): print('开始爬虫') self.fp = open('./data.txt', 'w', encoding='utf8') def process_item(self, item, spider): # 将爬虫文件提交的item写入文件进行持久化存储 self.fp.write(item['author'] + ':' + item['content'] + '\n') return item def close_spider(self, spider): print('结束爬虫') self.fp.close()