LoginSignup
8

More than 5 years have passed since last update.

Scrapyでログに出力されるItem内のUnicode文字列を読めるようにする

Last updated at Posted at 2016-01-13

2016-05-25追記:2016年5月にリリースされたScrapy 1.1はPython 3に対応したので、Python 3を使えばこのページの問題はそもそも発生しません。何もしなくてもItem内の日本語が読めます。ぜひPython 3とScrapy 1.1以降を使いましょう!

問題

Scrapyでは、SpiderからyieldしたItemがログに出力されますが、日本語など非ASCIIの文字列を含むフィールドはUnicodeエスケープされた状態で出力されるので、パット見で読めず、もどかしい思いをします。

(雑な) 対処法

Itemクラスに以下のような__unicode__()メソッドを定義すると読みやすくなります。

class MyItem(scrapy.Item):
    # ...
    def __unicode__(self):
        return repr(self).decode('unicode_escape')

実行例

以下のSpiderを実行します。これは12factor.netというWebサイトで翻訳のある言語の一覧を取得するSpiderです。

twelve_factor_spider.py
# coding: utf-8

import scrapy


class MyItem(scrapy.Item):
    languages = scrapy.Field()

    def __unicode__(self):
        return repr(self).decode('unicode_escape')


class TwelveFactorSpider(scrapy.Spider):
    name = '12factor'
    start_urls = ['http://12factor.net/']

    def parse(self, response):
        yield MyItem(languages=response.css('#locales a::text, #locales span::text').extract())

Before (__unicode__なし)

Unicode文字列がエスケープされています。

$ scrapy runspider twelve_factor_spider.py
2016-01-13 17:56:46 [scrapy] INFO: Scrapy 1.0.4 started (bot: scrapybot)
2016-01-13 17:56:46 [scrapy] INFO: Optional features available: ssl, http11
2016-01-13 17:56:46 [scrapy] INFO: Overridden settings: {}
...
2016-01-13 17:56:47 [scrapy] DEBUG: Scraped from <200 http://12factor.net/>
{'languages': [u'Espa\xf1ol (es)',
               u'Fran\xe7ais (fr)',
               u'Deutsch (de)',
               u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (ru)',
               u'English (en)',
               u'\u65e5\u672c\u8a9e (ja)',
               u'Italiano (it)',
               u'Brazilian Portuguese (pt_br)',
               u'\u7b80\u4f53\u4e2d\u6587 (zh_cn)',
               u'\ud55c\uad6d\uc5b4 (ko)']}
...

After (__unicode__あり)

Unicode文字列がエスケープされておらず、読みやすいです。

$ scrapy runspider twelve_factor_spider.py
2016-01-13 17:57:25 [scrapy] INFO: Scrapy 1.0.4 started (bot: scrapybot)
2016-01-13 17:57:25 [scrapy] INFO: Optional features available: ssl, http11
2016-01-13 17:57:25 [scrapy] INFO: Overridden settings: {}
...
2016-01-13 17:57:25 [scrapy] DEBUG: Scraped from <200 http://12factor.net/>
{'languages': [u'Español (es)',
               u'Français (fr)',
               u'Deutsch (de)',
               u'Русский (ru)',
               u'English (en)',
               u'日本語 (ja)',
               u'Italiano (it)',
               u'Brazilian Portuguese (pt_br)',
               u'简体中文 (zh_cn)',
               u'한국어 (ko)']}
...

ちなみに、あくまでログへの出力内容を変えるだけで、-o/--outputでファイルに保存した場合の内容などには影響しません。

注意点

decode('unicode_escape')を通すと、空白文字 (\n, \r, \t, \u3000など) や制御文字のUnicodeエスケープもアンエスケープされてしまいます。このため、空白文字やバイト列が含まれるItemでは逆に中身がわかりづらくなる可能性が大いにあります。使い方には気をつけてください。

ScrapyがPython 3に対応したらこんな面倒なことしなくて良くなるはずです。

おまけ:もう少し真面目に表示可能な文字のみをアンエスケープする関数を書いてみました。 → http://ideone.com/J77aaN

まとめ

  • Itemの__unicode__()を定義するとログへの出力内容を変更できる。
  • Python 3が便利。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8