12. scrapy 框架持续化存储
一、 基于终端指令的持久化存储
- 保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作
执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储:
scrapy crawl 爬虫名称 -o xxx.json
scrapy crawl 爬虫名称 -o xxx.xml
scrapy crawl 爬虫名称 -o xxx.csv
持久化存储,可以存储的数据类型有:
示例1: 爬取boss直聘网中在搜索框中搜索python的相关职位,薪资,公司
https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position=
1 # 基于终端指令的持久化储存 2 3 class BossSpider(scrapy.Spider): 4 name = 'boss' 5 # allowed_domains = ['www.xxx.com'] 6 # 起始的爬取的url列表 7 start_urls = ['https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position='] 8 9 def parse(self, response): 10 # xpath为response中的方法,可以将xpath表达式直接作用于该函数中 11 li_list = response.xpath('//div[@class="job-list"]/ul/li') 12 13 # 用于存储解析到数据 14 dic_data= [] 15 for li in li_list: 16 # xpath函数返回的为列表,列表中存放的数据为Selector类型的数据 17 title = li.xpath('.//div[@class="info-primary"]/h3/a/div[1]/text()').extract_first() 18 pay = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first() 19 company = li.xpath('.//div[@class="company-text"]/h3/a/text()').extract_first() 20 21 # 将解析到的数据封装到字典中 22 dic = { 23 "title":title, 24 "pay":pay, 25 "company":company 26 } 27 # 将分封住好的字典添加列表中 28 dic_data.append(dic) 29 return dic_data
在cmd终端中进行持久化存储,即可将数据保存到本地指定文件中
二、基于管道的持久化存储
scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:
items.py:数据结构模板文件。定义数据属性。使用时需要在爬虫文件中导入其定义的类方法
pipelines.py:管道文件。接收数据(items),进行持久化操作
注意:
items文件和pipelines文件必须要同时使用才能够生效(同生共死的关系)
使用管道进行持久化存储的流程:
1. 爬虫文件获取解析到的数据值
2. 将解析后的数据值储存到item对象中(item类惊醒相关属性的声明)
3. 使用yield关键字将items对象提交给pipelines管道进行持久化操作。
4. 在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,
然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
5. 在setting配置文件中开启管道
示例2:
爬取boss直聘网中在搜索框中搜索python的相关职位,薪资,公司
爬虫文件:boos.py
1 # -*- coding: utf-8 -*- 2 import scrapy 3 # 将在items文件中解析到值原文件类导入进来 4 from bossPorject.items import BossporjectItem 5 6 7 class BossSpider(scrapy.Spider): 8 name = 'boss' 9 # allowed_domains = ['www.xxx.com'] 10 # 起始的爬取的url列表 11 start_urls = ['https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position='] 12 13 def parse(self, response): 14 # xpath为response中的方法,可以将xpath表达式直接作用于该函数中 15 li_list = response.xpath('//div[@class="job-list"]/ul/li') 16 17 for li in li_list: 18 # xpath函数返回的为列表,列表中存放的数据为Selector类型的数据 19 # 解析到的内容被封装在了Selector对象中,需要调用extract()函数将解析的内容从Selecor中全部取出 20 # 如果Selector对象中只有一个值,使用extract_first()函数,将解析出内容取出
# 1.爬虫文件获取解析到数据值 21 title = li.xpath('.//div[@class="info-primary"]/h3/a/div[1]/text()').extract_first() 22 pay = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first() 23 company = li.xpath('.//div[@class="company-text"]/h3/a/text()').extract_first() 24 25 # 2. 实例化一个item类型的对象 26 item = BossporjectItem() 27 #将解析到数据封装(储存)到item对象中 28 # 这里面的key就是我在items中声明的属性 29 item['title'] = title 30 item['pay'] = pay 31 item['company'] = company 32 33 # 3.使用yield将item对象交给管道进行持久化储存 34 yield item
爬虫文件的作用是什么???:
1.url的指定
2.请求的发送
3.进行数据解析
4. item管道的提交
items.py 文件
import scrapy class BossporjectItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() #储存招聘职位 pay = scrapy.Field() # 储存薪资范围 company = scrapy.Field() #储存公司名称
pipelines.py文件
# 4.管道文件:需要接收爬虫文件提交过来的数据,并对数据进行持久化储存(Io操作) class BossporjectPipeline(object): # 构造方法 def __init__(self): self.fp = None # 定义一个文件描述符属性 # 下面都重写父类的方法: # 1.open_spider方法只会在开始爬虫的时候执行一次(只执行一次!!!) def open_spider(self,spider): self.fp =open('./data.txt','w',encoding="utf-8") print("爬虫开始了!!!") # 2.因为process_item方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中 # 爬虫文件每提交一次item,该方法会被调用一次 # 方法里面的item就是爬虫文件给我提交的item def process_item(self, item, spider): # 将爬虫文件提交的item数据进行持久化储存 self.fp.write(item["title"] + "\t" + item["pay"] + "\t" + item["company"] + "\n") return item # 3.结束爬虫的时候执行一次 def close_spider(self,spider): self.fp.close() print("爬虫结束了!!!")
配置文件: setting.py
5.配置setting文件,开启管道
ITEM_PIPELINES = { 'bossPorject.pipelines.BossporjectPipeline': 300, #300表示为优先级,值越小优先级越高 }
注意: 默认情况下,在setting文件中的管道机制并没有开启,需要进行手动开启
2.1 .基于mysql的管道储存
将示例2中,
在管道文件里将item对象中的数据值存储到了磁盘中,如果将item数据写入mysql数据库的话,
只需要将上述案例中的pipelines管道文件修改成如下形式:
-pipekines.py 文件
# 导入pymysql模块 import pymysql
# 在管道文件中重新定义一个mysql类,也可以在原有代码中修改 class mysqlPipeline(object): # 声明两个对象 conn = None # mysql的链接对象声明 cursor = None # mysql游标对象的声明 # 1.open_spider方法只会在开始爬虫的时候执行一次(只执行一次!!!) def open_spider(self, spider): # 在开始爬虫的时候进行链接数据库 self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='',db='bossw') print(self.conn) # 2.因为process_item方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中 # 爬虫文件每提交一次item,该方法会被调用一次 # 方法里面的item就是爬虫文件给我提交的item def process_item(self, item, spider): # 链接mysql游标 self.cursor = self.conn.cursor() # 执行sql语句 sql = 'insert into boss values("%s","%s","%s")'%(item['title'],item['pay'],item['company']) # 执行事务 try: self.cursor.execute(sql) self.conn.commit() # 如果正确,提交数据 except Exception as e: print(e) self.conn.rollback() # 如果不正确,进行回本 return item # 3.结束爬虫的时候执行一次 def close_spider(self,spider): self.cursor.close() # 执行结束,关闭游标 self.conn.close() # 执行结束,断开数据库链接
-setting.py 文件
ITEM_PIPELINES = { 'bossPorject.pipelines.BossporjectPipeline': 300, # #300表示为优先级,值越小优先级越高 'bossPorject.pipelines.mysqlPipeline': 301, }
2.2 基于redis的管道存储
将示例2中,
在管道文件里将item对象中的数据值存储到了磁盘中,如果将item数据写入mysql数据库的话,
只需要将上述案例中的pipelines管道文件修改成如下形式:
- pipelines.py文件
#基于redis的管道存储 from redis import Redis import json # 重新定义一个基于redis管道类,也可以在原有类的基础上进行修改 class redisPipeline(object): conn = None def open_spider(self,spider): # 创建链接对象 self.conn = Redis(host='127.0.0.1',port=6379) print(self.conn) def process_item(self, item, spider): # 将item中的数据写入字典 dic = { "title":item["title"], "pay":item["pay"], "company":item["company"] } #将字典写入到redis中 self.conn.lpush('jobInfo',json.dumps(dic)) return item
-setting.py
ITEM_PIPELINES = { 'bossPorject.pipelines.BossporjectPipeline': 300, # #300表示为优先级,值越小优先级越高 'bossPorject.pipelines.mysqlPipeline': 301, 'bossPorject.pipelines.redisPipeline': 302, }
pipelines.py文件使用时的几个注意事项:
注意1:
只要涉及到管道持久化存储的相关操作,必须要写到pipelines.py管道文件中
写到爬虫文件中也可以,但是效率没有写到管道文件中效率高
注意2:
一个管道文件中可以设置多个管道类,只需要在setting配置文件中进行开启管道
注意3:如果一个管道文件中有多个管道类的时候,一定要保证每一个管道类的
process_item方法要有 return item 的返回值,
如果没有返回值的话,根据管道执行的优先级,先执行的管道如果没有return返回值的话
下一次执行的执行的管道类就接收不到item了,数据就不能持久化存储了
注意4:
items文件必须和pipelines文件结合着使用的
是应为pipelines管道文件只能接收item类型的数据,
先在我们的爬虫文件获取到数据值,在将我们解析的数据值封装到item中,
最后提交给管道进行操作
注意: 默认情况下,在setting文件中的管道机制并没有开启,需要进行手动开启