【问题标题】:Scrapy convert from unicode to utf-8Scrapy 从 unicode 转换为 utf-8
【发布时间】:2016-08-24 12:01:03
【问题描述】:

我编写了一个简单的脚本来从某个站点提取数据。脚本按预期工作,但我对输出格式不满意
这是我的代码

class ArticleSpider(Spider):
    name = "article"
    allowed_domains = ["example.com"]
    start_urls = (
        "http://example.com/tag/1/page/1"
    )

    def parse(self, response):
        next_selector = response.xpath('//a[@class="next"]/@href')
        url = next_selector[1].extract()
        # url is like "tag/1/page/2"
        yield Request(urlparse.urljoin("http://example.com", url))

        item_selector = response.xpath('//h3/a/@href')
        for url in item_selector.extract():
            yield Request(urlparse.urljoin("http://example.com", url),
                      callback=self.parse_article)

    def parse_article(self, response):
        item = ItemLoader(item=Article(), response=response)
        # here i extract title of every article
        item.add_xpath('title', '//h1[@class="title"]/text()')
        return item.load_item()

我对输出不满意,例如:

[scrapy] 调试:从 http://example.com/tag/1/article_name> 抓取 {'标题': [u'\xa0"\u0412\u041e\u041e\u0411\u0429\u0415-\u0422\u041e \u0421\u0412\u041e\u0411\u041e\u0414\u0410\u0417\u0410\u041a\u001 \u041d\u0427\u0418\u0412\u0410\u0415\u0422\u0421\u042f"']}

我认为我需要使用自定义 ItemLoader 类,但我不知道如何使用。需要你的帮助。

TL;DR 我需要将由 Scrapy 抓取的文本从 unicode 转换为 utf-8

【问题讨论】:

  • 这只是拼凑打印 unicode 字符(西里尔文)。你如何保存你的刮掉的物品?一旦你保存了它,你将如何处理它? Unicode 问题通常取决于您用于查看 Unicode 数据的软件。
  • 稍后我将把它保存到 postgresql 数据库(使用管道),但现在我以scrapy crawl article -o file.json 运行它,我在 json 文件中看到相同的输出。不得不承认我是 Scrapy 的新手,所以我感谢任何批评者)

标签: python-2.7 unicode scrapy


【解决方案1】:

正如您在下面看到的,这不是 Scrapy 问题,而是 Python 本身的问题。它也可以被称为一个问题:)

$ scrapy shell http://censor.net.ua/resonance/267150/voobscheto_svoboda_zakanchivaetsya

In [7]: print response.xpath('//h1/text()').extract_first()
 "ВООБЩЕ-ТО СВОБОДА ЗАКАНЧИВАЕТСЯ"

In [8]: response.xpath('//h1/text()').extract_first()
Out[8]: u'\xa0"\u0412\u041e\u041e\u0411\u0429\u0415-\u0422\u041e \u0421\u0412\u041e\u0411\u041e\u0414\u0410 \u0417\u0410\u041a\u0410\u041d\u0427\u0418\u0412\u0410\u0415\u0422\u0421\u042f"'

您看到的是同一事物的两种不同表示形式 - 一个 unicode 字符串。

我的建议是使用-L INFO 运行爬网或将LOG_LEVEL='INFO' 添加到您的settings.py,以便不在控制台中显示此输出。

一件烦人的事情是,当您保存为 JSON 时,您会得到转义的 unicode JSON,例如

$ scrapy crawl example -L INFO -o a.jl

给你:

$ cat a.jl
{"title": "\u00a0\"\u0412\u041e\u041e\u0411\u0429\u0415-\u0422\u041e \u0421\u0412\u041e\u0411\u041e\u0414\u0410 \u0417\u0410\u041a\u0410\u041d\u0427\u0418\u0412\u0410\u0415\u0422\u0421\u042f\""}

这是正确的,但它需要更多空间,并且大多数应用程序同样可以很好地处理非转义 JSON。

settings.py 中添加几行可以改变这种行为:

from scrapy.exporters import JsonLinesItemExporter
class MyJsonLinesItemExporter(JsonLinesItemExporter):
    def __init__(self, file, **kwargs):
        super(MyJsonLinesItemExporter, self).__init__(file, ensure_ascii=False, **kwargs)

FEED_EXPORTERS = {
    'jsonlines': 'myproject.settings.MyJsonLinesItemExporter',
    'jl': 'myproject.settings.MyJsonLinesItemExporter',
}

基本上我们所做的只是为默认的 JSON 项目导出器设置 ensure_ascii=False。这可以防止逃跑。我希望有一种更简单的方法可以将参数传递给导出器,但我看不到任何东西,因为它们是用 here 周围的默认参数初始化的。无论如何,现在你的 JSON 文件有:

$ cat a.jl
{"title": " \"ВООБЩЕ-ТО СВОБОДА ЗАКАНЧИВАЕТСЯ\""}

更好看,同样有效且更紧凑。

【讨论】:

    【解决方案2】:

    有 2 个独立的问题会影响 unicode 字符串的显示。

    1. 如果你返回一个字符串列表,输出文件会有一些问题,因为它默认使用 ascii 编解码器来序列化列表元素。您可以按以下方式解决,但按照@neverlastn 的建议使用extract_first() 更合适

      class Article(Item):
          title = Field(serializer=lambda x: u', '.join(x))
      
    2. repr() 方法的默认实现会将 unicode 字符串序列化为其转义版本\uxxxx。您可以通过在项目类中覆盖此方法来更改此行为

      class Article(Item):
          def __repr__(self):
              data = self.copy()
              for k in data.keys():
                  if type(data[k]) is unicode:
                      data[k] = data[k].encode('utf-8')
              return super.__repr__(data)
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 2015-05-04
      • 1970-01-01
      • 2011-04-18
      • 2015-10-08
      • 2023-03-12
      相关资源
      最近更新 更多