如何逐行读取CSV避免跳行 处理不等列数数据转JSON
问题原因
pandas.read_csv 是为规整结构化表格设计的,默认取首行字段数作为全表固定列数,只要后续行列数和这个值不匹配,哪怕设置了error_bad_lines=False(1.3以上版本已替换为on_bad_lines='skip'),也只会直接跳过异常行,完全保留不了内容,适配不了列数动态变化的非规整CSV场景。
实现方案
不要依赖pandas自动推断表头和列结构,逐行拆分读取后再统一转格式即可,两种可直接复用的实现:
方案1:Python标准库csv模块实现(无额外依赖,优先使用)
用内置csv模块按分号逐行解析,能自动处理引号包裹、转义字符这类CSV特殊语法,不会跳过任何行,所有内容都能完整读入,最后转JSON即可,示例代码:
import csv import json from io import StringIO # 保留你原有的rawdata预处理逻辑 # 假设rawdata是REST接口返回的字节流 processed_str = rawdata.decode('utf-8').replace('\t', '') csv_buffer = StringIO(processed_str) # 逐行读取,不预设表头,不跳行 reader = csv.reader(csv_buffer, delimiter=';') all_rows = [] for row in reader: # 按需保留/去除空字段即可 cleaned_row = [field.strip() for field in row if field is not None] all_rows.append(cleaned_row) # 以下是转键值对格式JSON的逻辑,不需要固定结构可以直接输出all_rows max_col_count = max(len(r) for r in all_rows) # 首行是表头就取首行做键名,不是的话自动生成col_x格式的列名 headers = all_rows[0] if all_rows else [f"col_{i}" for i in range(max_col_count)] # 补全表头长度,适配后续行字段更多的情况 if len(headers) < max_col_count: headers += [f"extra_col_{i}" for i in range(len(headers), max_col_count)] json_result = [] # 首行是表头就从第二行开始遍历,不是表头直接遍历all_rows即可 for row in all_rows[1:]: # 字段不足补None,字段超出自动匹配额外列名 padded_row = row + [None]*(max_col_count - len(row)) json_result.append(dict(zip(headers, padded_row))) # 最终JSON结果 final_json = json.dumps(json_result, ensure_ascii=False)
方案2:pandas适配实现
如果一定要用pandas处理,先提前扫一遍所有行算出最大列数,给pandas传入固定列名,不让它自己从首行推断列数,就不会出现跳行问题,示例代码:
import pandas as pd from io import StringIO import csv processed_str = rawdata.decode('utf-8').replace('\t', '') # 先计算全表最大列数 max_cols = max(len(row) for row in csv.reader(StringIO(processed_str), delimiter=';')) # 传入固定列名,屏蔽pandas自动推断列数的逻辑 df = pd.read_csv( StringIO(processed_str), sep=';', header=None, # 首行是表头就改成header=0 names=[f"col_{i}" for i in range(max_cols)], on_bad_lines='warn' # 列数提前对齐后不会再触发跳行逻辑 ) final_json = df.to_json(orient='records', force_ascii=False)
踩坑提醒
- 不要直接用字符串
split(';')拆分每行,遇到引号包裹的字段内容里带分号的情况,会直接把字段拆错,必须用标准库csv.reader做拆分 - 如果不需要输出统一的键值对JSON结构,逐行读到列表后直接转JSON即可,不用做补全字段、映射表头的操作
- 如果首行是真实表头,只需要把代码里生成列名的逻辑替换成取第一行内容即可,记得补全超出表头长度的额外列名
内容的提问来源于stack exchange,提问作者Gamsner
相关产品推荐
相关产品推荐

