相信大家在玩爬虫的时候,经常需要自己去批量构建url,但是有的时候网站中作为参考的同类型url却包含一串百分号的乱码,让我们自己在构建的时候无从下手。这一篇博客就来一起看看这些百分号到底是什么东西。
问题描述
今天在爬虫的时候,需要构建的一个url需要附加搜索内容,例如爬取搜索内容为“零食 京东超市”的url,如果原样输出应该是
https://so.m.jd.com/ware/search.action?keyword=零食 京东超市
但是实际的url却是
https://so.m.jd.com/ware/search.action?keyword=%E9%9B%B6%E9%A3%9F%20%E4%BA%AC%E4%B8%9C%E8%B6%85%E5%B8%82
可以看出这里是对搜索的中文内容进行了某种编码。
为什么要编码?
现实世界的各种文字,汉字也好,英文也好,在计算机中都是二进制存储。因为各个国家的存储编码标准不统一,英文用ASCII,中文有GB,导致的结果就是同一个文件,在不同标准的电脑上有的能正常显示有的会乱码。所以后来ISO就规定大家都用UNICODE来统一进行编码,不管什么字符都用固定长度的字节来表示。现在我们的电脑和服务器使用的都是UNICODE编码来存储内容。
因为要对全球所有文字都囊括,所以一个UNICODE的字符会很长,这样势必就会造成巨大的浪费。例如英文本来一个字节就能表示一个字符的现在白白浪费高位的几个字节。这也是为什么之前UNICODE流行不起来的原因。
后来为了解决这种浪费的问题,面向传输的对UNICODE的改进编码方式开始出现,例如使用最广泛的UTF-8。UTF-8是一种变长编码,可以很方便地在两点之间进行UNICODE内容的传送。在发送方将UNICODE编码为UTF-8,接收方再将UTF-8解码为UNICODE。
除了UTF-8,也还有UTF-16和中国特色的GBK等传输编码方式。在UTF-8方式下,一个汉字编码为三个16进制数。
所以,url中的一堆乱码就是中文字符的十六进制传输编码用百分号隔开之后的形式,可能是UTF-8方式也可能是其他方式。
python的编码操作
在python3中,所有的字符串默认都是UNICODE编码,不再有python2中的u前缀了。
直接通过string类型的encode
和decode
方法就可以进行编码和解码了
'零食 京东超市'.encode('utf-8')
Out[61]: b'\xe9\x9b\xb6\xe9\xa3\x9f \xe4\xba\xac\xe4\xb8\x9c\xe8\xb6\x85\xe5\xb8\x82'
'零食 京东超市'.encode('gbk')
Out[62]: b'\xc1\xe3\xca\xb3 \xbe\xa9\xb6\xab\xb3\xac\xca\xd0'
\x
表示十六进制,可以看出GBK编码比UTF-8要节约空间一点,但是只是对中文有效。
注意编码后的b前缀,表示python中的bytes类型,细心的朋友应该已经注意到了,从网上爬下来的数据基本都是bytes类型,所以都要先解码为UNICODE再使用。
b'\xe9\x9b\xb6\xe9\xa3\x9f \xe4\xba\xac\xe4\xb8\x9c\xe8\xb6\x85\xe5\xb8\x82'.decode()
Out[66]: '零食 京东超市'
b'\xc1\xe3\xca\xb3 \xbe\xa9\xb6\xab\xb3\xac\xca\xd0'.decode('gbk')
Out[67]: '零食 京东超市'
默认的编码和解码规则都是UTF-8,而b前缀不能省略。
但是并没有直接变成url中的百分号格式,还需要用到别的库
from urllib.parse import quote
quote('零食 京东超市')
Out[58]: '%E9%9B%B6%E9%A3%9F%20%E4%BA%AC%E4%B8%9C%E8%B6%85%E5%B8%82'
from urllib.parse import unquote
unquote('%E9%9B%B6%E9%A3%9F%20%E4%BA%AC%E4%B8%9C%E8%B6%85%E5%B8%82')
Out[60]: '零食 京东超市'
总结
大多数场景下,只是从字符串到UTF-8的互相转换,用字符串的encode
和decode
方法就可以了。如果要使用在url中,还需要额外的quote
和unquote
方法。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。