持久化存储
scrapy的高性能持久化存储操作,有两种方式:基于终端指令的持久化存储 和 基于管道的持久化存储操作。
基于终端指令的持久化存储
保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作。
执行指令:
执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储
scrapy crawl 爬虫名称 -o xxx.json
scrapy crawl 爬虫名称 -o xxx.xml
scrapy crawl 爬虫名称 -o xxx.csv
# -*- coding: utf-8 -*- import scrapy class QiushiSpider(scrapy.Spider): name = 'qiushi' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.qiushibaike.com/text/'] def parse(self, response): # # 基于终端的持久化存储 div_list = response.xpath('//div[@class="col1 old-style-col1"]/div') all_data = [] for div in div_list: # xpath返回的是列表 列表中是Selector对象 # extract() 可将对象中的data参数存储的字符串取出 # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract() author = div.xpath('./div[1]/a[2]/h2/text()').extract_first() # 在确定列表只有一个元素的情况下使用 # 列表调用extract() 将列表中每一个Selector对象的data字符串取出来 content = div.xpath('./a[1]/div[1]/span//text()').extract() content = ''.join(content) dic = { 'author': author, 'content': content } all_data.append(dic) # 基于终端持久化存储 要求是存储parse方法的返回值 'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle' return all_data
- 要求:只可以将parse方法的返回值存储到本地的文本文件中
- 注意:持久化存储对应的文本文件的类型只可以为:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle
- 指令:scrapy crawl xxx -o filePath
- 好处:简介高效便捷
- 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中)
基于管道的持久化存储操作
我们首先来认识如下两个文件:
items.py:数据结构模板文件。定义数据属性。
pipelines.py:管道文件。接收数据(items),进行持久化操作。
持久化流程:
1.爬虫文件爬取到数据后,需要将数据封装到items对象中。
2.使用yield关键字将items对象提交给pipelines管道进行持久化操作。
3.在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
4.settings.py配置文件中开启管道
爬虫文件:qiushi.py
# -*- coding: utf-8 -*- import scrapy from qiuShi.items import QiushiItem class QiushiSpider(scrapy.Spider): name = 'qiushi' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.qiushibaike.com/text/'] def parse(self, response): # 基于管道的持久化存储 div_list = response.xpath('//div[@class="col1 old-style-col1"]/div') for div in div_list: # xpath返回的是列表 列表中是Selector对象 # extract() 可将对象中的data参数存储的字符串取出 # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract() author = div.xpath('./div[1]/a[2]/h2/text()').extract_first() # 在确定列表只有一个元素的情况下使用 # 列表调用extract() 将列表中每一个Selector对象的data字符串取出来 content = div.xpath('./a[1]/div[1]/span//text()').extract() content = ''.join(content) item = QiushiItem() item['author'] = author item['content'] = content yield item # 将item提交给管道
items文件:items.py
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class QiushiItem(scrapy.Item): # define the fields for your item here like: author = scrapy.Field() content = scrapy.Field() # 存储的数据用item封装 固定形式
管道文件:pipelines.py
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html import pymysql class QiushiPipeline: # 持久化存储 fp = None # 重写父类方法 该方法只在爬虫开始时执行一次 def open_spider(self, spider): print('爬取开始...') self.fp = open('qishi.txt', 'w', encoding='utf-8') def process_item(self, item, spider): author = item['author'] content = item['content'] self.fp.write(author + ':' + content + ' ') return item # 可以将item交给下一个被执行的管道类 # 重写父类方法 该方法只在爬虫结束时 执行一次 def close_spider(self, spider): print('爬取结束!') self.fp.close() # 管道文件中的一个管道类 对应将数据存储到一个平台或者载体中 class mysqlPipeline:
"""存入数据库""" conn = None cursor = None def open_spider(self, spider): self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='', db='qiushi', charset='utf8') def process_item(self, item, spider): self.cursor = self.conn.cursor() try: self.cursor.execute('insert into qiushi values("%s","%s")' % (item['author'], item['content'])) self.conn.commit() except Exception as e: print(e) self.conn.rollback() return item def close_spider(self, spider): self.cursor.close() self.conn.close() # 管道中的item会被提交到优先级最高的类
配置文件:settings.py
# 开启管道 300为优先级 数值越小 优先级越高 ITEM_PIPELINES = { 'qiuShi.pipelines.QiushiPipeline': 300, 'qiuShi.pipelines.mysqlPipeline': 301 }