洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码
编码
这篇博文的主题是,编码问题,老生常谈的问题了对吧?从我这一套的文章来看,前面已经提到好多次编码问题了,的确这个确实很重要,这可是难道了很多能人异士的,当你以为你学懂了,在研究爬虫时你发现你错了,还是没搞懂,爬虫研究完后,你以为你懂了,url编码又把你打回原形,然后你以为你真的懂了,你学到socket的时候,你发现,你还是没有真的理解,真实气人啊,对吧
与编码问题相关的都在这两篇博文中:
洗礼灵魂,修炼python(3)--从一个简单的print代码揭露编码问题,运行原理和语法习惯
洗礼灵魂,修炼python(57)--爬虫篇—知识补充—编码之对比不同python版本获取的数据
(注明:这是我之前的博文,前期对编码问题,可能理解的不够,我个人之前对编码问题也很困惑,所以如果有错,大家请忽略。结合本篇来看,相信你会真的理解编码问题)
那么本篇博文就深度的剖析一下这个最烦的问题
python2与python3不同的编码解码
首先我们都知道python2和python3有不同的编码规格。
在python3中只有两种数据存储类型,str,bytes
str:存储的就是Unicode,即全球都能认的编码类型
bytes:存储的就是十六进制
而由str转成bytes就叫编码
bytes转成str就叫解码
因为计算机能认识的字符集只能是二进制,那么bytes是最接近二进制的字符集,十六进制再转成二进制就方便很多了
在python2里
有两种类型:Unicode和str(bytes)
str和unicode都是类basestring的子类,str其实是字节串,它是unicode经过编码后的字节组成的序列。而unicode是一个字符串,str是unicode这个字符串经过编码(utf8,gbk等)后的字节组成的序列。unicode才是真正意义上的字符串,对字节串str使用正确的字符编码规则进行解码后获得
那么python2中又是什么鬼呢,不急,接着看
这情况看到了吧?其实我相信,如果你在爬虫方面研究的比较多,并且你是使用python2来爬的话,你早就遇到这个情况了,这是为什么呢?
在python2中,str 存储的就是bytes,首先在Python 2中,print是一个语句(而在Python 3中变成了函数),当直接print时字符串会把数据从IO中读取出来成为有编码规则的数据,所以print打印的正好是我们期待的,而放进容器类型(列表,元组,字典,集合)里时,就会看到存储时的样子。
所以在python2里,str=bytes,换句话python里只存在一种数据存储类型:bytes。Python 2 悄悄掩盖掉了 byte 到 unicode 的转换,让程序在处理 ASCII 的时候更加简单
py2编码的最大特点是Python 2 将会自动的将bytes数据解码成 unicode 字符串,所以在python2中字节数据可以和unicode型进行拼接:
也就是并没有把str和bytes严格的分开,在这一点上,python3就做得更好了,也是正确的,本来就是的,明明就是str,你存储就成了字节类型,这是搞事情啊,请看:
这段代码在python3中是成立的对吧(关于print在python2和3中的不同写法就不再赘述了),但是报错了,提示的是str()允许的参数必须是1个,而却给了两个,这里在上面我们已经知道str和bytes编码解码的功效是一样的了,那么也就是说,当转成字节类型时,python2已经默认为我们设定了一套编码规则,不需要我们手动添加编码规则了。所以这也是为什么使用python2时,时不时会报编码错误了,它已经给我们编码/解码好了,用的什么编码规则我们还要自己去拆解,不然就会出现一堆的错误,很混乱对吧?
还是那句话,在编码问题上,python3很完善,python2一堆小毛病
在python3里
有两种类型,Unicode和byte
现在你从普通文本转换成 “str” 类型后存储的是一个 unicode, “bytes” 类型存储的是 byte 串。你也可以通过一个 b 前缀来制造 byte 串。
Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分。文本总是Unicode,由str数据类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,正是这使得两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。
例如,bytes('你好','utf8')就可以把str为‘你好’编码为十六进制。这里的utf8可以理解为编码规则或者叫编码类型,它并不是固定的,也可以是其他的,比如gbk之类,像这种utf8和gbk,以及台湾的big5,韩国,日本的各种字符类型,这些除了utf8以外,各个国家都有自己各自的编码类型去编码,编出来的都不是不同的类型,虽然最后都是十六进制的bytes。
请看:
像这种’\xe4\xa0‘啥的就是bytes类型,它也是十六进制的数据
那么有朋友想到了,字符串类型的数据不是自带编码吗?请看:
发现b1 和b4是一样的,那么不用说,使用其他编码规则来编码也是一样的
上面是编码,那么解码呢?这里我就同时使用decode和str转码的方法了:
也是一样的对吧?那么有朋友突发奇想了,解码时解码成其他的可以不,试试呢:
呀,啥字,看不懂啊,其实这已经乱码了,因为编码和解码不统一,这里只是刚好给解码出来了,大部分情况是解码不出来并且会报错的,比如我这解码成big5试试:
看,报错了吧?
所以要记住,编码和解码必须是同一种编码规则
Python 3 中对 Unicode 支持的最大变化就是将会没有对 byte 字节串的自动解码。如果你想要用一个 byte 字节串和一个 unicode 相链接的话,你将会得到一个错误,不管你包含的内容是什么
url编码
这个问题,在前面的某一篇博文里我已经解析过了,为了统一,放在一起了
首先,Http协议中参数的传输是"key=value"这种键值对形式的,如果要传多个参数就需要用“&”符号对键值对进行分割。如"?key1=value1&key2=value2",这样在服务端在收到这种字符串的时候,会用“&”分割出每一个参数,然后再用“=”来分割出键和值并进行处理。
然后,url只能使用 ASCII 字符集来通过因特网进行发送,也就是说url允许的只能是英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。那么如果url中有汉字,就必须编码成为允许的字符后方可使用。
但是有个问题是,标准的国际组织并没有规定具体的编码方法,而是交给应用程序(浏览器)根据自己的一套编码方式进行编码,有点乱,而每个浏览器对同样的字符解码都是不太一样的。但这里只是指网站子文件的字符编码混乱,比如前面用的百度搜索,编码还是一样的:
火狐浏览器:
https://www.baidu.com/s?wd=%E8%83%A1%E6%AD%8C&rsv_spt=1&rsv_iqid=0xa88a849a000297f1&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=monline_3_dg&rsv_enter=1&oq=a&inputT=1164&rsv_t=44f3deAD5ZhHUuZS8qctF8DYdHQl0Jc0fIHprlrxVQPAKhGaI7WQzU0%2BDYkOZ7iFCV9H&rsv_pq=bc5bcce5000040e2&rsv_sug3=10&rsv_sug1=9&rsv_sug7=100&bs=a
谷歌浏览器:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E8%83%A1%E6%AD%8C&oq=%25E8%2583%25A1%25E6%25AD%258C&rsv_pq=bc8022d200026160&rsv_t=cf02s%2BKYldDmROy0mQpW7gMikG0rFAkF5WE0KydGdjM1v4PH9wW87XYxuCA&rqlang=cn&rsv_enter=1&rsv_sug3=1&rsv_sug1=1&rsv_sug7=100&rsv_sug2=0&inputT=12&rsv_sug4=439
IE浏览器:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=%E8%83%A1%E6%AD%8C&rsv_pq=b3b7634b00004749&rsv_t=fa91EE041mGXpmDfMhWtd6QSrm%2F24pXydfxJc%2BPc5W59OuaHKoicHE4Ngwo&rqlang=cn&rsv_enter=1&rsv_sug3=4
(搜索关键词我已经标注出来)
url的编码样式是使用【%】加上代表十六进制为一个字节形式的两位字符—【0-9和A-F】来(比如%EC),详细规则:
- 对于ASCII字符,字母a在ASCII码中对应的字节是0x97,那么Url编码之后得到的就是%97,字母abc, url编码后得到的就是%97%98%99
- 对于非ASCII字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。如前面搜索的"胡歌"使用UTF-8编码规则字符集得到的字节为0xE8 0x83 0xA1 0xE6 0xAD 0x8C,经过Url编码之后得到%E8%83%A1%E6%AD%8C
所以url编码通常也被称为百分号编码(percent-encoding)。
说白了就是ASCII码表里面有的字符,就直接按对应字节,然后把0x改为%。如果ASCII码表里没有的,就用unicode万国码里的utf8编码规则将字符转为字节,然后把0x改为%就行。
转载于:https://www.cnblogs.com/yangva/p/8417932.html
洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码相关推荐
- 史上最全的 python 基础知识汇总篇,没有比这再全面的了,建议收藏
网友们有福了,小编终于把基础篇的内容全部涉略了一遍,这是一篇关于基础知识的汇总的文章,请朋友们收下,不用客气,不过文章篇幅肯能会有点长,耐心阅读吧 爬虫(七十)多进程multiprocess(六十一) ...
- python基础知识拾遗
python菜鸟教程 文章目录 基础教程 简介 基础语法(略) 变量类型 标准数据类型 数字 字符串 列表 元组 字典 数据类型转换 运算符 算术运算符 赋值运算符 位运算符(?) 逻辑运算符 成员运 ...
- 【Python零基础到入门】Python预备知识必备篇——Python简介
目录
- 全网首篇深度剖析PoolFormer模型,带你揭开MetaFormer的神秘面纱
文章目录 摘要 作者简介 模型分析 Input Emb模块 to_2tuple函数 nn.Conv2d nn.Identity() Input Emb模块源码 PoolFormerBlock Norm ...
- 独热编码python实现_详解深度学习中的独热编码
很多人开始接触深度学习,数据处理遇到第一个专业英文术语就是one-hot encode(独热编码),很多初学者就会迷茫,这个东西是什么意思,其实说的直白点所谓的独热编码最重要的就是把一组字符串或者数字 ...
- Python基础语法入门篇(一)
Python基础语法入门篇(二) 1. 注释 在我们工作编码的过程中,如果一段代码的逻辑比较复杂,不是特别容易理解,可以适当的添加注释,以辅助自己 或者其他编码人员解读代码. 注释是给程序员看的,为了 ...
- 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸
类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...
- 类的继承python事例_【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸...
作者:白宁超 2016年10月10日22:36:57 摘要:继一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc入门资料包含了基本要点.本文是对文档常用核心要点进行梳理,简 ...
- 有关python方面的论文_有关python基础知识的文章推荐5篇
一.变量命名规则1.变量名只能是字母.数字.下划线的任意组合2.变量名不能以数字开头3.一些保留字段不能作为自定义变量名4变量名需要有明确含义,如保存名字的变量,最好定义为name之类的变量名二.字符 ...
最新文章
- Kafka为什么这么快?
- mysql ldap_OpenLDAP 使用MySQL作为数据库
- 使用批处理执行sql 语句
- JS-内置对象内置构造函数事件-拖拽轮播图无缝滚动
- BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )
- python编写代码运用递归画图形_python数据结构与算法 22 递归图形
- JScrollPane恢复正常滚动量
- 1005 Spell It Right (20)(20 分)
- 【设计鉴赏】张艺谋《影》震撼人心的海报设计
- 解决win10系统flash player无法播放,升级
- c语言程序中TMOD,keil 中用c 语言写的代码 error C231: 'TMOD': redefinition
- 如何获取目标期刊的参考文献格式模板?
- docker-compose 部署 mindoc文档服务器(支持在线markdown文件编辑)
- 2010考研数学二第(13)题——导数应用题
- WebKit的默认样式
- 仰望星空,脚踏实地——吴燕生
- 计算机usb无法使用,电脑USB接口都不能用的解决办法[多图]
- ValueError: multiclass format is not supported
- 从网线到网络设备是如何工作的
- PostgreSQL11 | pgadmin4基本使用