ScrapyのMailSenderでUnicodeDecodeError
Scrapy のバージョンを上げた影響か、MailSender の send で UnicodeDecodeError が出るようになってしまった。
Traceback (most recent call last): File "/Users/***/.pyenv/versions/2.7.17/envs/scrapy1.8/lib/python2.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks current.result = callback(current.result, *args, **kw) File "/Users/***/scm/git/primon/primon/pipelines.py", line 42, in close_spider self._send_mail(message) File "/Users/***/scm/git/primon/primon/pipelines.py", line 22, in _send_mail self.mailer.send(to=["***"], subject="Test", body=message.encode('shift_jis')) File "/Users/***/.pyenv/versions/2.7.17/envs/scrapy1.8/lib/python2.7/site-packages/scrapy/mail.py", line 101, in send dfd = self._sendmail(rcpts, msg.as_string().encode(charset or 'utf-8')) UnicodeDecodeError: 'ascii' codec can't decode byte 0x8d in position 179: ordinal not in range(128)
元々は Scrapy 1.0.5 だったのを 1.8.0 に上げた。同時に Python も 2.7.9 から 2.7.17 に上げている。
Scrapy の History を見ると、1.1.0 で「Sending non-ASCII emails」に関する修正が入っているのでこれが怪しい。
https://docs.scrapy.org/en/latest/news.html#additional-new-features-and-enhancements
しかしこの対応の issue を見る限りでは、文字コード指定してメール送れるようになった感じがするのだが。下記のように修正してもダメ。
// self.mailer.send(to=["***"], subject="Test", body=message.encode('shift_jis'))
self.mailer.send(to=["***"], subject="Test", body=message, charset='shift_jis') // NG
self.mailer.send(to=["***"], subject="Test", body=message, charset='utf-8') // NG
Python 2.7 を使っていることも影響しているのか??と思い調べてみると、ビンゴ。
https://github.com/scrapy/scrapy/issues/3710
この issue は open のまま。ただ、sys.setdefaultencoding すればいけそう。
/Users/****/.pyenv/versions/2.7.17/envs/scrapy1.8/lib/python2.7/site-packages に sitecustomize.py を下記の内容で作成。
import sys
sys.setdefaultencoding('utf-8')
ついにエラーなくなった!と思ったの束の間。メールが文字化けしていた…。
メールをテキストエディタで開くと文字化けせずにUTF-8で表示された。Content-Transfer-Encoding: base64 になっているが、base64でエンコードされていないためメーラーでは文字化けしている気がする。
ふと思い立ち、MailSender の send で charset=’iso-2022-jp’ を指定すれば base64 でエンコードする必要がなくなるのでいけるのでは?と思ったらビンゴ!ようやく文字化けせずに送れるようになった。
mailer = MailSender.from_settings(spider.settings)
message = u'日本語の内容'
mailer.send(to=["test@example.com"], subject="test", body=message, charset='iso-2022-jp')
という感じ。
ちなみにメールは送れるようになったが、最後に下記のエラーが残っている。
exceptions.AttributeError: 'NoneType' object has no attribute 'bio_read'
これは close_spider の中でメールを送っているためのようで、send の戻り値を close_spider で return すれば解消された。
def close_spider(self, spider):
mailer = MailSender.from_settings(spider.settings)
message = u'日本語の内容'
return mailer.send(to=["test@example.com"], subject="test", body=message, charset='iso-2022-jp')
https://github.com/scrapy/scrapy/issues/3478#issuecomment-498058336
ただこの対応も完璧じゃないようで、時々エラーが出る。タイミングの問題なのだろうか。
コメントを残す