你是否遇到过这种情况?收到同事发来的一个 CSV 文件,用 Excel 打开一看,全是方块和问号,中文全变乱码了。当时第一反应是文件传输出了问题,结果人家原文件打开好好的,就我这打开就炸。后来搞明白,这不是文件坏了,是编码不一致。Python 处理 CSV 的时候,编码问题是最容易被忽略,又最难排查的坑。今天把最常见的 5 种乱码场景一次性讲清楚。
坑 1:Windows 存的 CSV,Python 读就报 UnicodeDecodeError
出问题的代码:
import pandas as pddf = pd.read_csv('data.csv')
报错:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb5 in position 0
Windows 系统默认用 GBK 编码保存文件,但 pandas 默认用 UTF-8 读取。
编码不匹配,直接报错。你以为是文件损坏了,其实只是编码格式不一样。
修复方法:
# 先试 GBK(Windows 中文系统最常见)df = pd.read_csv('data.csv', encoding='gbk')# 如果还不行,试 gb18030(GBK 的超集,兼容更多字符)df = pd.read_csv('data.csv', encoding='gb18030')
翻车现场:有一次从财务那边拿到一份报表 CSV,用 Python 读直接报错。试了 UTF-8 不行,试了 GBK 还是不行,最后发现是 GB18030。折腾了半小时,就因为一个编码参数。
坑 2:文件能读了,但中文变成 ,,,
出问题的代码:
df = pd.read_csv('data.csv', encoding='utf-8')print(df.head())# 丕æ\u0087å\x8d\u0088ç\x95\x8c# 0 ,,,
代码没报错,但数据全是乱码。
原因是文件实际上不是 UTF-8,而是 GBK 编码,但 pandas 没有抛异常,因为 GBK 的某些字节碰巧被当成了合法的 UTF-8 序列,只是解析出来的内容完全不对。
修复方法:
# 用 errors='replace' 或 'ignore' 先看个大概with open('data.csv', 'r', encoding='gbk', errors='replace') as f: print(f.readline())# 确认编码后再正常读取df = pd.read_csv('data.csv', encoding='gbk')
翻车现场:这种坑最恶心,不报错,结果静默错误。你读了 1000 行数据,看起来格式都对,但中文全是乱码。等你拿去做分析才发现,数据早就废了。
坑 3:UTF-8 和 UTF-8-BOM,傻傻分不清
出问题的代码:
df = pd.read_csv('data.csv', encoding='utf-8')print(df.columns[0]) # 姓名
文件确实是 UTF-8 编码,但多了一个 BOM(Byte Order Mark)头。
Excel 保存 CSV 时经常会加这个标记,Python 读取时把它当成列名的一部分,第一列就变成 姓名。
修复方法:
# 用 utf-8-sig 编码,自动处理 BOMdf = pd.read_csv('data.csv', encoding='utf-8-sig')print(df.columns[0]) # 姓名
翻车现场:这个坑很隐蔽,你的代码在本地跑得好好的,换一台电脑就不行了。因为不同电脑的 Excel 版本不同,有的加 BOM 有的不加。你以为是环境问题,其实是编码差了一个字节。
坑 4:JSON 里混了 BOM,解析直接炸
出问题的代码:
import jsonwith open('config.json', 'r', encoding='utf-8') as f: data = json.load(f)# JSONDecodeError: \ufeff
JSON 文件是 UTF-8 编码,但开头有个 BOM 标记。
Python 的 json 模块不认 BOM,直接报解析错误。这种文件用文本编辑器打开看不出任何异常,但 Python 就是读不了。
修复方法:
# 用 utf-8-sig 读取,自动跳过 BOMimport jsonwith open('config.json', 'r', encoding='utf-8-sig') as f: data = json.load(f)
翻车现场:有一次用 Python 读一个 JSON 配置文件,反复报 JSONDecodeError。用 cat 查看文件内容,肉眼看不到任何问题。最后用 hexdump 一查,文件头有两个隐藏字节 EF BB BF——就是 BOM。这种坑你靠看代码根本看不出来。
坑 5:从网页抓下来的 CSV,编码和你想的不一样
出问题的代码:
import requestsresp = requests.get('https://example.com/data.csv')withopen('data.csv', 'w') as f: f.write(resp.text)df = pd.read_csv('data.csv', encoding='utf-8')# 可能乱码,也可能报错
网页返回的 CSV 文件,编码声明可能和实际编码不一致。
比如 HTTP 头说 charset=utf-8,但文件实际是 GBK,或者文件根本没有编码声明,你只能猜。
修复方法:
import requestsresp = requests.get('https://example.com/data.csv')# 优先用 apparent_encoding 检测实际编码resp.encoding = resp.apparent_encodingcontent = resp.textwith open('data.csv', 'w', encoding='utf-8') as f: f.write(content)# 或者直接用二进制读取,自己判断编码raw = resp.contentfor enc in ['utf-8-sig', 'utf-8', 'gbk', 'gb18030']: try: text = raw.decode(enc) break except UnicodeDecodeError: continue
翻车现场:爬了一个政府网站的数据,HTTP 头写的是 UTF-8,但文件实际是 GBK。用 resp.text 直接拿到的就是乱码,后来才知道,很多老系统根本不规范,编码声明形同虚设。
以上 5 个坑,核心就一个字:编码不一致。
Windows 默认 GBK,Linux/Mac 默认 UTF-8,Excel 喜欢加 BOM,网页可能乱标编码。Python 处理文件时,编码是最容易被忽略的一层。
记住一条铁律:读 CSV 永远手动指定 encoding 参数,别靠默认值猜。utf-8-sig 是万能后手,解决 90% 的 BOM 问题。
评论区聊聊:你被乱码坑过最惨的一次是什么情况?
Python/ML/DL/大模型都折腾过,坑也踩了不少。