Item以及Itempipeline的使用

在上一篇博客中,最后的结果是通过yield一个dict,但dict缺少数据结构,没法保证每一处返回都能返回相同的字段。因此scrapy提供了Item类,用来声明爬取数据的数据结构,该类提供了dict-like的接口,因此可以很方便的使用。

Item

每一个自定义的数据结构涉及到2个类:

  1. scrapy.Item:基类;
  2. scrapy.Field:用来描述自定义数据包含哪些字段信息,也仅此而已,并没有实际的作用。

比如,按照上一个博客的例子,爬取http://quotes.toscrape.com/的数据结构可以定义如下:

import scrapy

class QuoteItem(scrapy.Item):
    author = scrapy.Field()
    quote = scrapy.Field()
    tags = scrapy.Field()

这种定义方式跟Django.model很像。
By the way, scraoy.Field()可以带一个serializer参数,用于Item Expoter导出数据时使用,后面会提到。

Item的常见用法

Item提供dict-like的API接口,因此其大部分用法与dict一样。

class BookItem(scrapy.Item):
    name = scrapy.Field()
    author = scrapy.Field()
    price = scrapy.Field()

#创建Item对象
>>> book = BookItem(name = 'Scrapy book',author = 'Tom', price = 10)
>>> book2 = BookItem({'name' : 'Python book', 'author' : 'John'}) #从字典中生成Item对象
#访问键值
>>> book['name']
'Scrapy book'
>>> 'name' in book
True
>>> book['name']
'Scrapy book'
>>> 'name' in book
True
>>> book2 = BookItem(name = 'Python book', author = 'John')
>>> 'price' in book2        # price是否已经设定值
False
>>> 'price' in book2.fields     # price是否是声明的field
True
#设定值
>>> book2['price'] = 12
>>> book2
{'author': 'John', 'name': 'Python book', 'price': 12}
#访问已经被赋值的键
>>> book2.keys()
dict_keys(['name', 'author', 'price'])
>>> book2.items()
ItemsView({'author': 'John', 'name': 'Python book', 'price': 12})
>>> book1_copy = book.copy()
>>> book1_copy
{'author': 'Tom', 'name': 'Scrapy book', 'price': 10}
在spider中使用Item

上一篇博客的代码更改后如下:

# -*- coding: utf-8 -*-
import scrapy
from ..items import QuoteItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

#    def start_requests(self):
 #       url = "http://quotes.toscrape.com/"
  #      yield scrapy.Request(url, callback = self.parse)

    def parse(self, response):
        quote_selector_list = response.css('body > div > div:nth-child(2) > div.col-md-8 div.quote')

        for quote_selector in quote_selector_list:
            quote = quote_selector.css('span.text::text').extract_first()
            author = quote_selector.css('span small.author::text').extract_first()
            tags = quote_selector.css('div.tags a.tag::text').extract()

            yield QuoteItem({'quote':quote, 'author':author, 'tags':tags})

        next_page_url = response.css('ul.pager li.next a::attr(href)').extract_first()
        if next_page_url:
            next_page_url = response.urljoin(next_page_url)

            yield scrapy.Request(next_page_url, callback = self.parse)

ItemPipeline

当item从spider爬取获得之后,会被送到ItemPipeline,在scrapy,ItemPipeline是处理数据的组件,它们接收Item参数并再其之上进行处理。

ItemPipeline的典型用法:

  1. 清理脏数据;
  2. 验证数据的有效性;
  3. 去重
  4. 保存item到db,即持久化存储
如何实现一个ItemPipeline

ItemPipeline的定义放置于pielines.py中,实现一个ItemPipeline无需继承指定基类,只需要实现以下方法:
process_item(self, item, spider):必须实现的方法,该方法每个item被spideryield时都会调用。该方法如果返回一个Dict或Item,那么返回的数据将会传递给下一个PipeLine(如果有的话);抛出一个DropItem异常,那么该Item既不会被继续处理,也不会被导出。通常,在我们在检测到无效数据或想要过滤掉某些数据的时候使用;

其他方法可以实现,但非必须:
open_spider(self, spider):在spider打开时(数据爬取前)调用该函数,该函数通常用于数据爬取前的某些初始化工作,如打开数据库连接
close_spider(self, spider):在spider关闭时(数据爬取后)调用该函数,该函数通常用于数据爬取前的清理工作,如关闭数据库连接
from_crawler(cls, crawler):类方法,其返回一个ItemPipeline对象,如果定义了该方法,那么scrapy会通过该方法创建ItemPipeline对象;通常,在该方法中通过crawler.settings获取项目的配置文件,根据配置生成对象。

下面我们实现一个保存Quote到本地文件的ItemPipeline,来看看怎么实现一个自定义的ItemPipeline;

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.exceptions import NotConfigured
import json
import scrapy

class SaveFilePipeline(object):

    def __init__(self, file_name = None):
        if file_name is None:
            raise NotConfigured
        self.file_name = file_name
        self.fp = None

    def open_spider(self, spider):
        self.fp = open(self.file_name, 'w')

    def close_spider(self, spider):
        self.fp.close()

    def process_item(self, item, spider):
        json_item = json.dumps(dict(item))
        self.fp.write(json_item + "\n")

    @classmethod
    def from_crawler(cls, crawler):
        file_name = crawler.settings.get('FILE_NAME')
        # file_name = scrapy.conf.settings['FILE_NAME'] #这种方式也可以获取到配置
        return cls(file_name)
启用ItemPipeline

settings.py中添加以下内容:

ITEM_PIPELINES = {
    'newproject.pipelines.SaveFilePipeline': 300,
}
FILE_NAME = 'save_result.json'

其中,ITEM_PIPELINES是一个字典文件,键为要打开的ItemPipeline类,值为优先级,ItemPipeline是按照优先级来调用的,值越小,优先级越高。

总结

本篇介绍了如何设定爬取的数据结构以及利用ItemPipeline来实现对数据的保存,了解ItemPipeline的原理。下一节将学习下内置的ItemPipeline,FilesPipelineImagesPipeline

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • 背景 部门(东方IC、图虫)业务驱动,需要搜集大量图片资源,做数据分析,以及正版图片维权。前期主要用node做爬虫...
    字节跳动技术团队阅读 7,662评论 1 67
  • scrapy学习笔记(有示例版) 我的博客 scrapy学习笔记1.使用scrapy1.1创建工程1.2创建爬虫模...
    陈思煜阅读 12,692评论 4 46
  • 这些组件最重要的思路就是拦截,即过滤 item管道:作用一:入库 校验:一是可以在管道,但主要是在item定义字段...
    怂恿的大脑阅读 1,053评论 0 0
  • 前言 scrapy是python界出名的一个爬虫框架。Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应...
    以后的以后_hzh阅读 2,262评论 0 14
  • (一) 看到这次作业的关键词“情商”,脑海中立刻浮现了自己干的那些个低情商事件。光是想起都让我尴尬得捶胸顿足,...
    信义妈咪阅读 218评论 0 0