觉得《码农周刊》挺有意思的,想写个脚本把内容抓下来。
import urllib
import httplib
def get_html_content(url):
response = urllib.urlopen(url)
html = response.read()
print type(html)
return html
if __name__ == '__main__':
url = 'http://weekly.manong.io/issues/58'
html = get_html_content(url)
print html.decode('utf-8')
结果报错误
<type 'str'>
Traceback (most recent call last):
File "E:\src\infra.py", line 32, in <module>
print html.decode('utf-8')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 44: ordinal not in range(128)
[Finished in 1.6s]
我真的查了许多,像是http://nedbatchelder.com/text/unipain.html 通读一遍,结果怎么都搞不定,求解。
1
ihciah 2015-01-17 17:23:12 +08:00 via Android
我这里正常…不过是用的urllib2.urlopen
|
3
liqiu 2015-01-17 17:34:29 +08:00
|
4
aaaa007cn 2015-01-17 19:16:11 +08:00
如果只考虑这个场合
print html.decode('utf-8').encode('gb18030') |
5
Delbert 2015-01-17 19:25:26 +08:00
.decode("utf-8", "ignore")
这样试试呢? |
6
9hills 2015-01-17 19:39:44 +08:00 2
程序没问题,出问题的是你的环境。直接print Unicode的话,如果在Linux or OSX的默认UTF-8环境,是没有问题的。但是在Windows上就呵呵(4楼是windows上的解决办法)
两点: 1. 不要学3楼的reload sys哈,不是解决问题的办法。你reload前你懂它到底做了什么么,不懂的话就别写自己不懂的代码,如果你懂的话,那也不需要这个reload的办法 2. 直接输出Unicode是不好的行为,输出的时候应该encode下的,环境是utf-8就encode成utf-8,环境是gbk就encode成gbk |
7
9hills 2015-01-17 19:42:12 +08:00 1
处理编码的主要一个原则,就是让程序的默认隐式转换变成显式的。
比如所有中文都写成 u"中文" 这样的Unicode,而不是让它的编码随文件编码变化而变化 比如输出的时候显式转换编码,而不是依赖系统的编码转换。。 |
9
lerry 2015-01-17 21:39:23 +08:00
|
10
lyhapple 2015-01-17 21:40:09 +08:00
用python的requests库试试.
pip install requests |
12
icedx 2015-01-17 21:47:12 +08:00
print html.decode('utf8').encode('gbk','backslashreplace')
因为楼主用的是Windows |
13
endoffight 2015-01-17 22:12:02 +08:00 via Android
建议安装chardect模块确定编码后再决定转不转码
|
14
EPr2hh6LADQWqRVH 2015-01-17 22:15:34 +08:00
不要assume数据的编码,拿到手保持Bytes的形态,然后自己尝试解码
|
15
Sylv 2015-01-18 13:44:25 +08:00
你这个问题其实是和 Sublime Text 有关的,我刚好在总结一篇相关的 Unicode 编码问题的分析,写好会分享出来。
而针对你这个问题的短答案是: 你在最后将 str 类型的 html decode 为了 unicode 类型的字符串,然后想要打印 print 出这个 unicode 字符串时,Python 又需要将其转换为 str 后才能输出。在正常情况下,Python 能判断出正确的输出编码来进行转换而并不会出错,这就是前面有人说在他们的环境能正常运行的原因。而你会出现 UnicodeEncodeError 的原因是,因为某种原因,在 Sublime Text 里运行的 Python 不能判断出这个正确的输出编码,于是它就使用了它的默认编码 ascii 来进行转换,于是就出错了。 在 Sublime Text 里想要 print 出一个 unicode 类型的字符串,正确的方法是显式地进行 encode('utf-8') 后再 print。而为什么我说要用的是 utf-8 编码,而不是前面说的 gbk 等编码呢?因为默认配置下的 Sublime Text 所接收的默认输出编码是 utf-8,你用其它编码会出现 [Decode error - output not utf-8] 错误。而如果你用 cmd 运行的话,可能就要用 gbk 等编码了。 而针对这种情况下的你这段代码,其实最后没必要 .decode('utf-8') 一遍,因为 html 原本就是 utf-8 编码的 str 了,可以直接 print html 了,否则你需要多此一举 print html.decode('utf-8').encode('uff-8')。 关于这个问题的详细解释和其它解决方法,请等我的长答案。 |
16
KyL OP @Sylv 我确实是在用Sublime Text调试Py2的时候遇到这个问题的。str只可以hold1Byte字符的串,怎么会有所谓utf-8编码的str呢。期待着你的长答案。
|
17
Sylv 2015-01-18 15:16:23 +08:00
@KyL str 存储的是 bytes 字节序列,不是只有 1 byte。它当然就有不同的编码,见下例,同样表示的是 “中文” 的 str 字符串,在不同编码下,其内部存储的字节序列是不同的:
>>> text = u'中文' >>> text.encode('utf-8') '\xe4\xb8\xad\xe6\x96\x87' >>> text.encode('gbk') '\xd6\xd0\xce\xc4' |
18
KyL OP @Sylv py2中有两种字符串类型,str和unicode。 text = u'中文' 是Unicode类型,不是str类型。str只能储存ascii类型的字符吧。
|
19
Sylv 2015-01-19 04:10:37 +08:00
@KyL 你概念理解有错
首先,Python 2 unicode 和 str 转换方法要弄清楚: str.decode('utf-8') -> unicode unicode.encode('utf-8') -> str 我上例中 text.encode('utf-8') 后已经是 str 了。 然后你理解错了,str 并不是只能存储 ascii 类型的字符。str 存储的是一个一个的字节数据,也可以说就是一个一个字节的数字。然后这些数字代表的是什么字符,要看你用什么编码去解读它。 例如现在一个 str 用一个字节存储了数字 97,那么你用 ascii 编码去解读它,那么这个 str 就是 'a'。 然后现在有一个 str 用三个字节存储了三个数字:235、184 和 173,连起来用 16 进制表示也就是 '\xe4\xb8\xad'。然后你也可以用 ascii 编码去解读它,查 ascii 表后可以发现这三个数字都不在基本的 128 位 ascii 里,而是在扩展表里,都是一些很奇怪的字符,可见这个 str 用 ascii 编码去解读它对我们来说没有意义。 但是我们换一个编码 'utf-8' 去解读它,这个 str 就变得有意义了,在 utf-8 编码里是用三个字节来存储一个汉字字符的,而不是像 ascii 编码一个字节就对应了一个字符。那么 235、184 和 173 这三个字节的数字在 utf-8 编码里对应的就是一个汉字字符的 “中”。你可以用以下方法验证: >>> char = u'中' >>> print type(char) <type 'unicode'> >>> char = char.encode('utf-8') >>> print type(char) <type 'str'> >>> print repr(char) # repr 方法可以将对象在 Python 内部的存储形式表现出来 '\xe4\xb8\xad' >>> print char 中 >>> print '\xe4\xb8\xad' 中 在 print 这个 str 类型的 char 时,Python 只是把那三个数字直接发送给了用来显示的控制台(console)。console 就是用来输出的地方,例如 Sublime Text 的运行结果窗口,还有 Windows 下的 cmd。 然后决定用什么编码去解读它,是由 console 来决定的。在 Sublime Text 下这个编码默认是 utf-8,它用 utf-8 去解读 235、184 和 173 这三个数字,发现是 “中” 字,那么它就会去字库里找出 “中” 字这个字形给我们显示出来,因此我们就能看到 “中” 了。 而在 cmd 下,它用来解读的编码就不是 utf-8 了,而是 gbk 之类的。那它用 gbk 编码去解读这三个数字,可能它能找到另一些对应的字符,也有可能它完全找不到对应的字符,这时就产生了显示出乱码的情况。如果你想让它显示出 “中”,那么你就要让 Python 发送给它 gbk 编码下 “中” 所对应的数字,也就是 214 和 208,写成 16进制就是 '\xd6\xd0'。 因此你在 print 的时候想要显示正常,要看你现在的输出 console 用的是什么编码,然后就要发送给它对应编码的 str。 我最开始所说 html 是 utf-8 编码的 str,意思就是 html 里存储的字节序列,就是你想要的网页源码文字在 utf-8 编码下对应的一个个的数字,所以我们可以说它是 utf-8 编码的 str,因为它在 ascii 和 gbk 等编码下是没有意义的。Python 将它送给 Sublime Text, Sublime Text 也用 utf-8 编码去解读它,最后就能显示出你能看得懂的网页源代码文字。 |
22
KyL OP @aaaa007cn 为什么在cmd中使用gb18030是正确的呢。sys.stdout.encoding得到的结果是cp936,可是html.decode('utf-8').encode('cp936')报错。
|
23
aaaa007cn 2015-02-01 18:47:21 +08:00
https://en.wikipedia.org/wiki/Code_page_936
https://en.wikipedia.org/wiki/GB_2312 https://en.wikipedia.org/wiki/GBK https://en.wikipedia.org/wiki/GB_18030 https://docs.python.org/2/library/codecs.html gb2312 收录 6763 个汉字 gbk 收录 20900 多汉字 gb18030 收录 70244 个汉字 python2 中 cp936 是 gbk 的别名 所以有时候 encode("cp936") 会出错 一般在中文 windows 的 cmd 中用 python2 输出中文都是 encode("gb18030") 的 |