如果经常使用Python编程或者是其他语言编程,或者在前面的文章中已经多次使用Python练习网络爬虫技术,就不可避免地会遇到中文乱码的问题。中文乱码问题经常难以理解,或者治标不治本,本文就是来解决这一难题的。

下面主要讲解:什么是字符编码Python的字符编码是什么如何解决python中文乱码问题等。有基础的朋友可以通过章节导航选择性的阅读。

1 什么是字符编码

如果是已经学习Python爬虫或者其他技术编程一段时间了,就会发现字符编码是件让人头疼的事。下面先看下经常性报错提示:

ValueError:Expected a bytes object, not a unicode object

UnicodeDecodeError:'cp950'codec can't decode byte 0x96 in position 10:illegal multibyte sequence

或者是爬过程中的乱码:

还有这样的:

当我们遇到这些内容时,可能第一时间就会去百度或者谷歌搜索解决办法,运气好的,很快就能找到解决方法。运气差的,往往看到是各种文章互相搬,目前内容搬运太狂了,有关问题的解决方法千钧一律,重点还不能有效解决问题。

哪怕是解决了这个问题,但往往是只知其表不知其里,不知道为什么这个方法能解决这个问题。下面就会详细说下字符编码错误是如何发生的。

1.1 机器编码、ASCII 和 GB2312

计算机机器语言

(为了方便看,下面二进制都采用了中间空格)

1、计算机最初设计是8比特(bit)作为一个字节(byte)。

2、计算机是二进制,由0和1组成,一个字节就是0000 0000(表示一个字符:0)。

3、也就说从0000 0000到1111 1111总共就有256个字符,例如0100 0001表示字符:A。

下面我们看图加深理解:

ASCII 

在最初发明计算机的时候美国人就同时定制了属于他们自己的编码表,通过不同的二进制与英文字符或者其他特殊字符,这种编码就称为ASCII码,ASCII码总共有128个字符编码。例如上面的数字0就是0000 0000,大写A就是0100 0001,小写b就是0110 0010。

GB2312

那他们有自己的编码了,咱们也要有啊,但是咱们文字博大精深常用汉字就有六千多个中文。上面咱也说过8位数的二进制只有256种组合,对于英文字符128来说绰绰有余,但是对我们来说就远远不够。那怎么办呢?

发展线1:一个8位数字节表示一个字符,有256种组合,那咱们加大点量,双字节编码(前面一个高字节+后面一个低字节就能造出几千个简体中文了)这就是咱们中国的 GB2312简体中文编码 方式。

发展线2:很快就发现文字实在太多了,很多偏僻文字打不出来,那就只能继续加码了,这就是 GBK 了,涵盖了全部GB2312的内容。

发展线3:常用文字、偏僻字都有了,但是后来少数民族也是咱中国的一份子啊,随着网络的普及,他们也要联网进入大家庭,这时编码只能继续拓展啊,GBK就变成了 GB18030。

多语言

当然除了咱们中国以外,其他国家都定制了各自的编码方式,例如日文:Shift_JIS,韩语:ks_c_5601-1987,俄语:windows-1251等。

问题来了,每个国家都有自己的编码方式,当在多语言文本中就有可能出现乱码。这又怎么办呢?

1.2 通用的编码方式

Unicode编码

Unicode有个很好听的名字:统一码、万国码、单一码...

Unicode的创造就是为了解决上面不同国家/地区跨语言文本转换和处理的难题。

Unicode给不同语言中的每个字符设定了统一并且唯一的二进制编码,目前大概有100万多个。

Unicode和GB2312有点像,都是采用固定的双字节模式,对于ASCII来说就是在其前面加0,例如字符A,ASCII码标识:0100 0001,那Unicode码标识:0000 0000 0100 0001,大家看出有什么规律了吧。

Unicode很厉害,这就把世界难题解决了,但是人总是在进步的,很快就发现不是任何时候都需要双字节来表示字符,例如上面说到的大写字符A,这相比ASCII来说就是浪费存储空间。那有没有一种更灵活的统一编码方式?

UTF-8编码

答案是有的:UTF-8,最大特点是长度可变,可使用1-4字节表示一个字符

相比ASCII,英文被UTF-8编码为1个字节。

相比GB2312,中文被UTF-8编码为3个字节。

下面看下ASCII、Unicode、UTF-8的对比图:

字符 ASCII Unicode UTF-8
A 01000001 00000000 01000001 01000001
01001110 00101101 11100100 10111000 10101101

然后再整理下上面的编码关系:

2 Python的字符编码

上面讲解了各种编码之间的关系,咱们看下python的编码方式,下面都是以Pyhon3来讲解。在python3中字符串有str和bytes两种类型。然后str字符串使用的是Unicode编码bytes字符串使用将Unicode转成某种类型的编码

python3种默认是unicode编码,也正是因此可以让程序随意转化成某种类型编码,就会容易遇到编码问题。

下面看个简单例子:

str1 = '学习Python'
print(str1)
print(type(str1))

运行后的结果:

从上面可以看出python3字符串默认使用就是Unicode编码。

2.1 encode - Unicode编码转其他编码

encode()方法是将unicode编码转换成其他编码的字符串,例如下面转成UTF-8:

str1 = '学习Python'
str2_utf8 = str1.encode("utf-8")
print(str2_utf8)
print(type(str2_utf8))

运行后的结果:

运行后中文都被分成3个字节,由于找不到对应的ASCII编码就只能转成十六进制显示。

2.2 decode - 将其他编码解码为Unicode编码

decode()方法是将其他编码的字符串转换成Unicode编码,我们接着上面的示例,将encode的字符串转码回Unicode:

str1 = '学习Python'
str2_utf8 = str1.encode("utf-8")
print(str2_utf8)
print(type(str2_utf8))str1_unicode = str2_utf8.decode('utf-8')
print(str1_unicode)
print(type(str1_unicode))

运行结果:

通过最后打印的内容,咱们看到中文又被转换回来了。

在实际decode解码过程中还有第二个参数报错处理,decode([encoding], [errors='strict']),默认是严格模式,报错直接中止,还有ignore可以忽略报错不影响主程序运行。

2.3 多次转码

总有人会有特别想法,例如Unicode还可以再decode吗,肯定不行

print('学习Python'.decode('utf-8')) #直接报错 'str' object has no attribute 'decode'

那有人想知道我要想把utf-8转成其他非Unicode编码怎么办呢?

首先我们先decode成Unicode,再encode成其他编码,例如utf-8转GBK:

# 先将字符串转成utf-8编码
str1 = '学习Python'.encode('utf-8')
# 将utf-8编码转成其他编码
str2 = str1.decode('utf-8').encode('GBK')
print(str2)
print(type(str2))

运行后结果:

到此我们就把转码搞定了。

3 解决中文乱码

通过上面的学习,我们基本掌握了编码方式,转码技术,那么对后面出现的问题就很容易搞定了。一般在实际业务中,会有下面几种常见的乱码情况:

3.1 情况一:使用Requests请求网站获得内容后中文乱码

下面这个地址是仅供参考学习用:示例地址

然后我们按照正常的代码编写如下:

import requests
from bs4 import BeautifulSoup# 地址仅供学习参考使用
url = 'https://www.eol.cn/html/en/cetwords/cet4.shtml'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
print(soup)

运行后的结果:部分截图

对比下上面的源码截图,会发现我们直接获取回来的中文内容全是乱码了,这不是我们想要的结果。那问题出在哪里呢?

【分析】

我们先看下代码中的r到底是什么编码方式,通过在r = requests.get(url)下方增加代码:

print(r.encoding)

运行后的结果:

很明显r(网页)的编码是ISO-8859-1模式,然后我们再看下源码的编码模式是:utf-8

【解决方法】

通过分析,我们知道当前页面的编码是ISO-8859-1,但是网页实际需要的是utf-8,那我们就使用上面学习的方法转码即可。

import requests
from bs4 import BeautifulSoup# 地址仅供学习参考使用
url = 'https://www.eol.cn/html/en/cetwords/cet4.shtml'
r = requests.get(url)
print(r.encoding)
r.encoding = 'utf-8'
print(r.encoding)
soup = BeautifulSoup(r.text, 'lxml')
print(soup)

运行结果 :

通过结果看到中文已经显示正常了。

3.2 情况二:encode或decode某个含有非法字符的字符串时报错

当我们在爬取某些网站时,无论是无意还是有意反爬,有可能该网页含有非法字符,这时我们使用str.decode('utf-8')就会得到下面的异常:

UnicodeDecodeError:‘utf-8’codec can't decode byte in position :illegal multibyte sequence

这就是咱们解码或转码的时候字符串含有非法字符导致的问题。

【解决方法】

在文中2.2也有提过 decode([encoding], [errors='strict']) 方法中的第二参数errors 默认是strict严格模式,报错立刻终止,就会导致主程序无法正常运行下去。errors有3个值,分别是:

①errors=ignore:直接忽略错误,强制转换,非法字符被直接移除。

②errors=replace:使用符号代替非法字符,会被转换成合适的ASCII字符。

③errors=xmlcharrefreplace:使用XML字符引用代替非法字符。

3.3 乱码情况三:写入或者读取文件时,文件字符串非正常的中文

在使用python读取和写入文件的时候建议一定要注明编码方式。往往导致报错都是因为编码的问题,下面我们看下案例。

3.3.1 txt文件和csv文件读取写入

我们先准备2个txt文件:

第一个命名为test_ansi.txt,创建记事本,内容为:“abc中文”,直接默认保存。

第二个命名为test_utf8.txt,直接从上面test_ansi.txt文件中点击另存为,保存时选择UTF-8编码。

然后我们尝试读取这两个文件内容:

str_ansi = open('test_ansi.txt', 'r').read()
print(str_ansi)
str_utf8 = open('test_utf8.txt', 'r').read()
print(str_utf8)

运行结果:

从结果我们看到第一个是能够正常运行的,而第二个报错:'gbk' codec can't decode byte 0xad in position 5: illegal multibyte sequence。

这是由于我们的windows系统默认使用的是简体中文版本,所以字符编码就是默认的GBK(也就是这里的ANSI),这就导致了第二个UTF-8编码读取失败。

【解决方法】

解决方法也很简单,在读取的时候添加encoding=‘相应的编码格式’,例如上面我们可以改成:

str_ansi = open('test_ansi.txt', 'r').read()
print(str_ansi)
str_utf8 = open('test_utf8.txt', 'r', encoding='utf-8').read()
print(str_utf8)

运行结果:

我们看到添加编码格式后两个读取都正常了。

写入保存报错一般如下即可:

add_content = '测试hello'
with open('test_utf8.txt', 'a+', encoding='utf-8') as f:f.write(add_content)f.close()

csv格式也是差不多的解决方法,这里就不再赘叙了。

3.3.2 json文件读取写入

对于json文件,当我们把带有中文的字符串数据保存到json文件时,默认会以Unicode编码处理。

import json
title = '测试json中文'
with open('test.json', 'a+', encoding='UTF-8') as f:json.dump([title], f)f.close()

运行结果:

会在本地生成一个test.json文件,然后我们点击test.json看下:

【解决方法】

这是因为默认使用了ASCII编码,而我们中文不在这种编码解析中,所以就会被转成16进制。那我们把默认的编码格式禁止掉,换成我们指定的不就好了,就需要用到 ensure_ascii=false 参数了。如下修改:

import json
title = '测试json中文'
with open('test.json', 'a+', encoding='UTF-8') as f:json.dump([title], f, ensure_ascii=False)f.close()

运行结果:

对比第一次运行的结果,我们第二次成功把中文写入json文件里面。

4 写在最后

希望大家能够通过上面的学习快速掌握并理解中文乱码的由来以及解决方法,不再像以前一样一知半解,可以通过理解怎么回事,触类旁通地解决编码问题。

以上就是作者给大家带来有关于python中文乱码的内容,常见案例目前就积累了3个,如果大家还有其他方面的中文乱码问题,欢迎下方留言,作者亲自帮你解决并把案例写进文章中供大家学习。

Python 爬虫 中文乱码一文通相关推荐

  1. python爬虫中文乱码解决方法

    python爬虫中文乱码解决方法 参考文章: (1)python爬虫中文乱码解决方法 (2)https://www.cnblogs.com/surecheun/p/9694052.html 备忘一下.

  2. Python爬虫中文乱码问题(爬虫乱码)

    在输出内容时,出现如下图的情况: 解决爬虫中文乱码的步骤 网址编码为gbk 查看网页源代码的head部分的编码: <meta http-equiv="Content-Type" ...

  3. python爬虫中文乱码_解决Python爬虫处理文件时候中文名称出现乱码问题

    当下如果需要批量处理文件,爬虫网页和图片的时候使用Python是最为简单和高效的.但是在处理过程中还是有一些细节问题,比如在爬虫中文名称和处理中文文件URL的时候会出现乱码.实际上就是因为编码的问题. ...

  4. python爬虫中文乱码_Python爬虫处理抓取数据中文乱码问题

    原博文 2013-12-17 17:15 − 乱码原因:因为你的文件声明为utf-8,并且也应该是用utf-8的编码保存的源文件.但是windows的本地默认编码是cp936,也就是gbk编码,所以在 ...

  5. 盘点3种Python爬虫 中文乱码 的处理方法

    人生苦短,快学Python! 给大家祭出网络爬虫过程中三种中文乱码的处理方案,希望对大家的学习有所帮助. 前言 前几天有个粉丝在Python交流群里问了一道关于使用Python网络爬虫过程中中文乱码的 ...

  6. python爬虫中文乱码_Python 爬虫过程中的中文乱码问题

    python+mongodb 在爬虫的过程中,抓到一个中文字段,encode和decode都无法正确显示 注:以下print均是在mongodb中截图显示的,在pythonshell中可能会有所不同 ...

  7. python爬虫中文乱码问题

    爬取网站,内容中的中文出现乱码,处理过程中的2个问题: 1.内容乱码,解析错误造成,首先要找到网页的正确编码,通过3条命令: print(res.encoding) print(res.apparen ...

  8. 解决爬虫中文乱码问题

    解决爬虫中文乱码问题 今天群里有个人反映某个网址爬出来的网页源代码出现中文乱码,我研究了半天,终于找到了解决方法. 一开始,我是这样做的: import requestsurl = 'http://s ...

  9. python爬虫爬取百度文档

    使用python爬虫爬取百度文档文字 话不多说,直接上代码! import requests import reheaders = {"User-Agent": "Moz ...

最新文章

  1. 对话高博(二)| 换工作这件事
  2. LaTeX入门第一集!LaTeX下载资源分享!LaTeX教学资源分享!TeXstudio下载资源分享!
  3. mysql中两根竖线什么意思_SQL如何查询表字段值以竖线分割的数据
  4. MybatisPlus代码生成器配置
  5. VBS中MSGBOX用法
  6. JSON-B非对称属性绑定
  7. Linux中变量$#,$@,$0,$1,$2,$*,$$,$?的含义
  8. SpringBoot项目的mybatis逆向工程
  9. sql 基础知识普及
  10. 瑞友天翼服务器ip地址怎么修改,瑞友天翼6.0版本iphone移动客户端操作手册
  11. 使用VUE分分钟写一个验证码输入组件
  12. uni-app android权限
  13. 算法题 - 卡牌游戏问题 - Python
  14. 【电脑桌面不见了怎么办】
  15. vue 全局/局部组件
  16. 检测ip是否为中国php,PHP判断IP是中国IP还是外国IP
  17. 史上最牛的Linux视频教程—兄弟连Linux笔记
  18. 学科实践活动感悟50字_社会实践心得体会50字
  19. django+pyecharts制作工单系统实时刷新可视化仪表盘并设置报表定时发送
  20. 运维专家写给年轻运维的6条人生忠告

热门文章

  1. 从前后端的角度分析options预检请求——打破前后端联调的理解障碍
  2. linux开发环境工具
  3. goLang 如何开发 windows 窗口界面
  4. Ubuntu16.04安装VSCode,并修改系统界面和编辑面板字体大小
  5. 华峰氨纶,昨日黄花?
  6. 国家开放大学2021春1248公共部门人力资源管理题目
  7. 硬核小学生:玩自己写的游戏,未来想造机器人
  8. Tesseract的所有参数
  9. Unity_安卓(Android)端AVProVideo插件播放不了视频问题解决
  10. TSQL中PERCENT的用法