应优先用 response.content 手动解码,按 utf-8→gbk→gb2312 顺序尝试,避免依赖 response.text 或 apparent_encoding;设 response.encoding 必须在首次访问 response.text 前。

requests.get() 返回的 response.text 是乱码,怎么办?
requests 默认用 ISO-8859-1 解码响应体,而绝大多数中文网页实际是 UTF-8 或 GBK。直接读 response.text 就会错乱,尤其遇到 Content-Type 里没写 charset、或写错了的时候。
- 先别碰
response.text,改用response.content(原始字节) - 手动指定编码:先猜再试,优先用
response.apparent_encoding(基于 chardet 的启发式判断) - 但
apparent_encoding不可靠,比如 GBK 页面可能被误判成Windows-1254;更稳妥的是从 HTML 的<meta charset="...">或<meta http-equiv="Content-Type" content="text/html; charset=...">里提取
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.content, 'lxml')
encoding = soup.find('meta', attrs={'charset': True})
if encoding:
real_encoding = encoding.get('charset')
else:
meta = soup.find('meta', attrs={'http-equiv': 'Content-Type'})
if meta and 'charset=' in meta.get('content', ''):
real_encoding = meta.get('content').split('charset=')[-1].split(';')[0].strip()
用 BeautifulSoup 解析时显示 ,是不是编码没设对?
是,而且问题常出在两处:传入的字节流本身没解对,或者 BeautifulSoup 构造时没显式指定 from_encoding。
如果你已经拿到
response.content,直接传给BeautifulSoup,它会自己探测编码 —— 但探测失败率高,尤其小页面或无 meta 标签时-
显式传参更可控:
BeautifulSoup(response.content, 'lxml', from_encoding='utf-8')(注意:这里必须是字符串名,不是utf_8这种下划线形式)立即学习“Python免费学习笔记(深入)”;
别用
response.text再喂给BeautifulSoup,二次解码容易雪上加霜常见错误现象:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position ...→ 说明当前解码方式和真实编码不匹配使用场景:抓取国内新闻站、政府网站、老论坛,大概率是
GBK或GB2312,utf-8反而是少数性能影响:显式指定编码比让 BS4 自己探测快,也避免因探测失败导致解析中断
chardet.detect() 返回 confidence 只有 0.5,还敢用吗?
不敢直接信。0.5 意味着几乎是在抛硬币,尤其对短文本(比如只有 <meta> 标签的响应头)、纯 ASCII 内容,chardet 容易误判。
-
chardet.detect()最适合辅助判断,而不是最终决策依据 - 实操建议:先尝试常见编码列表按顺序解码,捕获
UnicodeDecodeError,直到成功为止 - 推荐顺序:
utf-8→gbk→gb2312→big5(繁体)→latin-1(兜底,不会报错但可能乱)
for enc in ['utf-8', 'gbk', 'gb2312']:
try:
text = response.content.decode(enc)
break
except UnicodeDecodeError:
continue
为什么有些页面用 response.encoding = 'gbk' 后,response.text 还是乱?
因为 response.encoding 是 requests 的“记忆”,设了它只影响后续对 .text 的访问,不改变已缓存的解码结果。如果你在设 encoding 之前已经访问过 response.text,requests 就按旧编码解了一次并缓存了,再改 encoding 也无效。
- 正确做法:在第一次访问
response.text前,就设置好response.encoding - 更推荐的做法:压根不用
.text,全程操作.content+ 手动.decode(),完全绕过 requests 的自动解码逻辑 - 容易踩的坑:写完
response.encoding = 'gbk'就以为万事大吉,结果调试时发现前面某行已经触发了response.text访问
乱码问题从来不是单一环节的事:HTTP 头、HTML meta、实际字节流、解码时机、库的缓存策略,全得串起来看。最省事的路径,其实是放弃依赖任何自动探测,拿到字节后,按确定的编码列表逐个试解 —— 看似笨,但稳定。










