(比如网页源码、API返回的JSON数据)显示为乱码时,乱码的根本原因是 编码不匹配。

就是服务器告诉你的数据是某种编码(ISO-8859-1),但你用另一种编码(UTF-8)去尝试解读它,结果自然就是乱码。
requests 库为我们提供了多种方法来处理和解决解码问题。
核心概念:requests.Response 对象的编码属性
当你使用 requests 发送请求并得到一个响应对象 response 后,这个对象有一个非常重要的属性 response.encoding。
response.encoding的作用:它告诉 Python 应该用哪种字符编码来解码response.content(响应的二进制内容)。response.text的工作原理:当你访问response.text时,requests内部会执行类似response.content.decode(response.encoding)的操作,将二进制内容转换成 Unicode 字符串。
关键点:response.encoding 的值有两个来源,按优先级顺序:

- 从 HTTP 响应头中自动推断:
requests会首先查看服务器返回的 HTTP 头部信息中的Content-Type字段,如果这个字段包含了charset参数(Content-Type: text/html; charset=utf-8),requests就会使用这个charset值来设置response.encoding,这是最理想的情况。 - 默认值
ISO-8859-1:HTTP 头部没有提供charset信息,requests会默认将response.encoding设置为ISO-8859-1。这是一个常见的乱码来源,因为ISO-8859-1只能处理有限的字符,而很多网站(尤其是中文网站)实际使用的是UTF-8。
如何解决解码问题(从易到难)
下面我们介绍几种处理解码问题的方法,从最简单到最可靠。
手动设置 response.encoding (最常用)
这是最直接、最常用的方法,当你发现页面乱码时,通常是因为服务器没有正确声明 charset 或者声明错误,你可以通过检查网页源码来确定正确的编码,然后手动告诉 requests。
场景:抓取一个没有正确声明 charset 的网页,导致 response.text 出现乱码。
步骤:

- 发送请求,获取
response对象。 - 检查
response.encoding的值,看看是不是默认的ISO-8859-1。 - 根据实际情况(或通过查看网页源码
<meta>标签),手动将response.encoding设置为正确的编码,'utf-8'、'gbk'、'gb2312'等。 - 再次访问
response.text就是正确的了。
示例代码:
import requests
# 假设这个网站没有在 HTTP 头中声明 charset,或者声明错误
url = 'https://example.com/some-chinese-page' # 替换为一个可能出问题的网址
try:
response = requests.get(url, timeout=10)
# 1. 检查原始编码
print(f"服务器原始编码推断值: {response.encoding}") # 很可能输出 'ISO-8859-1'
# 2. 尝试直接获取 text,可能会得到乱码
# print(response.text)
# 3. 手动设置正确的编码 (通过查看网页源码发现是 gbk)
# 你可以通过浏览器右键 -> 查看网页源码,找到 <meta charset="gbk"> 这样的标签
response.encoding = 'gbk'
# 4. 再次获取 text,此时就是正确解码后的内容
print(response.text)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
使用 response.content 和 decode() (更底层)
response.encoding 可能会因为某些原因无法正确设置,这时,你可以绕过 response.encoding,直接获取原始的二进制内容,然后使用 Python 内置的 decode() 方法进行解码。
场景:当 response.encoding 的值不准确,你确信自己知道正确的编码时。
步骤:
- 获取
response.content(这是一个bytes对象)。 - 直接对这个
bytes对象调用.decode('正确的编码')。
示例代码:
import requests
url = 'https://example.com/some-chinese-page'
try:
response = requests.get(url)
# 直接获取二进制内容
content_bytes = response.content
# 手动解码,假设我们知道是 utf-8
decoded_text = content_bytes.decode('utf-8')
print(decoded_text)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except UnicodeDecodeError as e:
print(f"解码失败,请确认编码是否正确: {e}")
使用 chardet 库自动检测编码 (最智能)
如果你不确定一个未知来源的网页或文件是什么编码,可以使用 chardet 库来自动检测其编码。chardet 是一个非常流行的第三方库,专门用于检测字符编码。
首先需要安装 chardet:
pip install chardet
场景:处理来源不明的文本数据,需要自动判断其编码。
步骤:
- 安装并导入
chardet。 - 获取
response.content。 - 使用
chardet.detect()函数检测content的编码。 - 使用检测到的编码来解码内容。
示例代码:
import requests
import chardet
url = 'https://example.com/some-chinese-page'
try:
response = requests.get(url)
# 1. 获取二进制内容
content_bytes = response.content
# 2. 使用 chardet 检测编码
# chardet.detect() 返回一个字典,{'encoding': 'gbk', 'confidence': 0.99}
detected_result = chardet.detect(content_bytes)
encoding = detected_result['encoding']
confidence = detected_result['confidence']
print(f"检测到的编码: {encoding}, 置信度: {confidence}")
# 3. 根据检测结果进行解码
if confidence > 0.9: # 设置一个置信度阈值,避免错误解码
decoded_text = content_bytes.decode(encoding)
print(decoded_text)
else:
print("置信度过低,无法确定编码。")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except UnicodeDecodeError as e:
print(f"使用检测到的编码 {encoding} 解码失败: {e}")
总结与最佳实践
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
手动设置 response.encoding |
简单、直接、高效 | 需要预先知道或查证正确的编码 | 最常用,适用于绝大多数你知道或能查到编码的网站。 |
使用 response.content.decode() |
灵活,绕过 requests 的默认逻辑 |
需要手动指定编码,容易出错 | 当 response.encoding 不可靠,且你确信自己知道编码时。 |
使用 chardet 自动检测 |
自动化,无需人工判断编码 | 依赖第三方库,检测可能不完全准确,有性能开销 | 适用于处理来源不明的、编码未知的文本数据。 |
最佳实践流程:
- 首选
response.text:直接使用response.text,让requests自动处理,大多数情况下(如Content-Type声明了charset)这是没问题的。 - 检查乱码:如果发现
response.text有乱码,立即检查response.encoding的值。 - 手动修正:
response.encoding是ISO-8859-1或其他明显错误的值,最佳做法是手动设置为正确的编码(如'utf-8'),这是最可靠、最常用的解决方案。 - 终极手段:如果你处理的是大量未知来源的文本,或者不想手动去查每个网站的编码,那么集成
chardet是一个非常好的自动化方案。
通过以上方法,你就可以轻松应对 requests 中遇到的各种解码问题了。
