忍受我。我正在写每一个细节,因为工具链的很多部分都不能很好地处理 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 的输出?

最佳答案

请在你的 Attempt 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 导出器,要获取您可以执行此操作的 dict 列表:
# -*- 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

关于scrapy - 如何从Scrapy获得UTF-8编码的Unicode输出?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39582409/

10-16 05:42