杰瑞科技汇

Python requests如何正确解码响应内容?

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

Python requests如何正确解码响应内容?-图1
(图片来源网络,侵删)

就是服务器告诉你的数据是某种编码(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 的值有两个来源,按优先级顺序:

Python requests如何正确解码响应内容?-图2
(图片来源网络,侵删)
  1. 从 HTTP 响应头中自动推断requests 会首先查看服务器返回的 HTTP 头部信息中的 Content-Type 字段,如果这个字段包含了 charset 参数(Content-Type: text/html; charset=utf-8),requests 就会使用这个 charset 值来设置 response.encoding,这是最理想的情况。
  2. 默认值 ISO-8859-1:HTTP 头部没有提供 charset 信息,requests 会默认将 response.encoding 设置为 ISO-8859-1这是一个常见的乱码来源,因为 ISO-8859-1 只能处理有限的字符,而很多网站(尤其是中文网站)实际使用的是 UTF-8

如何解决解码问题(从易到难)

下面我们介绍几种处理解码问题的方法,从最简单到最可靠。

手动设置 response.encoding (最常用)

这是最直接、最常用的方法,当你发现页面乱码时,通常是因为服务器没有正确声明 charset 或者声明错误,你可以通过检查网页源码来确定正确的编码,然后手动告诉 requests

场景:抓取一个没有正确声明 charset 的网页,导致 response.text 出现乱码。

步骤

Python requests如何正确解码响应内容?-图3
(图片来源网络,侵删)
  1. 发送请求,获取 response 对象。
  2. 检查 response.encoding 的值,看看是不是默认的 ISO-8859-1
  3. 根据实际情况(或通过查看网页源码 <meta> 标签),手动将 response.encoding 设置为正确的编码,'utf-8''gbk''gb2312' 等。
  4. 再次访问 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.contentdecode() (更底层)

response.encoding 可能会因为某些原因无法正确设置,这时,你可以绕过 response.encoding,直接获取原始的二进制内容,然后使用 Python 内置的 decode() 方法进行解码。

场景:当 response.encoding 的值不准确,你确信自己知道正确的编码时。

步骤

  1. 获取 response.content(这是一个 bytes 对象)。
  2. 直接对这个 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

场景:处理来源不明的文本数据,需要自动判断其编码。

步骤

  1. 安装并导入 chardet
  2. 获取 response.content
  3. 使用 chardet.detect() 函数检测 content 的编码。
  4. 使用检测到的编码来解码内容。

示例代码

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 自动检测 自动化,无需人工判断编码 依赖第三方库,检测可能不完全准确,有性能开销 适用于处理来源不明的、编码未知的文本数据。

最佳实践流程

  1. 首选 response.text:直接使用 response.text,让 requests 自动处理,大多数情况下(如 Content-Type 声明了 charset)这是没问题的。
  2. 检查乱码:如果发现 response.text 有乱码,立即检查 response.encoding 的值。
  3. 手动修正response.encodingISO-8859-1 或其他明显错误的值,最佳做法是手动设置为正确的编码(如 'utf-8'),这是最可靠、最常用的解决方案。
  4. 终极手段:如果你处理的是大量未知来源的文本,或者不想手动去查每个网站的编码,那么集成 chardet 是一个非常好的自动化方案。

通过以上方法,你就可以轻松应对 requests 中遇到的各种解码问题了。

分享:
扫描分享到社交APP
上一篇
下一篇