如何在Python中以UTF-8编码将数据写入磁盘?
以下是一些Python代码...
html_data = urllib2.urlopen(some_url).read()
f = codecs.open(filename, 'w', encoding='utf-8')
f.write(html_data)
f.close()
... 有时会出现 UnicodeDecodeError
错误...
File "/.../lib/python2.6/codecs.py", line 686, in write
return self.writer.write(data)
File "/.../lib/python2.6/codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 5605: ordinal not in range(128)
我有几个问题:
- 我该如何确保我的
urllib2.urlopen(some_url).read()
调用总是返回UTF-8格式的数据? - 我的
codecs.open(...)
调用有没有什么问题,导致它无法以UTF-8编码将数据存储到磁盘上?
2 个回答
2
问题不在于 codecs.open
,而是你传给 .write
的字节串,它里面有 \xd0
这个代码,明显是用某种 ISO-8859-*
或相关编码格式编码的。
urllib2.urlopen 返回一个响应对象,除了像文件一样的行为外,还有一个额外的方法:
info()
— 返回页面的元信息,比如头部信息,以httplib.HTTPMessage
实例的形式呈现(可以参考 HTTP头部快速参考)
特别是对于文本类内容,Content-Type
头部应该有一个 charset
参数,指定它使用的编码,比如 Content-Type: text/html; charset=ISO-8859-4
。你需要解析并提取出 charset
,然后用它来把内容解码成Unicode(这样你的 codecs.open
打开的文件对象在 write
时总是接收Unicode参数,并且能正确地以 utf-8
格式写出内容)。
如果 charset
缺失,或者用它解码文本时出现错误(这说明 charset
可能不对),作为最后的救命稻草,你可以尝试使用 通用编码检测器,它使用一些启发式方法来进行检测(毕竟,网上很多页面的元数据都有严重错误,还有破损的HTML等等)。
1
- 据我所知,你是做不到这一点的。不过,你可以从头部信息或HTML中检测编码,然后重新编码。
- 我不太确定。我一直使用二进制模式来写文件,这样总是能正常工作。
示例:
data = urlopen(uri).read().decode(encoding)
f = open(file_name, 'wb')
f.write(data.encode('utf-8'))
f.close()