on_bad_lines参数仅支持"error"(默认报错)、"warn"(警告并跳过)、"skip"(静默跳过)三个值,且必须配合engine="python"使用,C引擎不支持该参数。

on_bad_lines参数在pandas.read_csv中到底支持哪些值
on_bad_lines 是 pandas 3.0+ 新增的关键字参数,用于控制 CSV 解析遇到格式异常行(比如字段数不匹配、引号未闭合)时的行为。它只在 engine="python" 下生效(默认 engine="c" 不支持该参数,强行传入会报 ValueError: Invalid parameter "on_bad_lines" for engine "c")。
可用值只有三个:"error"(默认,抛 ParserError)、"warn"(打印警告并跳过)、"skip"(静默跳过)。注意:没有 "ignore" 或 "continue" 这类别名,写错会直接报 ValueError: on_bad_lines must be 'error', 'warn', or 'skip'。
为什么设了on_bad_lines="skip"还是报错
最常见原因是没显式指定 engine="python"。pandas 默认用 C 引擎解析,而 C 引擎完全不识别 on_bad_lines 参数——它要么成功,要么崩溃,没有“跳过”逻辑。
必须同时满足两个条件才真正生效:
立即学习“Python免费学习笔记(深入)”;
-
on_bad_lines设为"warn"或"skip" -
engine="python"显式传入
示例正确写法:
df = pd.read_csv("data.csv", on_bad_lines="skip", engine="python")漏掉 engine="python" 就会触发报错而非跳过。
用on_bad_lines="skip"时,哪些异常行真能被跳过
engine="python" + on_bad_lines="skip" 能处理的仅限于“行结构错误”,典型包括:
使用 qbo-mileage CLI 及用户凭证,从 Airtable、Outlook 或 Google Calendar 记录生成 QuickBooks Online 里程 CSV 文件。
- 某行字段数与表头不一致(如 header 有 5 列,某行只写了 3 个逗号分隔值)
- 某行存在未闭合的双引号(
"value1","unterminated value) - 换行符出现在 quoted 字段内(但文件本身用 \n 分割行)
它**不能**处理以下情况:
- 编码错误(如文件是 GBK 却用 utf-8 打开 → 报
UnicodeDecodeError) - 空文件或首行为空 → 报
EmptyDataError - 列名重复 → 报
DuplicateLabelError(发生在解析后,不在on_bad_lines管辖范围)
也就是说,on_bad_lines 只管“这行能不能拆成字段”,不管“这行能不能解码”或“拆完字段合不合逻辑”。
跳过异常行后如何知道丢了多少数据
on_bad_lines="warn" 会在终端输出类似这样的警告:
ParserWarning: Skipping line 42: expected 5 fields, saw 7但它不会告诉你总共跳了几行,也不提供回调钩子。
如果需要精确统计,得自己封装一层:
import pandas as pd
from io import StringIO
<p>def safe_read_csv(filepath, **kwargs):
with open(filepath, "r", encoding=kwargs.get("encoding", "utf-8")) as f:
lines = f.readlines()</p><pre class="brush:php;toolbar:false;">good_lines = []
bad_count = 0
for i, line in enumerate(lines, 1):
try:
# 用 StringIO 模拟单行读取,复用 pandas 解析逻辑
pd.read_csv(StringIO(line), nrows=1, **{k: v for k, v in kwargs.items() if k != "on_bad_lines"})
good_lines.append(line)
except Exception:
bad_count += 1
print(f"Skipped {bad_count} bad lines")
return pd.read_csv(StringIO("".join(good_lines)), **kwargs)
不过这种做法性能差很多,仅适合小文件或调试阶段。生产环境建议先用 on_bad_lines="warn" 跑一次看警告,再决定是否清洗源数据。

















