scrapy爬虫之item pipeline保存数据

##简介

前面的博文我们都是使用"-o ***.josn"参数将提取的item数据输出到json文件,若不加此参数提取到的数据则不会输出。其实当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。当我们创建项目时,scrapy会生成一个默认的pipelines.py,如:

vim pipelines.py
class DoubanPipeline(object):
    def process_item(self, item, spider):
        return item

但是我们没有具体定义,因此执行爬虫并不会输出结果。

下面我们还是通过定义pipeline,使提取到的item通过pipeline输出到json文件、mongodb数据库。
本文爬虫以scrapy爬虫之crawlspide爬取豆瓣近一周同城活动为例,在此我们更新item、item pipeline即可。

##输出到json文件
1.定义item

vim items.py
def filter_string(x):
	str = x.split(':')
	return str[1].strip()
class tongcheng(scrapy.Item):
        #主题
        title = scrapy.Field()
        #时间
        time = scrapy.Field()
        #地址
        address = scrapy.Field(output_processor=Join())
        #票价
        money = scrapy.Field()
        #感兴趣人数
        intrest = scrapy.Field()
        #参加人数
        join = scrapy.Field()

2.定义item pipeline

vim pipelines.py
#以json格式输出
from scrapy.exporters import JsonItemExporter
#以jl格式输出
#from scrapy.exporters import JsonLinesItemExporter
#以csv格式输出
#from scrapy.exporters import CsvItemExporter
class tongcheng_pipeline_json(object):
	def open_spider(self, spider):
		#可选实现,当spider被开启时,这个方法被调用。
		#输出到tongcheng_pipeline.json文件
		self.file = open('tongcheng_pipeline.json', 'wb')
		self.exporter = JsonItemExporter(self.file, encoding='utf-8')
		self.exporter.start_exporting()
	def close_spier(selef, spider):
		#可选实现,当spider被关闭时,这个方法被调用
		self.exporter.finish_exporting()
		self.file.close()
	def process_item(self, item, spider):
		self.exporter.export_item(item)
		return item

3.激活item pipeline
我们的pipeline定义后,需要在配置文件中添加激活才能使用,因此我们需要配置settings.py。

vim settings.py
ITEM_PIPELINES = {
	#默认使用这个,但我们没有定义,因此注释掉。
    #'douban.pipelines.DoubanPipeline': 300,
    #在此添加我们新定义的pipeline
    'douban.pipelines.tongcheng_pipeline_json': 300,
}

4.启动爬虫

scrapy crawl tongcheng
#打印信息中会显示
2018-01-20 10:48:10 [scrapy.middleware] INFO: Enabled item pipelines:
['douban.pipelines.tongcheng_pipeline_json']
....

#查看tongcheng_pipeline.json文件
cat tongcheng_pipeline.json
[{"money": ["263元"], "address": "深圳  深圳市少年宫剧场 深圳市福田区福中一路市少年宫", "join": ["69 "], "intrest": ["174 "], "title": ["孟京辉戏剧作品《一个陌生女人的来信》深圳站"]},{"money": ["93 - 281元"], "address": "深圳  南山文体中心剧院 小剧场 深圳市南山区南山大道南山文体中心", "join": ["4 "], "intrest": ["11 "],"title": ["2018第五届城市戏剧节 诗·歌·舞变奏三幕剧《木心·人曲》-深圳"]}.....]

如上显示,则说明我们的爬虫调用了配置文件中的pipeline,
并将提取的item输出到tongcheng_pipeline.json文件了。

###注意
1.在settings.py中设置的pipeline,会被project中的所有爬虫按照优先级默认调用,例如:

ITEM_PIPELINES = {
    'douban.pipelines.DoubanPipeline': 300,
    'douban.pipelines.movieTop250_crawlspider_json': 200,
    'douban.pipelines.tongcheng_pipeline_json': 100,
}

当我们"scrapy crawl tongcheng"时,会按照优先级从低到高也就是100、200、300顺序调用pipeline,从打印信息中可以看到:

2018-01-20 10:48:10 [scrapy.middleware] INFO: Enabled item pipelines:
['douban.pipelines.tongcheng_pipeline_json',
douban.pipelines.movieTop250_crawlspider_json,
douban.pipelines.DoubanPipeline
]

2.不同spider绑定pipeline
由于一个project中有多个不同功能的爬虫,我们需要将爬虫绑定不同的pipeline,以将提取的内容保存到不同地方。如何实现?
我们知道scrapy运行会调用不同的配置文件,按照优先级从高到低为:

1.Command line options (most precedence)
2.Settings per-spider
3.Project settings module
4.Default settings per-command
5.Default global settings (less precedence

我们使用的settings.py属于“Project settings module”
,因此我们需要使用优先级比它高的配置文件即可实现绑定pipeline,例如“Settings per-spider”。

vim tongcheng.py
#在下面添加custom_settings即可
class TongchengSpider(CrawlSpider):
    name = 'tongcheng'
    allowed_domains = ['douban.com']
    start_urls = ['https://www.douban.com/location/shenzhen/events/week-all']
    custom_settings = {
    	'ITEM_PIPELINES': {
    	    'douban.pipelines.tongcheng_pipeline_json': 300,
    	}
    }
    rules = (
        Rule(LinkExtractor(allow=r'start=10')),
        Rule(LinkExtractor(allow=r'https://www.douban.com/event/\d+/'),callback='parse_item'),
    )   
    
    def parse_item(self, response):
        loader = ItemLoader(item=tongcheng(),selector=response)
        info = loader.nested_xpath('//div[@class="event-info"]')
        info.add_xpath('title','h1[@itemprop="summary"]/text()')
        info.add_xpath('time','div[@class="event-detail"]/ul[@class="calendar-strs"]/li/text()')
        info.add_xpath('address','div[@itemprop="location"]/span[@class="micro-address"]/span[@class="micro-address"]/text()')
        info.add_xpath('money','div[@class="event-detail"]/span[@itemprop="ticketAggregate"]/text()')
        info.add_xpath('intrest','div[@class="interest-attend pl"]/span[1]/text()')
        info.add_xpath('join','div[@class="interest-attend pl"]/span[3]/text()')
        
        yield loader.load_item()

通过custom_settings我们可以绑定tongcheng_pipeline_json
,从而避免调用setttings.py中的所有pipeline。

##输出到mongodb

由于是测试,我们在此使用docker安装并运行mongo

1.docker安装mongo

#查看镜像
sudo docker search mongo
#安装镜像
sudo docker pull mongo
#启动mongodb,将镜像端口27017映射到本地端口27017,挂在本地数据目录到镜像内的/data/db
sudo docker run --name scrapy-mongodb -p 27017:27017 -v /home/yanggd/docker/mongodb:/data/db -d mongo
#本地连接到mongo
sudo docker run -it mongo mongo --host 10.11.2.102

2.添加数据库链接参数到配置文件

vim ../settings.py
#最后添加
MONGO_HOST = '10.11.2.102'
MONGO_PORT = 27017
MONGO_DB = 'douban'

3.定义pipelines

vim pipelines.py
import pymongo
class tongcheng_pipeline_mongodb(object):
        mongo_collection = "tongcheng"
        def __init__(self, mongo_host, mongo_port, mongo_db):
                self.mongo_host = mongo_host
                self.mongo_port = mongo_port
                self.mongo_db = mongo_db
        @classmethod
        def from_crawler(cls, crawl):
                return cls(
                        mongo_host = crawl.settings.get("MONGO_HOST"),
                        mongo_port = crawl.settings.get("MONGO_PORT"),
                        mongo_db = crawl.settings.get("MONGO_DB")
                )       
        def open_spider(self, spider):
                self.client = pymongo.MongoClient(self.mongo_host, self.mongo_port)
                self.db = self.client[self.mongo_db]
        def close_spider(self, spider):
                self.client.close()
        def process_item(self, item, spider):
                tongchenginfo = dict(item)
                self.db[self.mongo_collection].insert_one(tongchenginfo)
                return item

3.绑定pipeline

由于project中有多个爬虫,因此我们需要通过custom_settings绑定pipeline。

vim tongcheng.py
#在下面添加custom_settings即可
class TongchengSpider(CrawlSpider):
    name = 'tongcheng'
    allowed_domains = ['douban.com']
    start_urls = ['https://www.douban.com/location/shenzhen/events/week-all']
    custom_settings = {
    	'ITEM_PIPELINES': {
   	    'douban.pipelines.tongcheng_pipeline_mongodb': 300,
    	}
    }
    rules = (
        Rule(LinkExtractor(allow=r'start=10')),
        Rule(LinkExtractor(allow=r'https://www.douban.com/event/\d+/'),callback='parse_item'),
    )   
    
    def parse_item(self, response):
        loader = ItemLoader(item=tongcheng(),selector=response)
        info = loader.nested_xpath('//div[@class="event-info"]')
        info.add_xpath('title','h1[@itemprop="summary"]/text()')
        info.add_xpath('time','div[@class="event-detail"]/ul[@class="calendar-strs"]/li/text()')
        info.add_xpath('address','div[@itemprop="location"]/span[@class="micro-address"]/span[@class="micro-address"]/text()')
        info.add_xpath('money','div[@class="event-detail"]/span[@itemprop="ticketAggregate"]/text()')
        info.add_xpath('intrest','div[@class="interest-attend pl"]/span[1]/text()')
        info.add_xpath('join','div[@class="interest-attend pl"]/span[3]/text()')
        
        yield loader.load_item()

4.查看数据库

#本地连接到mongo
sudo docker run -it mongo mongo --host 10.11.2.102
> show dbs
admin   0.000GB
config  0.000GB
douban  0.000GB
local   0.000GB
> use douban
switched to db douban
> show collections
movietop250
tongcheng
> db.tongcheng.find()
{ "_id" : ObjectId("5a6319a76e85dc5a777131d2"), "join" : [ "69 " ], "intrest" : [ "175 " ], "title" : [ "孟京辉戏剧作品《一个陌生女人的来信》深圳站" ], "money" : [ "263元" ], "address" : "深圳  深圳市少年宫剧场 深圳市福田区福中一路市少年宫" }
{ "_id" : ObjectId("5a6319a96e85dc5a777131d3"), "join" : [ "4 " ], "intrest" : [ "11 " ], "title" : [ "2018第五届城市戏剧节 诗·歌·舞变奏三幕剧《木心·人曲》-深圳" ], "money" : [ "93 - 281元" ], "address" : "深圳  南山文体中心剧院 小剧场 深圳市南山区南山大道南山文体中心" }
{ "_id" : ObjectId("5a6319ab6e85dc5a777131d4"), "join" : [ "7 " ], "intrest" : [ "16 " ], "title" : [ "2018第五届城市戏剧节·焦媛X王安忆X茅盾文学奖《长恨歌》-深圳" ], "money" : [ "93 - 469元" ], "address" : "深圳  南山文体中心剧院大剧院 南山大道与南头街交汇处南山文体中心" }
......

如果喜欢请关注我的公众号“木讷大叔爱运维”,与你分享运维路上的点滴。

你可能感兴趣的:(scrapy爬虫)