数据持久化的两种方式:(1)基于终端指令的持久化存储;(2)基于管道的持久化存储
基于终端指令的持久化存储
在爬虫文件的parse方法中必须要return可迭代对象类型(通常为列表或字典等)的返回值,该返回值作为基于终端指令持久化指定文件的输出内容。
执行输出指定格式进行存储-------将爬取到的数据写入不同格式的文件中进行存储,存储格式有限:
scrapy crawl 爬虫文件 -o xxx.json
scrapy crawl 爬虫文件 -o xxx.xml
scrapy crawl 爬虫文件 -o xxx.csv
基于管道的持久化存储
(1)编写爬虫文件进行数据解析
(2)在items.py中定义相关字段(用于存储解析的数据)
(3)在爬虫文件中将解析到的数据封装在实例化的item对象中
(4)通过yield将item对象提交到pipelines.py中的管道
(5)在管道中进行任意方式的数据持久化(数据库持久化需要重写两个方法open_spider和close_spider)
(6)在settings.py配置文件中开启管道(ITEM_PIPELINES ,同时处理ROBOTSTXT_OBEY协议、USER_AGENT 伪装和LOG_LEVEL='ERROR'日志输出等级)
(7)启动爬虫:scrapy crawl 爬虫文件
百度首页超链接数据解析与持久化存储
1.编写爬虫文件firstPro.py

1 # -*- coding: utf-8 -*-
2 import scrapy
3 from firstPro.items import FirstproItem
4
5
6 class FirstbaiduSpider(scrapy.Spider):
7 name = 'firstBaidu' # 爬虫文件(应用)名
8 # allowed_domains = ['https://www.baidu.com/']#域名限定,一般直接注释
9 start_urls = ['https://www.baidu.com//'] # 起始url,创建应用时指定的,可修改
10
11 def parse(self, response): # 自动访问起始URL并获取结果后的回调函数,参数respons为起始请求的响应对象,可以直接调用封装好的xpath解析
12
13 # print(response.text)#获取字符串类型的响应内容
14 # print(response.body)#获取字节类型的相应内容
15
16 # 进行数据解析
17 a_list = response.xpath('//p[@id="nv"]/a') # 注意页面解析标签定位!!!浏览器看到的标签位置和实际爬去的页面内容位置可能不一样
18 for a in a_list:
19 # scrapy自带xpath解析获取文本或属性需要使用extract()或extract_first()
20 title = a.xpath('./text()').extract_first().replace('\xa0','') # extract_first()从结果列表获取第一个值
21 url = a.xpath('./@href')[0].extract() # extract()从解析结果中取出所有制,结果只有一个就是字符串,多个就是列表
22 # print(title, url)
23
24 # 解析后的数据需要进行持久化存储:
25 # (1)items.py中定义相关存储字段;
26 item = FirstproItem()
27 # (2)实例化item对象将解析的数据进行封装;
28 item['title'] = title
29 item['url'] = url
30 # (3)使用yield将item对象提交给管道处理
31 yield item
32
33 pass
2.自定义items.py中的类字段

1 # -*- coding: utf-8 -*- 2 3 # Define here the models for your scraped items 4 # 5 # See documentation in: 6 # https://docs.scrapy.org/en/latest/topics/items.html 7 8 import scrapy 9 10 11 class FirstproItem(scrapy.Item): 12 # define the fields for your item here like: 13 # name = scrapy.Field() 14 title=scrapy.Field()#存储标题 15 url=scrapy.Field()#存储连接 16 pass
3.管道pipilines.py处理类定义
注意: (1)要想使用管道进行数据持久化,必须在settings.py中进行开启配置; (2)可以定义多个管道类进行处理,但是在每个process_item函数中必须return item 传递给其它管道使用; (3)process_item参数item只接受爬虫文件提交来的item对象,参数spider是爬虫文件中类的实例化对象,可以进行数据传递; (4)如果要对数九持久化写入到数据库,需要在管道类中重写open_spider和close_spider方法,这两个方法只会被执行一次; (5)对于图片类(视频、音频等二进制)数据的下载有可以定义新的管道继承相关类既可以直接实现图片的下载,注意要在settings.py中指定存储路径IMAGES_STORE=path

1 # 注意: 2 # (1)要想使用管道进行数据持久化,必须在settings.py中进行开启配置 3 # (2)可以定义多个管道类进行处理,但是在每个process_item函数中必须return item 传递给其它管道使用 4 # (3)process_item参数item只接受爬虫文件提交来的item对象,参数spider是爬虫文件中类的实例化对象,可以进行数据传递; 5 # (4)如果要对数九持久化写入到数据库,需要在管道类中重写open_spider和close_spider方法,这两个方法只会被执行一次; 6 # (5)对于图片类(视频、音频等二进制)数据的下载有可以定义新的管道继承相关类既可以直接实现图片的下载 7 8 # 默认管道处理 9 class FirstproPipeline(object): 10 # item对象处理函数 11 def process_item(self, item, spider): 12 print(item) 13 return item

1 # (1)自定义的文件持久化管道
2 class TofilePipeline(object):
3 # 构造方法初始化一个属性文件句柄,也可以定义一个类变量:fp=None
4 def __init__(self):
5 self.fp = None
6
7 # 打开文件句柄
8 def open_spider(self, spider):
9 print('开始写入数据...')
10 self.fp = open('a.text', 'w', encoding='utf-8')
11
12 # 关闭文件进行系统资源回收
13 def close_spider(self, spider):
14 self.fp.close()
15 print('数据下载成功,爬虫结束!')
16
17 def process_item(self, item, spider):
18 self.fp.write(f'{item["title"]}:{item["url"]}\n')
19 return item

1 # (2)自定义的基于mysql数据库持久化管道
2 import pymysql
3 class ToMysqlPipeline(object):
4 conn = None
5 cursor = None
6
7 # 建立数据库连接
8 def open_spider(self, spider):
9 print('建立数据库连接...')
10 self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123456', db='spider')
11
12 # 关闭数据库连接
13 def close_spider(self, spider):
14 self.cursor.close() # conn断开时也会自动断开
15 self.conn.close()
16 print('成功写入数据库!')
17
18 def process_item(self, item, spider):
19 sql = f'insert into table1 values ({item["title"]},{item["url"]})'
20 self.cursor = self.conn.cursor()
21
22 # 数据库事务操作
23 try:
24 self.cursor.execute(sql)
25 self.conn.commit()
26 except Exception as e:
27 print(e)
28 self.conn.rollback()
29
30 return item

1 # (3)自定义的基于redis数据库持久化管道
2 import redis
3 class ToRedisPipeline(object):
4 conn = None
5
6 # 建立数据库连接
7 def open_spider(self, spider):
8 print('建立数据库连接...')
9 self.conn = redis.Redis(host='127.0.0.1', port=6379)
10
11 def process_item(self, item, spider):
12 self.conn.lpush('data', dict(item)) # 将item对象以字典形式存储在redis列表结构中
13 return item

1 # (4)自定义的基于mongodb数据库持久化管道
2 import pymongo
3 class ToMongoDBPipeline(object):
4 conn = None
5
6 # 建立数据库连接
7 def open_spider(self, spider):
8 print('建立数据库连接...')
9 self.conn = pymongo.MongoClient(host='127.0.0.1', port=27017)
10
11 # 关闭数据库连接(可以不写)
12 def close_spider(self, spider):
13 self.conn.close()
14 print('成功写入数据库!')
15
16 def process_item(self, item, spider):
17 self.conn.Spider.col.insert_one({item["title"]:item["url"]}) #将title:url存入mongodb的Spider数据库中col集合(表)中
18 return item

1 # (5)自定义图片等文件的下载管道
2 #IMAGES_STORE='filepath'在settings设置文件中指定存储图片的下载路径
3 import os
4 import scrapy
5 from scrapy.pipelines.images import ImagesPipeline
6
7 class ImageDownloadPipeline(ImagesPipeline):
8 #接收item且将item中存储的url进行请求发送
9 def get_media_requests(self, item, info): # 下载图片
10 url=item["url"]
11 yield scrapy.Request(url, meta={'item': item})
12
13 # 指定下载路径
14 def file_path(self, request, response=None, info=None):
15 item = request.meta['item']
16 img_name = request.url.split('/')[-1]
17 path='图片'#自动会创建文件夹,同时存放在settings.py中指定的IMAGES_STORE配置路径下
18 filename = os.path.join(path, img_name)
19 print(f'正在下载------{filename}...')
20 return filename
21
22 # 将item传递给下一个即将被执行的管道类
23 def item_completed(self, result, item, info):
24 return item
4.settings.py配置文件
1 # Crawl responsibly by identifying yourself (and your website) on the user-agent
2 # USER_AGENT = 'firstPro (+http://www.yourdomain.com)'
3 # (1)UA伪造
4 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
5
6 # Obey robots.txt rules
7 # ROBOTSTXT_OBEY = True
8 # (2)不遵守robots协议
9 ROBOTSTXT_OBEY = False
10
11 # (3)设置日志输出等级
12 LOG_LEVEL = 'ERROR'
13
14
15
16
17 # Configure item pipelines
18 # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
19 # 取消注释,开启管道,数字代表优先级,越小级别越高,按需要开启
20 ITEM_PIPELINES = {
21 'firstPro.pipelines.FirstproPipeline': 300,
22 'firstPro.pipelines.TofilePipeline': 200,
23 # 'firstPro.pipelines.ToMysqlPipeline': 600,
24 'firstPro.pipelines.ToRedisPipeline': 100,
25 # 'firstPro.pipelines.ToMongoDBPipeline': 400,
26 # 'firstPro.pipelines.ImageDownloadPipeline': 200,
27 }
28
29 #如果开启图片下载管道,需要指定下载目录
30 # IMAGES_STORE='./images'
5.启动爬虫程序
scrapy crawl firstPro
