这是恋习Python之浅入深出系列第3篇原创首发文章

作者|丁彦军

来源|恋习Python(ID:sldata2017)

转载请联系授权(微信ID:2394608316)

近日,有位粉丝向我请教,在爬取某网站时,网页的源代码出现了中文乱码问题。之前关于爬虫乱码有很多粉丝的各式各样的问题,今天恋习Python与大家一起总结下关于网络爬虫的乱码处理。注意,这里不仅是中文乱码,还包括一些如日文、韩文 、俄文、藏文之类的乱码处理,因为他们的解决方式 是一致的,故在此统一说明。

一、乱码问题的出现

就以爬取51job网站举例,讲讲为何会出现“乱码”问题,如何解决它以及其背后的机制。

代码示例:

import requestsurl = "http://search.51job.com"
res = requests.get(url)
print(res.text)

显示结果:

打印res.text时,发现了什么?中文乱码!!!不过发现,网页的字符集类型采用的gbk编码格式。

我们知道Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 r.text 之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用r.encoding 属性来改变它。

接下来,我们一起通过resquests的一些用法,来看看Requests 会基于 HTTP 头部对响应的编码方式。

print(res.encoding)  #查看网页返回的字符集类型
print(res.apparent_encoding) #自动判断字符集类型

输出结果为:

可以发现Requests 推测的文本编码(也就是网页返回即爬取下来后的编码转换)与源网页编码不一致,由此可知其正是导致乱码原因。

二、乱码背后的奥秘

当源网页编码和爬取下来后的编码转换不一致时,如源网页为gbk编码的字节流,而我们抓取下后程序直接使用utf-8进行编码并输出到存储文件中,这必然会引起乱码,即当源网页编码和抓取下来后程序直接使用处理编码一致时,则不会出现乱码,此时再进行统一的字符编码也就不会出现乱码了。最终爬取的所有网页无论何种编码格式,都转化为utf-8格式进行存储。

注意:区分源网编码A-gbk、程序直接使用的编码B-ISO-8859-1、统一转换字符的编码C-utf-8。

在此,我们拓展讲讲unicode、ISO-8859-1、gbk2312、gbk、utf-8等之间的区别联系,大概如下:

最早的编码是iso8859-1,和ascii编码相似。但为了方便表示各种各样的语言,逐渐出现了很多标准编码。iso8859-1属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。

1981年中国人民通过对 ASCII 编码的中文扩充改造,产生了 GB2312 编码,可以表示6000多个常用汉字。但汉字实在是太多了,包括繁体和各种字符,于是产生了 GBK 编码,它包括了 GB2312 中的编码,同时扩充了很多。中国又是个多民族国家,各个民族几乎都有自己独立的语言系统,为了表示那些字符,继续把 GBK 编码扩充为 GB18030 编码。每个国家都像中国一样,把自己的语言编码,于是出现了各种各样的编码,如果你不安装相应的编码,就无法解释相应编码想表达的内容。终于,有个叫 ISO 的组织看不下去了。他们一起创造了一种编码 UNICODE ,这种编码非常大,大到可以容纳世界上任何一个文字和标志。所以只要电脑上有 UNICODE 这种编码系统,无论是全球哪种文字,只需要保存文件的时候,保存成 UNICODE 编码就可以被其他电脑正常解释。UNICODE 在网络传输中,出现了两个标准 UTF-8 和 UTF-16,分别每次传输 8个位和 16个位。于是就会有人产生疑问,UTF-8 既然能保存那么多文字、符号,为什么国内还有这么多使用 GBK 等编码的人?因为 UTF-8 等编码体积比较大,占电脑空间比较多,如果面向的使用人群绝大部分都是中国人,用 GBK 等编码也可以。

也可以这样来理解:字符串是由字符构成,字符在计算机硬件中通过二进制形式存储,这种二进制形式就是编码。如果直接使用 “字符串↔️字符↔️二进制表示(编码)” ,会增加不同类型编码之间转换的复杂性。所以引入了一个抽象层,“字符串↔️字符↔️与存储无关的表示↔️二进制表示(编码)” ,这样,可以用一种与存储无关的形式表示字符,不同的编码之间转换时可以先转换到这个抽象层,然后再转换为其他编码形式。在这里,unicode 就是 “与存储无关的表示”,utf—8 就是 “二进制表示”。

三、乱码的解决方法

根据原因来找解决方法,就非常简单了。

方法一:直接指定res.encoding

import requestsurl = "http://search.51job.com"
res = requests.get(url)
res.encoding = "gbk"
html = res.text
print(html)

方法二:通过res.apparent_encoding属性指定

import requestsurl = "http://search.51job.com"
res = requests.get(url)
res.encoding = res.apparent_encoding
html = res.text
print(html)

方法三:通过编码、解码的方式

import requestsurl = "http://search.51job.com"
res = requests.get(url)
html = res.text.encode('iso-8859-1').decode('gbk')
print(html)

输出结果:

基本思路三步走:确定源网页的编码A---gbk、程序通过编码B---ISO-8859-1对源网页数据还原、统一转换字符的编码C-utf-8。至于为啥为出现统一转码这一步呢? 网络爬虫系统数据来源很多,不可能使用数据时,再转化为其原始的数据,假使这样做是很废事的。所以一般的爬虫系统都要对抓取下来的结果进行统一编码,从而在使用时做到一致对外,方便使用。

比如如果我们想讲网页数据保存下来,则会将起转为utf-8,代码如下:

with open("a.txt",'w',encoding='utf-8') as f:f.write(html)

四、总结

关于网络爬虫乱码问题,恋习Python不仅给出了一个解决方案,还深入到其中的原理,由此问题引申出很多有意思的问题,如,utf-8、gbk、gb2312的编码方式怎样的?为什么这样转化就可以解决问题?

最后,多动脑,多思考,多总结,致每一位码农!

浅入深出:Python字符串切片操作

浅入深出Python元编程

处理中文乱码_浅入深出:一次提问引发的深思,从此再也不怕“乱码”问题相关推荐

  1. Java 注解 (Annotation)浅入深出

    Java 注解 (Annotation)浅入深出 本文主要参考与借鉴frank909 文章,但更为简单,详细. Annotation 中文译过来就是注解.标释的意思.Annotation是一种应用于类 ...

  2. 浅入深出之Java集合框架(上)

    Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到浅入深出之Java集合框架(下). ...

  3. 浅入深出之Java集合框架(中)

    Java中的集合框架(中) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到浅入深出之Java集合框架(下). ...

  4. Angular浅入深出系列 - 写在前面

    本系列目录: 写在前面 基础知识 控制器(Controller) 作用域(Scope) 集合(Collection) 模块(Module) 依赖注入(Dependency Injection) 服务( ...

  5. 浅入深出Vue:环境搭建

    浅入深出Vue:环境搭建 工欲善其事必先利其器,该搭建我们的环境了. 安装NPM 所有工具的下载地址都可以在导航篇中找到,这里我们下载的是最新版本的NodeJS Windows安装程序 下载下来后,直 ...

  6. JavaScript中函数作用域之精辟,函数原理的浅入深出,及程序执行预编译之通天编译???

    1.程序执行的前一刻会先将代码预编译一遍,如果有语法错误则直接终止程序运行 //预编译之通天编译 --> 在执行的前一刻,会把文件通天扫描一遍 /** //预编译 函数整体提升(即函数会放到程序 ...

  7. 浅入深出被人看扁的逻辑回归!

    好像在各种机器学习入门教程中,逻辑回归模型(Logistic/Logit Regression)经常被拿来作为入门的机器学习模型,比如我家的Andrew Ng就是这样做的. 看起来,逻辑回归模型实在太 ...

  8. Why WebRTC|“浅入深出”的工作原理详解

    WebRTC可以被看作是一个不需要安装任何插件或者下载任何额外程序就能运行的浏览器原生实时通信手段.不同的客户端通过(相同或不同)浏览器跳转到同一个 URL 就能实现实时互通.看见彼此.但这只是&qu ...

  9. Delphi控件开发浅入深出(一)

    有人说过"不会开发控件的Delphi程序员不是真正的程序员".Delphi正是由于高度的可扩展性和大量的第三方控件的支持才能吸引无数程序员挑剔的目光.即使是由于工作需要使用其他开发 ...

最新文章

  1. python怎么读文件名-Python获取指定文件夹下的文件名
  2. Python中包含义及其定义
  3. android实现背景音乐播放
  4. ELK技术栈—Kibana
  5. TreeView控件的展开与折叠
  6. python21天打卡Day8-string,int互转
  7. php表格批量修改数据,php批量修改数据库表名前缀
  8. revit建筑样板_BIM技术在历史保护建筑中的具体应用(艾三维BIM分享)
  9. iOS 三步完成购买苹果开发者账号
  10. win10系统默认壁纸路径
  11. MySQL的两阶段提交(数据一致性)
  12. gazebo设置_gazebo的学习与使用
  13. 6-1 插入法建立有序链表
  14. GitHub 3.6k Satr自监督学习(Self-Supervised Learning)资源你值得拥有!
  15. win7计算机本地用户和组,Win7旗舰版找不到本地用户和组如何解决
  16. 字节跳动算法工程师总结:腾讯+字节+阿里面经真题汇总,含面试题+答案
  17. source tree ui操作对应的git命令
  18. postgis——几何图形创建使用
  19. 复现《nature communications》图表(一):一模一样的Figure1
  20. ✨英语学习|如何高效做英语阅读笔记

热门文章

  1. php7cms框架,GitHub - itsky71/itskycms: 基于ThinkPHP框架的一个CMS系统
  2. jsp 如何动态给图片赋值_在Excel表格中你知道如何动态引用图片吗?
  3. mysql导入报编码错误问题解决
  4. php yii框架连接数据库,Yii 框架使用数据库(databases)的方法示例
  5. list选取多个元素 python_python基础篇:list列表的操作大盘点
  6. bash: go: 未找到命令_golang快速入门[2.3]-go语言开发环境配置-linux
  7. 我的世界java手机版怎么调按键_博阅Likebook P6高配青春版使用评测
  8. mysql修改引擎_修改MySQL引擎
  9. OpenShift 4 Tekton (2) - OpenShift Pipeline入门-用Pipeline部署应用
  10. Visual Studio提示——DebuggerDisplay