这些错误通常由相应的解析库抛出,

- JSON:
json.JSONDecodeError - XML:
xml.etree.ElementTree.ParseError - CSV:
csv.Error - HTML (BeautifulSoup):
bs4.FeatureNotFound或其他解析器相关的错误。
要“跳过”这些错误,核心思想就是使用 try...except 结构来捕获异常,然后让程序继续执行,而不是崩溃。
下面我将分步讲解,并提供不同场景下的代码示例。
核心方法:try...except 结构
这是处理所有 Python 异常的标准方法。
try:
# 尝试执行可能会出错的代码
result = parse_some_data(data)
# 如果成功,处理 result
print(f"解析成功: {result}")
except SpecificParseError as e:
# 如果发生了 SpecificParseError 类型的错误,执行这里的代码
print(f"解析失败,已跳过,错误信息: {e}")
# 程序会继续从这里往下执行,而不会崩溃
# 无论是否发生错误,这里的代码都会被执行
print("继续处理下一个数据项...")
跳过单个 JSON 解析错误
假设你有一个字符串列表,其中大部分是有效的 JSON,但有一个是无效的,你只想处理有效的,并跳过无效的那个。

错误类型: json.JSONDecodeError
代码示例:
import json
data_strings = [
'{"name": "Alice", "age": 30}',
'{"name": "Bob", "age": 25}',
'{"name": "Charlie", "age": 40,}', # 最后多了一个逗号,是无效的 JSON
'{"name": "David", "age": 35}'
]
valid_data = []
for s in data_strings:
try:
# 尝试解析 JSON 字符串
person_data = json.loads(s)
valid_data.append(person_data)
print(f"成功解析: {person_data['name']}")
except json.JSONDecodeError as e:
# 捕获 JSON 解析错误
print(f"!!! 跳过无效的 JSON: {s}")
print(f" 错误原因: {e}")
# 使用 pass 语句表示什么都不做,直接继续循环
pass
print("\n最终收集到的有效数据:")
for item in valid_data:
print(item)
输出:
成功解析: Alice
成功解析: Bob
!!! 跳过无效的 JSON: {"name": "Charlie", "age": 40,}
错误原因: Expecting property name enclosed in double quotes: line 1 column 33 (char 32)
成功解析: David
最终收集到的有效数据:
{'name': 'Alice', 'age': 30}
{'name': 'Bob', 'age': 25}
{'name': 'David', 'age': 35}
处理文件中的多行数据,跳过解析失败的行
这是一个非常常见的用例,比如处理一个 CSV 或每行都是 JSON 的日志文件。

代码示例:
假设我们有一个 data.jsonl 文件,内容如下:
{"id": 1, "user": "user1"}
{"id": 2, "user": "user2"}
{"id": 3, "user": "user3",} # 无效行
{"id": 4, "user": "user4"}
Python 代码:
import json
valid_entries = []
file_path = 'data.jsonl'
try:
with open(file_path, 'r', encoding='utf-8') as f:
for line_number, line in enumerate(f, 1):
line = line.strip() # 去掉首尾的空白字符
if not line: # 跳过空行
continue
try:
entry = json.loads(line)
valid_entries.append(entry)
print(f"成功解析第 {line_number} 行: {entry}")
except json.JSONDecodeError as e:
print(f"!!! 第 {line_number} 行解析失败,已跳过,内容: '{line}'")
print(f" 错误原因: {e}")
pass # 跳过此行,继续处理下一行
except FileNotFoundError:
print(f"错误: 文件 {file_path} 未找到。")
print("\n成功解析的总条目数:", len(valid_entries))
输出:
成功解析第 1 行: {'id': 1, 'user': 'user1'}
成功解析第 2 行: {'id': 2, 'user': 'user2'}
!!! 第 3 行解析失败,已跳过,内容: '{"id": 3, "user": "user3",}'
错误原因: Expecting property name enclosed in double quotes: line 1 column 27 (char 26)
成功解析第 4 行: {'id': 4, 'user': 'user4'}
成功解析的总条目数: 3
使用 csv 模块跳过格式错误的行
对于 CSV 文件,错误类型通常是 csv.Error。
代码示例:
假设有一个 bad_data.csv 文件:
Name,Age,City Alice,30,New York Bob,25 # 缺少一个字段 Charlie,40,Los Angeles
Python 代码:
import csv
valid_rows = []
file_path = 'bad_data.csv'
try:
with open(file_path, 'r', encoding='utf-8') as f:
# csv.reader 会自动处理引号等,但如果行列数不匹配会报错
reader = csv.reader(f)
header = next(reader) # 读取表头
print(f"表头: {header}")
for row_number, row in enumerate(reader, 2): # 从第2行开始计数
try:
# 这里可以添加更复杂的验证逻辑
# 检查行是否包含预期的列数
if len(row) != len(header):
raise ValueError(f"列数不匹配: 期望 {len(header)} 列,实际 {len(row)} 列")
valid_rows.append(dict(zip(header, row)))
print(f"成功解析第 {row_number} 行: {row}")
except (csv.Error, ValueError) as e:
# 同时捕获 csv.Error 和我们自定义的 ValueError
print(f"!!! 第 {row_number} 行解析失败,已跳过,内容: {row}")
print(f" 错误原因: {e}")
pass
except FileNotFoundError:
print(f"错误: 文件 {file_path} 未找到。")
print("\n成功解析的总行数:", len(valid_rows))
输出:
表头: ['Name', 'Age', 'City']
成功解析第 2 行: ['Alice', '30', 'New York']
!!! 第 3 行解析失败,已跳过,内容: ['Bob', '25']
错误原因: 列数不匹配: 期望 3 列,实际 2 列
成功解析第 4 行: ['Charlie', '40', 'Los Angeles']
成功解析的总行数: 2
总结与最佳实践
-
明确异常类型:首先确定你使用的库在解析失败时会抛出什么具体的异常类(如
json.JSONDecodeError),使用except时捕获这个具体的异常,而不是笼统的except Exception:,这样可以更精确地处理问题。 -
记录错误信息:在
except块中,至少应该打印出错误信息 (e) 和导致错误的数据(失败的行号或行内容),这对于后续调试和数据清洗至关重要。 -
pass的使用:当你的目的仅仅是“跳过”时,pass语句是最简单直接的选择,它表示“什么都不做,继续执行”。 -
处理文件时使用
with语句:这能确保文件在操作完成后(无论是否发生错误)都会被正确关闭,是 Python 的推荐做法。 -
考虑更复杂的逻辑:在某些情况下,你可能不想简单地跳过,你可以:
- 将错误的数据记录到一个单独的“错误日志”文件中。
- 尝试修复数据(用默认值填充缺失的字段)。
- 统计错误发生的频率,如果错误过多,可能需要检查数据源或解析逻辑。
通过掌握 try...except 结构,你就可以稳健地处理各种数据解析任务,让你的程序更加健壮。
