摘要:关于scrapy中使用[Feed exports],导出scrapy中的item

1 概要

  • 介绍数据输出到文件的一些细节;
  • 本节为文档类介绍,可做为今后使用时查阅;
  • 对Scrapy中官方Feed exports的学习;
  • 作为下一节Items学习的参考以及上一节从命令行保存数据到文件的补充。

在之前的章节中我们通过执行爬虫命令时添加可选参数来导出数据到文件:

scrapy runspider Quotes_Spider2.py -a category=life -o quotes.json
# scrapy runspider Quotes_Spider2.py -a category=life -o quotes.jsonlines
# scrapy runspider Quotes_Spider2.py -a category=life -o quotes.csv
scrapy runspider Quotes_Spider2.py -a category=life -o quotes.xml
# scrapy内置的总共有 csv,json,jsonlines,xml四种格式,最好别用json,因为会把所有的生成的item放在一个字典对象里,会占用大量内存。使用jsonlines格式时会一个item占用一行,推荐使用这个格式。

我们可以先看看我们保存的数据是什么样的:

{"text": "\u201cThere are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.\u201d", "author": "Albert Einstein"}
{"text": "\u201cIt is better to be hated for what you are than to be loved for what you are not.\u201d", "author": "Andr\u00e9 Gide"}
……

可以看到数据中包含了一些类似:\u201c、\u201d这样的不可读字符,其实这是保存数据时编码格式没有设置,导致使用类似\uXXXX 这样的序列进行保存。这里我们就要好好理理数据保存时的参数设置问题了。设置FEED_EXPORT_ENCODING就可以解决

2 Feed exports参数详解

  • FEED_URI (指向文件)
  • FEED_FORMAT(数据格式)
  • FEED_STORAGES(额外存储方式,即存到哪)
  • FEED_STORAGES_BASE(基础存储方式,即存到哪)
  • FEED_EXPORTERS(额外输出方式)
  • FEED_EXPORTERS_BASE(基础输出方式)
  • FEED_STORE_EMPTY(是否输出空数据,默认不输出)
  • FEED_EXPORT_ENCODING(文件编码格式)
  • FEED_EXPORT_FIELDS(指定数据输出项及顺序)
  • FEED_EXPORT_INDENT(添加数据缩,优雅输出)

下面开始说明(上面加粗参数为重点掌握,比较实用):

  1. FEED_URI
    指定文件存储的位置以及文件名,支持输出到:

    • 本地文件

      D://tmp/filename.csv
    • FTP

      ftp://user:pass@ftp.example.com/path/to/filename.csv
    • Amazon S3

      s3://aws_key:aws_secret@mybucket/path/to/export.csv
      # 也可以通过在设置中设置
      AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY 
      s3://mybucket/path/to/export.csv

      注意使用Feed exports输出到文件,如果FEED_URI的路径存在文件就会追加。下面是连续两次输入到csv文件时的惨状:

      连续两次输出csv.jpg

      此外FEED_URI还可以使用变量,例如时间日期等。详情参考:https://docs.scrapy.org/en/latest/topics/feed-exports.html#storage-uri-parameters

      例子:

      custom_settings = {
          'FEED_EXPORT_ENCODING': 'utf-8',
          'FEED_FORMAT': 'csv',
          'FEED_URI': '%(name)s.csv', # %(name)s 会被替换成爬虫的名字,还可以使用%(time)s,记录文件的时间
          'FEED_EXPORT_FIELDS': ['text','author']
      }
  2. FEED_FORMAT

    指定数据输出格式,支持的输出格式有(分别示例):

    custom_settings = {
        'FEED_FORMAT': 'json', #(注意'json'格式为小写)
        'FEED_EXPORT_ENCODING': 'utf-8',
        'FEED_URI': 'rule1.json'
    }
    • JSON

      实际上是JsonItemExporter,示例:

      [{"name": "Color TV", "price": "1200"},
      {"name": "DVD player", "price": "200"}]

      注意:如果数据量太多的话不建议使用json格式,因为它是把整个对象放入内存中,所以大数据量简易使用jsonlines 或者分块输出数据到文件。

    • JSON lines

      实际上是JsonLinesItemExporter,示例:

      {"name": "Color TV", "price": "1200"}
      {"name": "DVD player", "price": "200"}
    • CSV

      实际上为CsvItemExporter,示例:

      product,price
      Color TV,1200
      DVD player,200

      第一行为输出数据项的名称,下面每行为一组数据。

    • XML

      实际上为XmlItemExporter,示例:

          <?xml version="1.0" encoding="utf-8"?>
          <items>
       <item>
         <name>Color TV</name>
         <price>1200</price>
      </item>
       <item>
         <name>DVD player</name>
         <price>200</price>
      </item>
          </items>

      剩余的还有Pickle、Marshal暂时不做不了解。

  3. 存储方式

    • FEED_STORAGES

      默认为{},如果要进行设置则以URL方案名作为key,值为该存储类的路径。

    • FEED_STORAGES_BASE

      基础存储方式,默认的为:

      {
          '': 'scrapy.extensions.feedexport.FileFeedStorage',
          'file': 'scrapy.extensions.feedexport.FileFeedStorage',
          'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage',
          's3': 'scrapy.extensions.feedexport.S3FeedStorage',
          'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
      }
  4. 文件存储格式

    • FEED_EXPORTERS

      默认为{},定义扩展的文件存储方法,以格式为key,值为该格式类的路径。

    • FEED_EXPORTERS_BASE

      默认存储格式有:

      {
          'json': 'scrapy.exporters.JsonItemExporter',
          'jsonlines': 'scrapy.exporters.JsonLinesItemExporter',
          'jl': 'scrapy.exporters.JsonLinesItemExporter',
          'csv': 'scrapy.exporters.CsvItemExporter',
          'xml': 'scrapy.exporters.XmlItemExporter',
          'marshal': 'scrapy.exporters.MarshalItemExporter',
          'pickle': 'scrapy.exporters.PickleItemExporter',
      }
  5. 编码及数据输出

    • FEED_EXPORT_ENCODING

      存储文件编码,默认为None,一般设置为utf-8。

    • FEED_EXPORT_FIELDS

      当输出到csv格式的文件时候很重要。

      设定输出item的哪些字段,以及字段的顺序,例子:

      # 当 item有 "bar","baz","abc","foo"四个字段时,按照顺序输出item["foo"],item["bar"],item["baz"]到csv文件
      FEED_EXPORT_FIELDS = ["foo", "bar", "baz"]
    • FEED_EXPORT_INDENT

      默认值为0,单值为0或负数时将在新一行输出数据,设置大于0则为每一级的数据添加等量倍的空格缩进。

      'FEED_EXPORT_INDENT': 4
      # 设置缩进四格

3 使用范例

# -*- coding: utf-8 -*-
import scrapy


class QuotesItem(scrapy.Item):
    text = scrapy.Field()
    author = scrapy.Field()


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ['toscrape.com']
    custom_settings = {
        'FEED_FORMAT': 'jsonlines',
        'FEED_EXPORT_ENCODING': 'utf-8',
        'FEED_URI': 'quotes.jsonlines',
        'FEED_EXPORT_INDENT': 4,
    }
    #custom_settings = {
        #'FEED_EXPORT_ENCODING': 'utf-8',
        #'FEED_FORMAT': 'csv',
        #'FEED_URI': '%(name)s.csv',
        #'FEED_EXPORT_FIELDS': ['text','author']
    #}

    def __init__(self, category=None, *args, **kwargs):
        super(QuotesSpider, self).__init__(*args, **kwargs)
        self.start_urls = ['http://quotes.toscrape.com/tag/%s/' % category, ]

    def parse(self, response):
        quote_block = response.css('div.quote')
        for quote in quote_block:
            text = quote.css('span.text::text').extract_first()
            author = quote.xpath('span/small/text()').extract_first()
            # item = dict(text=text, author=author)
            item = QuotesItem()
            item['text'] = text
            item['author'] = author
            yield item

        next_page = response.css('li.next a::attr("href")').extract_first()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

在同目录下cmd输入:

(保存数据到爬虫中定义的文件中)

scrapy runspider Quotes_Spider.py -a category=life

(保存数据到命令行中指定的文件)

scrapy runspider Quotes_Spider.py -a category=life -o new_quotes.json
# 优先按照-o new_quotes.json 指定的文件格式,如果没有-o 指定文件格式,就按照文件中设置的FEED_FORMAT参数,如果没有FEED_FORMAT就默认使用jsonlines格式

4 参考

上面的文章大都抄自Feed exports - 数据导出配置详解,少部分自己补充,感谢前人铺路。

文章目录