乱码本质是response.content解码时编码不匹配,应优先用content手动解码,按响应头→HTML meta→charset_normalizer顺序确定编码,设encoding必须在首次访问.text前,否则无效。

乱码不是网页有问题,而是 Python 把字节流错误映射成了字符串——关键在 response.content 到 str 这一步没对上编码。
requests.text 为什么一用就乱?
response.text 是 requests 自动调用 response.content.decode(response.encoding) 的结果,而 response.encoding 的推导顺序是:Content-Type 响应头 > HTML <meta> 标签 > chardet。任意一环出错(比如老站声明 charset=utf-8 实际发的是 gbk),response.text 就不可信,且改 response.encoding 后再读 .text 不会重解码。
- 设
response.encoding必须在首次访问.text之前,之后设等于白设 -
response.apparent_encoding是内置的chardet粗略检测,中文页面上经常不准(比如把gb18030误判成utf-8) - 很多老旧站点 HTTP 头里压根不带
charset,或写成charset=gb2312但实际用gbk存储,requests默认 fallback 到ISO-8859-1,必然全乱
怎么安全地从 content 解码出正确字符串?
手动解码才是可控路径,但不能瞎试。得按可信度降序取编码源:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 先查响应头:
response.headers.get('content-type', ''),正则提取charset=([^;]+) - 再查 HTML
<meta>:用re.search(rb'<meta>]*?charset=[\'"]?([^\'">]+)', response.content[:10240]),只搜前 10KB 避免慢 - 最后 fallback 到
charset_normalizer(比chardet更准更快,尤其对中文):from charset_normalizer import from_bytes; r = from_bytes(response.content); encoding = r[0].confidence > 0.7 and r[0].encoding or 'gb18030' - 解码时务必加
errors='replace'或errors='ignore',防止个别坏字节崩掉整个解析
保存文件还是乱码?那是另一回事
写文件乱码和爬取乱码是两件事:前者是 Python 写入时用了错误编码,后者是读取时解错了。
- 用
open(..., 'w')必须显式传encoding='utf-8',Python 默认编码不一定是 UTF-8 - 存 CSV 给 Excel 看,一定要用
encoding='utf-8-sig',否则首列多出\ufeff - 如果原始内容是
gbk编码,又想存成 UTF-8 文件,别用str.encode().decode()转换,直接:text_gbk = response.content.decode('gbk'); text_utf8 = text_gbk.encode('utf-8').decode('utf-8') - 用
csv.writer时,newline=''必须带上,否则 Windows 下会多空行
最常被忽略的一点:代理中间件可能篡改 Content-Type 头,尤其是缓存型代理;即使用了隧道代理,源站本身的编码声明冲突也依然存在,所以“智能探测”不能只做一次,要分段、可降级、带 fallback。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










