【问题标题】:How can I get an output in UTF-8 encoded unicode from Scrapy?如何从 Scrapy 获得 UTF-8 编码的 unicode 输出?
【发布时间】:2016-09-19 21:27:59
【问题描述】:

忍受我。我正在写每一个细节,因为工具链的很多部分都不能优雅地处理 Unicode,而且还不清楚是什么失败了。

前奏曲

我们首先设置并使用最近的 Scrapy。

source ~/.scrapy_1.1.2/bin/activate

由于终端默认是ascii,不是unicode,所以我们设置:

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

另外由于默认情况下 Python 使用 ascii,我们修改编码:

export PYTHONIOENCODING="utf_8"

现在我们准备开始一个 Scrapy 项目。

scrapy startproject myproject
cd myproject
scrapy genspider dorf PLACEHOLDER

我们被告知我们现在有一个蜘蛛。

Created spider 'dorf' using template 'basic' in module:
  myproject.spiders.dorf

我们将myproject/items.py修改为:

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

class MyprojectItem(scrapy.Item):
    title = scrapy.Field()

尝试 1

现在我们写spider,依赖urllib.unquote

# -*- coding: utf-8 -*-
import scrapy
import urllib
from myproject.items import MyprojectItem

class DorfSpider(scrapy.Spider):
    name = "dorf"
    allowed_domains = [u'http://en.sistercity.info/']
    start_urls = (
        u'http://en.sistercity.info/sister-cities/Düsseldorf.html',
    )

    def parse(self, response):
        item = MyprojectItem()
        item['title'] = urllib.unquote(
            response.xpath('//title').extract_first().encode('ascii')
        ).decode('utf8')
        return item

最后我们使用custom item exporter(从 2011 年 10 月开始)

# -*- coding: utf-8 -*-
import json
from scrapy.exporters import BaseItemExporter

class UnicodeJsonLinesItemExporter(BaseItemExporter):

    def __init__(self, file, **kwargs):
        self._configure(kwargs)
        self.file = file
        self.encoder = json.JSONEncoder(ensure_ascii=False, **kwargs)

    def export_item(self, item):
        itemdict = dict(self._get_serialized_fields(item))
        self.file.write(self.encoder.encode(itemdict) + '\n')

并添加

FEED_EXPORTERS = {
    'json': 'myproject.exporters.UnicodeJsonLinesItemExporter',
}

myproject/settings.py

现在我们运行

~/myproject> scrapy crawl dorf -o dorf.json -t json

我们得到

UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 25: ordinal not in range(128)

尝试 2

另一种解决方案(Scrapy 1.2 的候选解决方案?)是使用蜘蛛

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

class DorfSpider(scrapy.Spider):
    name = "dorf"
    allowed_domains = [u'http://en.sistercity.info/']
    start_urls = (
        u'http://en.sistercity.info/sister-cities/Düsseldorf.html',
    )

    def parse(self, response):
        item = MyprojectItem()
        item['title'] = response.xpath('//title')[0].extract()
        return item

还有custom item exporter

# -*- coding: utf-8 -*-
from scrapy.exporters import JsonItemExporter

class Utf8JsonItemExporter(JsonItemExporter):

    def __init__(self, file, **kwargs):
        super(Utf8JsonItemExporter, self).__init__(
            file, ensure_ascii=False, **kwargs)

FEED_EXPORTERS = {
    'json': 'myproject.exporters.Utf8JsonItemExporter',
}

myproject/settings.py.

我们得到以下 JSON 文件。

[
{"title": "<title>Sister cities of D\u00fcsseldorf \u2014 sistercity.info</title>"}
]

Unicode 不是 UTF-8 编码的。虽然对于几个字符来说这是一个微不足道的问题,但如果整个输出都是外语,它就会成为一个严重的问题。

如何获得 UTF-8 unicode 格式的输出?

【问题讨论】:

    标签: scrapy


    【解决方案1】:

    在 Scrapy 1.2+ 中有一个 FEED_EXPORT_ENCODING 选项。当 FEED_EXPORT_ENCODING = "utf-8" 转义 JSON 输出中的非 ascii 符号被关闭时。

    【讨论】:

    • 如何在 scrapy spider 中添加 FEED_EXPORT_ENCODING
    • 放入settings.py文件
    【解决方案2】:

    请在您的 尝试 1 上尝试一下,并告诉我它是否有效(我已经在没有设置所有这些环境变量的情况下对其进行了测试)

    def to_write(uni_str):
        return urllib.unquote(uni_str.encode('utf8')).decode('utf8')
    
    
    class CitiesSpider(scrapy.Spider):
        name = "cities"
        allowed_domains = ["sitercity.info"]
        start_urls = (
            'http://en.sistercity.info/sister-cities/Düsseldorf.html',
        )
    
        def parse(self, response):
            for i in range(2):
                item = SimpleItem()
                item['title'] = to_write(response.xpath('//title').extract_first())
                item['url'] = to_write(response.url)
                yield item
    

    range(2) 用于测试 json 导出器,以获取 dicts 列表,您可以这样做:

    # -*- coding: utf-8 -*-
    from scrapy.contrib.exporter import JsonItemExporter
    from scrapy.utils.serialize import ScrapyJSONEncoder
    
    class UnicodeJsonLinesItemExporter(JsonItemExporter):
        def __init__(self, file, **kwargs):
            self._configure(kwargs, dont_fail=True)
            self.file = file
            self.encoder = ScrapyJSONEncoder(ensure_ascii=False, **kwargs)
            self.first_item = True
    

    【讨论】:

      猜你喜欢
      • 2016-08-24
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 2012-10-11
      • 2013-09-11
      相关资源
      最近更新 更多