python3编码问题汇总


Posted in Python onSeptember 06, 2016

这两天写了个监测网页的爬虫,作用是跟踪一个网页的变化,但运行了一晚出现了一个问题。。。。希望大家不吝赐教!
我用的是python3,错误在对html response的decode时抛出,代码原样为:

response = urllib.urlopen(dsturl)
content = response.read().decode('utf-8')

抛出错误为

File "./unxingCrawler_p3.py", line 50, in getNewPhones
  content = response.read().decode()
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb2 in position 24137: invalid start byte

之前运行都没问题,经过一晚上就出现了。。。。最不明白的是在它声明为utf-8编码的网页中为什么会出现utf-8无法解析的字符?

后来经过热心网友的提醒,才发现需要使用decode('utf-8', 'ignore')

为了彻底闹明白python的编码问题,特分享下文,希望对大家熟悉python的编码问题带来些帮助

1.从字节说起:

一个字节包括八个比特位,每个比特位表示0或1,一个字节即可表示从00000000到11111111共2^8=256个数字。一个ASCII编码使用一个字节(除去字节的最高位作为作奇偶校验位),ASCII编码实际使用一个字节中的7个比特位来表示字符,共可表示2^7=128个字符。比如ASCII编码中的01000001(即十进制的65)表示字符'A',01000001加上32之后的01100001(即十进制的97)表示字符'a'。现在打开Python,调用chr和ord函数,我们可以看到Python为我们对ASCII编码进行了转换。如图

python3编码问题汇总

第一个00000000表示空字符,因此ASCII编码实际上只包括了 字母、标点符号、特殊符号等共127个字符。因为ASCII是在美国出生的,对于由字母组成单词进而用单词表达的英文来说也是够了。但是中国人、日本人、 韩国人等其他语言的人不服了。中文是一个字一个字,ASCII编码用上了浑身解数256个字符都不够用。

因此后来出现了Unicode编码。Unicode编码通常由两个字节组成,共表示256*256个字符,即所谓的UCS-2。某些偏僻字还会用到四个字节,即所谓的UCS-4。也就是说Unicode标准也还在发展。但UCS-4出现的比较少,我们先记住: 最原始的ASCII编码使用一个字节编码,但由于语言差异字符众多,人们用上了两个字节,出现了统一的、囊括多国语言的Unicode编码。

在Unicode中,原本ASCII中的127个字符只需在前面补一个全零的字节即可,比如前文谈到的字符‘a':01100001,在Unicode中变成了00000000 01100001。不久,美国人不开心了,吃上了世界民族之林的大锅饭,原本只需一个字节就能传输的英文现在变成两个字节,非常浪费存储空间和传输速度。

人们再发挥聪明才智,于是出现了UTF-8编码。因为针对的是空间浪费问题,因此这种 UTF-8编码是可变长短的 ,从英文字母的一个字节,到中文的通常的三个字节,再到某些生僻字的六个字节。解决了空间问题,UTF-8编码还有一个神奇的附加功能,那就是兼容了老大哥的ASCII编码。一些老古董软件现在在UTF-8编码中可以继续工作。

注意除了英文字母相同,汉字在Unicode编码和UTF-8编码中通常是不同的。比如​汉字的‘中'字在Unicode中是01001110 00101101,而在UTF-8编码中是11100100 10111000 10101101。

我们祖国母亲自然也有自己的一套标准。那就是GB2312和GBK。当然现在挺少看到。通常都是直接使用UTF-8。

2.Python3中的默认编码

Python3中默认是UTF-8,我们通过以下代码:

import sys

sys.getdefaultencoding()

可查看Python3的默认编码。​

python3编码问题汇总

3.Python3中的​encode和decode

Python3中字符编码经常会使用到decode和encode函数。特别是在抓取网页中,这两个函数用的熟练非常有好处。encode的作用,使我们看到的直观的字符转换成计算机内的字节形式。decode刚好相反,把字节形式的字符转换成我们看的懂的、直观的、“人模人样”的形式。

python3编码问题汇总

\x表示后面是十六进制, \xe4\xb8\xad即是二进制的 11100100 10111000 10101101。也就是说汉字‘中'encode成字节形式,是 11100100 10111000 10101101。同理,我们拿 11100100 10111000 10101101也就是 \xe4\xb8\xad来decode回来,就是汉字‘中'。完整的应该是 b'\xe4\xb8\xad',在Python3中, 以字节形式表示的字符串则必须加上 前缀b,也就是写成上文的b'xxxx'形式。

前文说的Python3的默认编码是UTF-8,所以我们可以看到,Python处理这些字符的时候是以UTF-8来处理的。因此从上图可以看到,就算我们通过encode('utf-8')特意把字符encode为UTF-8编码,出来的结果还是相同:b'\xe4\xb8\xad'。

明白了这一点,同时我们知道​UTF-8兼容ASCII,我们可以猜想大学时经常背诵的‘A'对应ASCII中的65,在这里是不是也能正确的decode出来呢。十进制的65转换成十六进制是41,我们尝试下:

b'\x41'.decode()

结果如下。果然是字符‘A'

python3编码问题汇总

4.Python3中的​编码转换

据说字符在计算机的内存中统一是以Unicode编码的。只有在字符要被写进文件、存进硬盘或者从服务器发送至客户端(例如网页前端的代码)时会变成utf-8。但其实我比较关心怎么把这些字符以Unicode的字节形式表现出来,露出它在内存中的庐山正面目的。这里有个照妖镜:

xxxx.encode/decode('unicode-escape')

python3编码问题汇总

b'\\u4e2d'还是b'\u4e2d,一个斜杠貌似没影响。同时可以 发现在shell窗口中,直接输 '\u4e2d'和输入b '\u4e2d'.decode('unicode-escape')是相同的,都会打印出汉字‘中', 反而是 '\u4e2d'.decode('unicode-escape')会报错。说明 说明Python3不仅支持Unicode,而且一个‘\uxxxx'格式的 Unicode字符 可被辨识且被等价于str类型。

python3编码问题汇总

如果我们知道一个Unicode字节码,怎么变成UTF-8的字节码呢。懂了以上这些,现在我们就有思路了,先decode,再encode。代码如下:

​xxx.decode('unicode-escape').encode()

python3编码问题汇总

​最后的扩展

还记得刚刚那个ord吗。时代变迁,老大哥ASCII被人合并,但ord还是有用武之地。试试ord('中'),输出结果是20013。20013是什么呢,我们再试试hex(ord('中')),输出结果是'0x4e2d',也就是20013是我们在上文见面了无数次的x4e2d的十进制值。这里说下hex,是用来转换成十六进制的函数,学过单片机的人对hex肯定不会陌生。

最后的扩展,在网上看到的他人的问题。我们写下类似于'\u4e2d'的字符,Python3知道我们想表达什么。但是让Python读取某个文件的时候出现了'\u4e2d',是不是计算机就不认识它了呢?后来下文有人给出了答案。如下:

import codecs

file = codecs.open( "a.txt", "r", "unicode-escape" )

u = file.read()

print(u)
Python 相关文章推荐
跟老齐学Python之有容乃大的list(1)
Sep 14 Python
web.py在SAE中的Session问题解决方法(使用mysql存储)
Jun 24 Python
在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
Jun 07 Python
python 全文检索引擎详解
Apr 25 Python
python中requests爬去网页内容出现乱码问题解决方法介绍
Oct 25 Python
python基础之包的导入和__init__.py的介绍
Jan 08 Python
python+ffmpeg视频并发直播压力测试
Mar 06 Python
python实现12306抢票及自动邮件发送提醒付款功能
Mar 08 Python
Pandas 按索引合并数据集的方法
Nov 15 Python
浅谈django2.0 ForeignKey参数的变化
Aug 06 Python
python 队列基本定义与使用方法【初始化、赋值、判断等】
Oct 24 Python
Python中re模块的元字符使用小结
Apr 07 Python
用Python实现命令行闹钟脚本实例
Sep 05 #Python
Python爬虫爬取美剧网站的实现代码
Sep 03 #Python
Python选课系统开发程序
Sep 02 #Python
简单谈谈Python中函数的可变参数
Sep 02 #Python
Python实现自动添加脚本头信息的示例代码
Sep 02 #Python
利用Python获取操作系统信息实例
Sep 02 #Python
好用的Python编辑器WingIDE的使用经验总结
Aug 31 #Python
You might like
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
CI框架中通过hook的方式实现简单的权限控制
2015/01/07 PHP
JavaScript实际应用:innerHTMl和确认提示的使用
2006/06/22 Javascript
Jquery通过Ajax访问XML数据的小例子
2013/11/18 Javascript
Js冒泡事件详解及阻止示例
2014/03/21 Javascript
VS2008中使用JavaScript调用WebServices
2014/12/18 Javascript
JavaScript设计模式之代理模式介绍
2014/12/28 Javascript
JavaScript实现列表分页功能特效
2015/05/15 Javascript
js仿3366小游戏选字游戏
2016/04/14 Javascript
jquery 一键复制到剪切板的实例
2017/09/20 jQuery
jQuery移动端跑马灯抽奖特效升级版(抽奖概率固定)实现方法
2019/01/18 jQuery
vue实现鼠标经过动画
2019/10/16 Javascript
[05:08]2014DOTA2国际邀请赛 Hao专访复仇的胜利很爽
2014/07/15 DOTA
Django中的“惰性翻译”方法的相关使用
2015/07/27 Python
Python实现读取并保存文件的类
2017/05/11 Python
python实现二分查找算法
2017/09/21 Python
python enumerate函数的使用方法总结
2017/11/15 Python
python交互式图形编程实例(三)
2017/11/17 Python
Python实现打印螺旋矩阵功能的方法
2017/11/21 Python
动态规划之矩阵连乘问题Python实现方法
2017/11/27 Python
python编程通过蒙特卡洛法计算定积分详解
2017/12/13 Python
详解Python中的各种转义符\n\r\t
2019/07/10 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
基于python实现坦克大战游戏
2020/10/27 Python
德国电子产品购物网站:TechInTheBasket德国
2018/12/07 全球购物
Camper鞋西班牙官方网上商店:西班牙马略卡岛的鞋类品牌
2019/03/14 全球购物
英语教育专业自荐信
2014/05/29 职场文书
思想作风建设心得体会
2014/10/22 职场文书
幼儿园大班毕业评语
2014/12/31 职场文书
2015年售票员工作总结
2015/04/29 职场文书
结婚典礼主持词
2015/06/29 职场文书
财务管理制度范本
2015/08/04 职场文书
2016元旦主持人开场白
2015/12/03 职场文书
读《钢铁是怎样炼成的》有感:百炼方成钢
2019/11/05 职场文书
2019关于垃圾分类处理的调查报告
2019/12/26 职场文书
sql时间段切分实现每隔x分钟出一份高速门架车流量
2022/02/28 SQL Server