Scrapy_pipelines管道文件详细教程保存csv,Mysql,Mongodb以及多个item返回pipelines的处理
文章目录
- piplines的使用
- pipelines介绍
- pipelines常用方法
- pipelines注意点
- 保存为csv,Mysql,Mongodb
- 多个item 返回pipeline的处理
piplines的使用
pipelines介绍
管道文件 pipelines.py 主要用来对抓取的数据进行处理:一般一个类即为一个管道,比如创建存入MySQL、MongoDB 的管道类。管道文件中 process_item() 方法即为处理所抓数据的具体方法。
pipelines常用方法
process_item(self,item,spider):
处理爬虫抓取的具体数据,在 process_item() 函数中 必须要 return item,因为存在多管道时,会把此函数的返回值继续交由下一个管道继续处理;
init():爬虫项目启动时只执行一次,一般用于数据库连接;
close_spider():爬虫项目结束时只执行一次,一般用于收尾工作,如数据库的关闭。
pipelines注意点
- pipeline对应的值越小优先级越高
- pipeline中的process_item方法的名字不能够修改为其他的名称
保存为csv,Mysql,Mongodb
settings.py文件
关于settings具体设置点击查看 Scrapy_settings配置文件设置
# 管道文件设置,保存为哪个,就打开对应的管道,可以同时保存
ITEM_PIPELINES = {
# 300是最后一个
"douban.pipelines.DoubanPipeline": 300,
# Mysql管道
"douban.pipelines.MysqlDoubanPipeline": 299,
# mongodb管道
"douban.pipelines.MongodbDoubanPipeline": 298,
}
pipelines.py文件
# 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
# useful for handling different item types with a single interface
import csv
import pymongo
import pymysql
from itemadapter import ItemAdapter
# 保存csv
class DoubanPipeline:
def __init__(self):
headers = ('title', 'score')
self.f = open('douban.csv', 'w+', encoding='utf-8', newline='')
self.f_csv = csv.DictWriter(self.f, headers)
self.f_csv.writeheader() # 写入表头
def process_item(self, item, spider):
self.f_csv.writerow(item)
return item
def close_spider(self, spider):
self.f.close()
print('douban.csv文件写入完成')
# 保存Mysql
class MysqlDoubanPipeline:
def __init__(self):
# 创建链接
self.db = pymysql.Connect(
host="127.0.0.1",
port=3306,
user="root",
password="密码",
db="数据库"
)
# 创建游标,用于传递python给MySQL的命令和MySQL返回的内容
self.cursor = self.db.cursor()
# 不想手动创建数据库,也可以在init方法中实现
# sql_1 = """
# create table xiangxue009.douban_top250
# (
# `title` text null,
# `score` text null
# );
# """
# self.cursor.execute(sql_1)
def process_item(self, item, spider):
# SQL插入语句
sql = "insert into `douban_Top250`(`title`, `score`) values (%s,%s)"
# 执行SQL语句
self.cursor.execute(sql,[item['title'], item['score']]) # 放值
# 提交到数据库执行
self.db.commit()
return item
def close_spider(self, spider):
# 关闭游标
self.cursor.close()
# 关闭连接
self.db.close()
print('Mysql文件写入完成')
# 保存Mongodb
class MongodbDoubanPipeline:
# 初始化方法
def __init__(self):
# 连接mongo
self.myclient = pymongo.MongoClient("mongodb://localhost:27017")
# 连接mydb数据库,账号密码认证
# self.myclient = self.myclient.admin # 连接系统默认数据库admin
# self.myclient.authenticate("用户名", "密码")
"""
如果出错了,报错:pymongo.errors.OperationFailure: auth failed,可以增加mechanism参数,因为mongoDB有不同的认证机制
3.0版本以后采用的是'SCRAM-SHA-1', 之前的版本采用的是'MONGODB-CR'
即:self.myclient.authenticate("用户名", "密码",mechanism='MONGODB-CR')
"""
# 连接数据库,没有则自动创建
self.db = self.myclient.xiangxue009
def process_item(self, item, spider):
# print(item)
# 连接集合,没有集合则自动创建,连接后导入单条数据(类型为字典)
self.db.douban_Top250.insert_one(dict(item))
return item
# spider一定要加在参数里,不然会报错
def close_spider(self, spider):
print('Mongo文件写入完成')
print('爬虫结束!!')
print('当前爬虫的名字',spider) # 当前爬虫的名字
关于spider参数
多个item 返回pipeline的处理
我们有时候爬的数据不需要存在一张表里,但是如果需要爬两次,或者全部保存在一个item里在提取就不方便
所以我们会设置多个items,多个items的时候pipelines.py文件怎么保存呢
大致分为三步:
- 新建items类,创建管道
- 爬虫文件传输数据到对应的管道
- pipelines判断管道类型存入数据
items.py
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
# 第一个管道
class DoubanItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 创建标题字段
title = scrapy.Field()
# 创建评分字段
score = scrapy.Field()
# 第二个管道
class DoubanItem2(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 创建标题字段
abstract_name = scrapy.Field()
# 创建导演字段
abstract = scrapy.Field()
douban_data.py
import scrapy
# 导入两个管道
from ..items import DoubanItem,DoubanItem2
class DoubanDataSpider(scrapy.Spider):
name = "douban_data"
allowed_domains = ["www.douban.com"]
# 把url换成我们需要爬取的
start_urls = ["https://www.douban.com/doulist/124084417/?start=0&sort=seq&playable=0&sub_type="]
# 爬虫函数 添加**kwargs就不会报黄
def parse(self, response,**kwargs):
# print(response)
# print(type(response))
# 获取25个大盒子
data_divs = response.xpath('//*[@class="doulist-item"]')
print(data_divs,len(data_divs))
# 创建第一个管道实例
items = DoubanItem()
# 创建第二个管道实例
items2 = DoubanItem2()
for data in data_divs:
# 电影标题
title = ''.join(data.xpath('./div/div[2]/div[@class="title"]//text()').getall()).strip()
# 电影评分
score = ''.join(data.xpath('./div/div[2]/div[@class="rating"]//text()').getall()).replace('\n','').strip().replace(' ','')
# 电影导演
abstract = '-'.join(data.xpath('./div/div[2]/div[@class="abstract"]//text()').getall()).replace('\n','').strip().replace(' ','')
print(title)
print(score)
print(abstract)
# 第一个管道
items['title'] = title
items['score'] = score
# 第二个管道
items2['abstract_name'] = title
items2['abstract'] = abstract
print('items',items)
print('items2',items2)
# 返回数据
yield items
# 可以yield 很多次
yield items2
pipelines.py文件,核心文件
# 导入管道
import csv
# 导入管道,注意要带. 不然管道的类型就和item的数据类型不一样
from .items import DoubanItem,DoubanItem2
class DoubanPipeline:
def __init__(self):
# 第一个管道保存文件
headers = ('title', 'score')
self.f = open('douban.csv', 'w+', encoding='utf-8', newline='')
self.f_csv = csv.DictWriter(self.f, headers)
self.f_csv.writeheader() # 写入表头
# 第二个管道保存文件
headers = ('abstract_name', 'abstract')
self.f2 = open('douban2.csv', 'w+', encoding='utf-8', newline='')
self.f_csv2 = csv.DictWriter(self.f2, headers)
self.f_csv2.writeheader() # 写入表头
def process_item(self, item, spider):
#### 核心代码
# 判断是不是第一个管道
if isinstance(item,DoubanItem):
self.f_csv.writerow(item)
# 是的话保存过后直接返回,告诉引擎保存好了,可以下一个了,就不用在执行elif了
return item
# 判断是不是第二个管道
elif isinstance(item,DoubanItem2):
self.f_csv2.writerow(item)
# 是的话保存过后直接返回,告诉引擎保存好了,可以下一个了
return item
def close_spider(self, spider):
# 关闭文件
self.f.close()
print('douban.csv文件写入完成')
self.f2.close()
print('douban2.csv文件写入完成')
pipelines.py文件,核心文件解读
def process_item(self, item, spider):
# 看他们的类型
print(item,type(item))
print(DoubanItem)
print('isinstance(item,DoubanItem)',isinstance(item,DoubanItem))
print(DoubanItem2)
print('isinstance(item,DoubanItem2)',isinstance(item,DoubanItem2))
可以看到 <class ‘douban.items.DoubanItem’>和<class ‘douban.items.DoubanItem2’>两个类型
所有我们只需要判断item的类型就行,将相应的管道存入相应的数据就行
比如第一个管道的数据存csv,第二个管道存Mysql,这样就只需要在item加一个判断即可
操作性可大了
后面还会更新图片管道和视频管道教程