Python:爬虫乱码

一、预备知识

进制

  • 十进制(0-9):
    0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9,
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  • 四进制(0-3):
    0, 1, 2, 3,
    10, 11, 12, 13,
  • 二进制(0-1):
    0, 1,
    10, 11,

n进制就是每一个位置只能表示0~n-1,到了n之后向前进位,通过一系列连续的位置来表示一个数字
e.g. 十进制的4 – 四进制的10 – 二进制的100
我们在使用计算机时,看到和输入的是十进制,但计算机底层(存储、网络传输)是采用二进制来存储数据的

位(bit)与字节(Byte)

  • bit:一个0或1
    • 上面说的一个位置,就是1bit;
    • 计算机中最小的数据单位,1bit代表1个二进制位,0101大小就是4bit。
  • Byte:8个连续的0或1
    • 计算机中存储、处理数据的基本单位;
    • 1bit有1个位置,能表示0或1
      2bit有2个位置,能表示2^2即4种状态

      8bit有8个位置,能表示2^8即128种状态
    • 1Byte由8bit组成。各种数据在计算机中存储、处理的单位都是字节,一个数字/符号/文字/图片/视频等,其大小一定是整数倍的Byte

编码/解码

计算机底层只认识0和1,所以计算机存储、网络传输的并不是我们看到的数据的样子,而是一系列的0和1,这一系列的0和1,一般称之为字节流

1、编码:将数据转化为字节流,进行存储和网络传输;
2、解码:将字节流转化为数据本身,以供阅读/使用/观看。

  • 数字:数字的编码是十进制转化为二进制、解码是二进制转化为十进制,也就是进制的转化;
  • 字符(汉字、标点、符号、…)/图片/视频:相对复杂,有不同的解码规则与方法

二、编解码方式(以文本/字符串编解码为例)

规则

要求:将某个字符编码为二进制,之后可以将该二进制在转化为该字符

  • 字符与二进制要有固定、唯一的对应关系

    • 特定的字符只能编码为唯一、确认的二进制字节流
    • 这个二进制字节流只能解码为特定的字符
  • 需要一个大家认可的字典/规范,规定这种对应关系

  • 字符集(记录全部的字符)+ 该字符集对应的编解码方式(字符与二进制的对应关系)

    • 一种字符集可能有多种编解码的方式;
      或者说,不同的编解码方式,可能采用同一种字符集。

1. ASCII字符集——ASCII编/解码

  • ASCII字符集:共定义了128个字符。
    大写字母26个,小写字母26个,0-9阿拉伯数字(字符),所有的英文标点符号,数学运算符号,其他特殊符号以及控制码
  • ASCII编/解码:ASCII字符集中的每个字符与二进制字节流的对应关系。
    全部都是用1个字节(Byte)/8bit 标识一个字符,如 'A’被编码为0100 0001

2. GBK字符集——GBK编/解码

  • GBK字符集:在ASCII字符集的基础上,增加了简体汉字、繁体汉字、数学符号、罗马字母、希腊字母等。

  • GBK编/解码:GBK字符集中每个字符与二进制字节流的对应关系。

    • ASCII字符集中的字符用1个字节(Byte)/8bit 标识,并且对其ASCII编码,如 0100 0001还是表示’A’;
    • 不在ASCII字符集中的字符,都用2个字节(Byte)/16bit来标识,如1101 0000 1110 1100表示’徐’。

3. Unicode字符集——UTF-8编/解码(最通用)

  • Unicode字符集:为了解决传统的字符编码方案的局限性而产生。包含了每种语言的每个字符,以满足跨语言、跨平台进行文版转换、处理的需求,适应全球化的发展。

  • UTF-8编/解码:Unicode字符集中每个字符与二进制字节流的对应关系。(还有很多其他的编码方式也采用了Unicode字符集,如 UTF-32、UTF-16等)。

    • ASCII字符集中的字符用1个字节(Byte)/8bit 标识,并且对其ASCII编码,如 0100 0001还是表示’A’;
    • 部分字符用2个字节(Byte)/16bit来标识,如1100 1111 1000 1111表示ⱪ;
    • 中文字符一般用3个字节(Byte)/24bit来标识,如1110 0101 1011 1110 1001 0000表示’徐’。

4. 总结

  • 在所有的编解码方式中,ASCII码字符对应的二进制表示都是一样的。
  • 编、解码要相对应,才能不损失数据原本的意义,我们才不会误解数据;
    数据以编码方式1进行编码的到字节流,那么这段字节流必须以对应的解码方式1进行解码,才可以得到原始的数据;
    否则这段字节流可能会:1、解码成别的数据(按照解码方式2,这一段二进制位对应了别的字符);2、解码失败(按照解码方式2,这一段二进制位可能不对应任何字符)。

三、Python操作编解码

Python中的bytes与str

一个str一定能编码成二进制,因为组成str的字符一定在Unicode字符集中。

  • bytes:字节流/比特流
    bytes就是一系列二进制位,也就是说,bytes是0101 0001,但Python中通过十六进制的形式来表示

    • Python的IDE中展示bytes类型的方式是b’\x~';
    • 在此基础上,由于在所有的编解码方式中,ASCII码字符对应的二进制表示都是一样的,所以如果一段字节流中有ASCII字符,则直接将该ASCII字符展示出来;否则还是展示十六进制数字。
    • Python中看到的bytes对象有两个样子:b’ascii字符’;b’\x十六进制数字’。

一段二进制不一定能解码成str。

如果想在Python中直接声明一个bytes对象:

  • b’\x十六进制’:b’\x61’
  • b’ascii字符’:b’\a’

print一个bytes对象:

  • b’\x十六进制’形式:print(b’\x61’)

    • 如果对应ascii字符:则直接转换成b’ascii字符’的形式
    • 否则:原样输出
  • b’ascii字符’形式:print(b’\a’)

    • 原样输出

在这里插入图片描述
在这里插入图片描述

Python演示

  • 方法

    • 编码:

      • bytes(str, ‘编码方式’)
      • str.encode(‘编码方式’)
    • 解码:

      • 字节流.decode(‘解码方式’)
  • 编码

    • ASCII编码
      在这里插入图片描述
    • GBK编码
      在这里插入图片描述
    • UTF-8编码
      在这里插入图片描述
  • 编解码练习
    在这里插入图片描述

    在这里插入图片描述
    b1三个字节,gbk解码时一个中文占2个字节,这时会认为少了一个字节所以报错。s2六个字节则不会报错。在这里插入图片描述

四、爬虫、保存数据过程

请求网络,拿到Response,Response中包含了二进制字节流/bytes

  1. 字节流 —> 变成字符串(解码):需要知道相应的编码方式,按照给定的编码方式,解码出字符串
  2. 字符串 —> 本地txt文档(编码):按照UTF-8编码,保存到本地txt文档
  3. 本地txt文档 —> 字符串(解码):按照UTF-8解码,读取本地txt文档

用软件打开本地的txt文档,也是以某种编解码方式进行的,一般和系统默认的编解码方式有关:可以抛弃原生txt文本编辑器,选用VSCode或nodepad++

1.Response --> str

(1)HTTP Response对象

在这里插入图片描述

  • headers: 响应头
    在这里插入图片描述

{
‘Date’: ‘Thu, 13 Oct 2022 16:17:47 GMT’,
‘Content-Type’: ‘text/html; charset=utf-8’,
‘Transfer-Encoding’: ‘chunked’,
‘Connection’: ‘keep-alive’,
‘Keep-Alive’: ‘timeout=30’,
‘X-Xss-Protection’: ‘1; mode=block’,
‘X-Douban-Mobileapp’: ‘0’,
‘Expires’: ‘Sun, 1 Jan 2006 01:00:00 GMT’,
‘Pragma’: ‘no-cache’,
‘Cache-Control’: ‘must-revalidate, no-cache, private’,
‘X-DAE-App’: ‘movie’,
‘X-DAE-Instance’: ‘default’,
‘Set-Cookie’: ‘bid=tGj9VMzEG8M; Expires=Fri, 13-Oct-23 16:17:47 GMT; Domain=.douban.com; Path=/’,
‘X-DOUBAN-NEWBID’: ‘tGj9VMzEG8M’,
‘Server’: ‘dae’,
‘Strict-Transport-Security’: ‘max-age=15552000’,
‘X-Content-Type-Options’: ‘nosniff’,
‘Content-Encoding’: ‘gzip’
}

i) ‘Content-Type’: ‘text/html; charset=utf-8’
响应体的媒体类型(类型和编码),确定了接收方以什么类型、什么编码读取响应体。

application/x-www-form-urlencoded
multipart/form-data
application/json
text/xml

ii) ‘Content-Encoding’: ‘gzip’
响应体的压缩方式(不同压缩算法),确定了接收方以什么样的方式解压响应体。

gizp
compress
deflate
identity
  • content:响应体
    响应主体的二进制内容,即bytes类型。
    在这里插入图片描述
  • encoding: ‘utf-8’
    返回用于解码 response.content 的编码方式
    response.encoding 是response headers响应头 Content-Type字段 charset 的值。
    response.encoding 是从http协议中的response headers响应头中的charset字段中提取的编码方式;若response headers响应头中没有charset字段,则服务器响应的内容默认为ISO-8859-1 编码模式【使用此编码方式无法解析中文内容,会造成响应体乱码(解析为乱码数据)】
  • apparent_encoding: ‘utf-8’
    自动的从服务器接口响应的内容中(响应体)分析内容编码的方式,所以apparent_encoding 比encoding更加准确。当网页或者接口响应内容出现乱码时可以把 apparent_encoding 的编码格式赋值给encoding。
  • text
    将response.content进行解码的字符串,解码需要制定一个编码方式,requests会根据自己的猜测来判断编码的方式,所以有时候可能会猜测错误,就会导致解码产生乱码。
    在这里插入图片描述

(2)代码

  • text = response.text:
    将response.content进行解码,requests会根据自己的猜测来判断编码的方式,所以有时候可能会猜测错误,就会导致解码产生乱码。

  • ==> text = response.content.decode(response.encoding):
    是response headers响应头 Content-Type 字段 charset 的值;
    若response header响应头中没有charset字段,则服务器响应的内容默认为 ISO-8859-1 编码模式,使用此编码方式无法解析中文内容,会造成响应体乱码(解析为乱码数据)

  • ==> text = response.content.decode(apparent_encoding):
    自动的从服务器接口响应的内容中(响应体)分析内容编码的方式,所以比 encoding 更加准确

(3)乱码案例

r = requests.get('https://www.baidu.com/')
print(r.text)	# 乱码

print(r.content.decode(response.encoding))	# 乱码
print(r.encoding)	# ISO-8859-1
print(r.headers('Content-Type'))	# 'text/html'

print(r.content.decode(response.apparent_encoding))		# 中文
print(r.apparent_encoding)	# utf-8

2. str --> 本地

with open(sourcePath, 'w', encoding='utf-8') as f:
    f.write(text)
    f.close()

3. 本地 --> str

f = open(sourcePath, encoding='utf-8')
content = f.read()
print(content)
f.close()
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python网络爬虫过程中,遇到汉字乱码问题是比较常见的情况。根据引用\[1\]中提到的方法,我可以给你提供一些解决乱码问题的方法。 首先,你可以尝试使用引用\[2\]中的方法,即对于编码为utf-8的网址,进行两次重编码。你可以使用requests库发送请求,并在获取到的响应中设置编码为'GBK',然后再将编码设置为'utf-8'。这样可以解决一些网页中文乱码的问题。 另外,你还可以尝试使用其他的编码方式来解决乱码问题。比如,可以尝试将编码设置为'gb2312',如引用\[2\]中提到的方法。这种方法适用于网址编码为'gb2312'的情况。 综上所述,解决Python爬虫中文乱码问题的步骤可以总结为: 1. 使用requests库发送请求获取网页内容。 2. 根据网页编码设置响应的编码方式,可以尝试设置为'GBK'或'gb2312'。 3. 如果仍然存在乱码问题,可以尝试进行多次编码转换,如将编码设置为'utf-8'。 希望以上方法能够帮助你解决Python爬虫中文乱码问题。如果还有其他问题,请随时提问。 #### 引用[.reference_title] - *1* [盘点3种Python网络爬虫过程中的中文乱码的处理方法](https://blog.csdn.net/i54996/article/details/120749614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Python爬虫中文乱码问题](https://blog.csdn.net/wvqusrtg/article/details/113742520)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值