python转码译码
python的编码问题研究------使用scrapy体验
基于python2
scrapy是一款非常轻量级的爬虫框架,但是由于它隐藏了太多关于网络请求的细节,所以我们有时候会遭遇到一下很尴尬的bug,当然这主要是因为碰到一些不规范的网站。
python的编码转码网上有很多文章,如果你不了解这个你可以参考下面了解。
Ned Batchelder 关于python unicode和str的理解,通俗易懂
通过上面我们可以很好的理解python的转码译码,在这里我想谈一下我自己对其的认识吧,我一开始接触的c语言序列的基本上都是强类型,比如C里面假如我想写一个函数每个传人的参数都得是有类型的,但是python弱化了类型这一点,python也是面对对象的,但是他的对象就是鸡同鸭讲,照猫画虎就能运行,弱类型适合动态语言,我们不确定下一行代码输入的是什么,自从学python起,一直感觉python对类型一直不严格,这样就给了我一种错觉,只要长得差不多就能一样的比划,比如在两个string,'中国'
,u'中国'
,看起来差不多但是如果你把u'中国'
存入文件中就会出错(假如你没定义编码规则) UnicodeEncodeError: 'ascii' codec can't encode characters in position 344-351: ordinal not in range(128)
unicode字符编码错误,要想理解这个要对unicode字符集和unicode编码有一定的理解,推荐你读一下这篇博客字符编码的知识,python内部使用unicode字符集存贮所以的编码的字符,为什么要用unicode字符集举个栗子吧:
A是米国的程序员,他使用asicc编码的文件上传了一封邮件, B是中国的程序员他使用gbk编码的文件上传了一封邮件, 现在C要用程序同时处理A和B的邮件,有两种解决方法他把A的文件译码再编码成B的gbk,或者将B的文件译码成asicc但是中文无法处理,那么只能使用第一种方法将A的文件编码成gbk,但是改天D又来啦,他是俄国人,天啊噜gbk可能没有把俄语编进去,那肿么办,我们迫切需要一种编码可以把所以的字符放进去,所以unicode出现了,Unicode中将字符集按照一定的类别划分到0~16这17个层面(Planes)中,每个层面中拥有216=65536个字符码,因此Unicode总共拥有的字符码,也即是Unicode的字符空间总共有17*65536=1114112,一共有1114112这么多的字符可以用,这下我们不用担心了吧,太好了这下不用愁了,
python 内部使用unicode字符集作为一个译码中转站,因为他编码了所以的字符集,只要你能在自己编码方案上找到自己的字,我就能在unicode字符集找到你的位置,所以使用unicode可以很好的解决多种编码方案产生的问题(比如gbk,utf-8) 当然其他编码方案如果想使用unicode解码成其他的必须同unicode有一一对应关系,不过现在主流的编码方案如gbk,gb2312,utf-8都是unicode系的。
了解了这些基础知识就可以知道了为什么存贮u'中国'
存不进文件里面去了,因为unicode并不提供给当今字符解析器的方法,就是u234e
一个16进制数字,屏幕上不知道他对应什么图形,所以python系统要求存进文件的必须是字节流,也就是可以unicode是一种更高级的字符流,这个字符流能存贮当今世界所以定义的字符,但是他只是一个规定字符集合,我们只需要把发现的字符放进去占据一个位置,但是我们不需要考虑屏幕是否认识这个字符,这个字符的存贮由编码方案负责,如utf-8这些,假如没有字符编码方案可以存贮这些,我们虽然在unicode上有这个字符但是我们无法print出来,所以我们必须将unicode转换成普通字符流,有人就会问了,假如我真的没有找到一个合适编码方案可以存贮所有语言,我们可以将他编码成unicode—escape类型,这里我们不多讲。
这就可以解释我们大部分碰到的错误unicodedecodeerror和unicodeencodeerror错误,都是因为字符编码方案不了解造成的,网上很多说碰到这种错误就encode,decode搞一下就行但是不弄清楚这背后的知识就会犯迷糊。
接下来我谈谈我遇到的错误吧,在爬取http://yjsy.ncu.edu.cn/yjs_showmsg.asp?id=2770
这个页面时(这是一个不规范的页面没有设置charset),因为每个spider调用的
response.xpath('//xpath').extract()
选择器返回的是一个unicode编码的字符集,但是他是接受的是一个字符流,spider可能调用了 response.body.decode(response.encoding)
进行转码,但是这个response.encoding有时候会判断错误,比如将我一个gbk编码的文件判断成cp1253,这个时候假如我把他解码成encode成其他编码方式的话,我们就会得到乱码,那怎么纠正呢,我们可以这样干 先将得到的列表中每个content
取出来,然后使用content.encode(resonse.encoding)
转码成原始字符流,现在你可以将它用正确的编码转换成unicode了
下面是我github上的关于这个scrapy的项目,在coding_pitch.py文件里面就是对于这个乱码的处理