python编码错误和中文的乱码问题,研究了整整两天,查阅了很多资料,也走了一些弯路,我把经验写下,让新手少走点弯路,本人技术较渣,有什么疏漏错误望大牛指正!
以下str表示文本字符,byte表示字节流。
py3只有str和byte,str只能encode,byte只能decode,不需要显式地通过unicode这个“中间人”…py2就必须会经过unicode这个”中间人”….
主要讲一下py2的编码方式,因为现在用py2来造轮子的人挺多的,很多新手会因为中文乱码的问题很头疼,尤其是抓去网页的数据的时候….
首先必须要知道输入的str会被系统以什么方式去编码,是utf-8还是gbk还是其他的编码方式,用chartdet包可以来判断。chardet包在win下要自行安装!
import chardet
s=’大家好,我叫卓少!’
chardet.detect(s)
{'confidence': 0.99, 'encoding': 'GB2312'}
判断出这个输入将会以GB2312去编码,用print 输出也是GB2312编码的中文。一般这种是在windows下py环境里的,GBK系列的编码方式就是windows下默认的,Linux下的编码方式一般是utf-8,输出也一样(这里讲的都是中文的编码方式,英文的默认是ascii…中文用ascii也编码不了…才128个字符...)
上面这种输入情况是自己敲键盘打进去的,还有一种输入情况是你在网页上爬取的str,这种你就要看看这个网站是什么编码方式了,打开网页的源代码,上面可以看到chardet=’xxx’…一般现在基本都用的是utf-8编码(utf-8是unicode中综合性最好的编码方式了,而且是包含了全世界各种语言字符的集合,大而全)。知道了网页的编码之后,我们分别来尝试一下在可能会遇到的乱码或者编码错误的问题。
比如说我们来爬取一个网页,就拿鱼c的首页来试水。先看看其前端的源码,是utf-8的。写个最简单的爬取脚本。
import urllib2
url=’http://www.fishc.com’
res=urllib2.urlopen(url)
res=res.read() #把抓取的网页的utf-8数据流读进去。
res=res.decode(‘utf-8’) #由于数据流是utf-8,因此要把utf-8解码成Unicode
#这里可以查看一下res的数据,可以发现有中文的地方就有/uxxx/uxxx啥的,这就是unicode字符…
#这也是编码成其他形式的第一步,必须要先解码变成unicode字符。再encode…
print res #print 这个命令有自动转换成系统的”习惯编码”(例如上面说的win下是GBK系列,linux下是utf-8系列),GBK编码方式包含了所有中文,不会有乱码。
我们来试试另一种种方法:(接着上面res=res.read()往后)
res =res.encode(‘gbk’) #直接在utf-8的时候编码成gbk,由于win和linux系统默认编码方式都是ascii ,肯定是显示ascii cann’t decode…
怎么回事?utf-8编码成gbk关ascii解码啥事?
其实是这样的,因为如果res这个字节流编码不是unicode就直接encode的话python会自动用默认的编码方式来decode成为unicode,刚才说过,py2编码(encode)必须要先把原来的格式解码(decode)成unicode,要经过这个”中间人”才能去编码成其他格式…然而网页的编码方式是utf-8,用ascii方式来decode怎么可能不报错呢…所以,我在网上找到了修改py默认编码方式的方法(一般改成utf-8比较好):
在linux下:
python安装目录:/etc/python2.x/sitecustomize.py
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
try:
import apport_python_hook
except ImportError:
pass
else:
apport_python_hook.install()
如果在windows下:
可以在Python安装目录下的Lib/site-packages目录中,新建一个sitecustomize.py文件(也可以建在其它地方,然后手工导入,建在这里,每次启动Python的时候设置将自动生效),内容如下:
import sys
sys.setdefaultencoding('utf-8') #set default encoding to utf-8
然后可以查看到改变已经生效
import sys
sys.getdefaultencoding()
'utf-8'
此时运行程序,如果仍然报告之前的错误,只需要显示地设定输出的编码
print s.encode('utf-8')
就可以看到正确显示。
本人亲测有效!
改了默认编码方式以后,只要网页的编码方式和修改的默认编码方式相同,就可以直接encode,不需要decode这个步骤,因为这个步骤py会自动做好,代码如下:
res =res.read()
res.encode(‘gbk’) #在linux下可以这样,不过经常会看到gbk cann’t encode \uxxx....这只是gbk储存的字符集没有utf-8多,所以用gbk去编码unicode的话可能会出现”这个词不懂”的现象,一般都是用utf-8来编码gbk的,就不会”不懂”了,这个例子要是换成网站是gbk编码的就好了(反过来就行),但是gbk的网站比较少,只是例子问题,了解原理就OK...
在win下直接print res就相当于encode(‘gbk’)了...
前面讲的是用urllib2库中的中文编码问题,下面讲一下requests库中的中文编码问题…
还是用那个例子
import requests
url=’http://www.fishc.com’
res=requests.get(url)
print res.content
这个用print res.content不会有任何问题,但是如果使用print res.text就有可能有问题...(如果你喜欢折腾的话就用res.text吧,改一个默认编码方式就行)
这种情况输入可能会有乱码,因为res.text是unicode编码…然后直接print res.text就会以默认的编码方式输出,这个默认的编码方式是ISO-8859-1...应该是requests库默认的,可以用res.encoding来查看其方式…一般都是'ISO-8859-1'
我们可以改变其默认的方式:
res.encoding=’utf-8’
改成utf-8之后再试试res.text就没有乱码了…
我看官方的文档是说response.text每次都会去访问response.encoding里的编码方式。所以说py2真的很多地方没有考虑到中文字符,连unicode字符集也是后面才加入的,一开始很长一段时间都是用ascii,谁让这玩意是美国人发明的呢….
还好py3中有一些地方已经默认了是utf-8的方式,不然还得像py2一样去修改…很多人一直在问新手应该学py2还是py3,我个人认为,py3对中文的支持是毋庸置疑的,论编程的方便是远超py2的,但是因为年龄还比较短,py2具体有的很多包可能py3还不太完善,而且书籍也不多,所以如果想造轮子的话还是建议用py2,就是得多折腾些..不过未来肯定是py3的,这点是肯定的,如果新版本还比不上旧版本那做出来还有什么意义…所以说选择还是看自己….