浏览 AI使用教程

Python 批量处理 Excel:保留原文件并生成差异报告

用 Python 批量清洗 Excel 时,原文件、公式、日期和异常行都要保留证据。输出一份新文件和差异报告,比直接覆盖“整理干净”更重要。

按实际操作顺序推进

每完成一段就检查当前输出,确认结果符合预期后再继续。

  1. 01准备先生成能对账的输入
  2. 02执行完整清洗程序
  3. 03检查为什么“数据行数一致,工作簿仍可能损坏”还不能交付
  4. 04完成新文件、差异报告与异常行通过哪些检查才算完成
从手头这一份材料开始

表格看起来整齐了,公式和异常日期却一起丢了

日期 01/09/2026 存在日月歧义,订单号 00123 又必须保留前导零。清洗时新增规范列,原始字段和公式不覆盖。

此处给出预期与断言;当前编辑环境未运行 Python/openpyxl。公式保留不等于公式重算,复杂真实工作簿需单独验证支持范围。

  • 原文件哈希不变
  • 新增规范列而非覆盖原值
  • 歧义与未知映射有行号和原因
本例材料

动手前,把材料和不能改的部分定下来

需要确认本例内容
现有材料Python 3、openpyxl 3.1 系列;下方生成包含 orders 与 notes 的练习工作簿,3 行订单、3 个公式,不包含宏、图片、复杂对象。
不能越过的边界原文件只读,输出新文件;公式与样式变化单列;异常行保留原值、原因和行号。
要交付的结果新文件、差异报告与异常行
实际操作

Python 批量处理 Excel,从“在新目录建环境”开始做

在新目录建环境

安装 openpyxl,保存并运行 make_fixture.py;不要使用唯一的真实工作簿练习。

确认规则

只接受明确的年/月/日字符串;渠道只映射 wechat→微信,未知值保留。

运行清洗

保存 clean.py,生成新工作簿和逐行 CSV;已有输出时脚本停止。

核对输出

手工打开两个工作表,比较原列、规范列、公式与异常报告。

迁移到真实文件前复核

宏、图形、外链、合并单元格与复杂样式并未被本例覆盖,不能仅凭公式数宣称完整保真。

Python / openpyxl

先生成能对账的输入

终端

在新的练习目录执行

py -m venv .venv
.\.venv\Scripts\python.exe -m pip install "openpyxl>=3.1,<3.2"
.\.venv\Scripts\python.exe make_fixture.py
make_fixture.py

完整输入工作簿

from openpyxl import Workbook
from pathlib import Path
if Path("orders.xlsx").exists(): raise FileExistsError("不要覆盖已有文件")
wb = Workbook(); ws = wb.active; ws.title = "orders"
ws.append(["order_id","date","channel","amount","double"])
ws.append(["00123","2026/9/1","wechat",100,"=D2*2"])
ws.append(["00124","01/09/2026","微信",200,"=D3*2"])
ws.append(["00125","2026/9/3","unknown",50,"=D4*2"])
wb.create_sheet("notes")["A1"] = "教学数据;不包含宏、图形或外部链接"
wb.save("orders.xlsx")

完整清洗程序

clean.py

新增规范列、写差异与检查不变项

from pathlib import Path
from datetime import datetime
import csv, hashlib
from openpyxl import load_workbook
source = Path("orders.xlsx")
before = hashlib.sha256(source.read_bytes()).hexdigest()
wb = load_workbook(source, data_only=False)
ws = wb["orders"]
if [ws.cell(1, c).value for c in range(1, 6)] != ["order_id","date","channel","amount","double"]:
    raise ValueError("表头不符合本练习,不猜列")
formula_before = sum(c.data_type == "f" for sheet in wb for row in sheet for c in row)
ws.cell(1,6,"date_normalized"); ws.cell(1,7,"channel_normalized")
diff = []
channels = {"wechat":"微信", "微信":"微信"}
for row in range(2, ws.max_row + 1):
    raw_date, raw_channel = ws.cell(row,2).value, ws.cell(row,3).value
    normalized, reason = raw_date, ""
    try:
        if not isinstance(raw_date, str) or raw_date.count("/") != 2 or len(raw_date.split("/")[0]) != 4:
            raise ValueError()
        normalized = datetime.strptime(raw_date, "%Y/%m/%d").strftime("%Y-%m-%d")
    except ValueError:
        reason = "日期不是明确的年/月/日,保留原值"
    channel = channels.get(raw_channel, raw_channel)
    if raw_channel not in channels:
        reason += (";" if reason else "") + "渠道未在映射表中,保留原值"
    ws.cell(row,6,normalized); ws.cell(row,7,channel)
    diff.append([row, ws.cell(row,1).value, raw_date, normalized, raw_channel, channel, reason])
target = Path("orders_cleaned.xlsx")
if target.exists() or Path("orders_diff.csv").exists():
    raise FileExistsError("输出已存在;先检查或换一个练习目录")
wb.save(target)
with open("orders_diff.csv","w",encoding="utf-8-sig",newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["row","order_id","date_old","date_new","channel_old","channel_new","reason"])
    writer.writerows(diff)
check = load_workbook(target, data_only=False)
formula_after = sum(c.data_type == "f" for sheet in check for row in sheet for c in row)
assert hashlib.sha256(source.read_bytes()).hexdigest() == before
assert formula_after == formula_before == 3
assert check["orders"]["A2"].value == "00123"
print("原文件哈希未变;公式数量3;差异记录", len(diff))
终端

执行

.\.venv\Scripts\python.exe clean.py

openpyxl 不计算 Excel 公式。本例 data_only=False 保留公式字符串;读取公式缓存与重新计算是另一个问题。支持范围参见 [openpyxl 教程](https://openpyxl.readthedocs.io/en/stable/tutorial.html)。

最终输出

完成后的新文件、差异报告与异常行

预期输出 orders_cleaned.xlsx 和 orders_diff.csv,3 条逐行记录;第二行日期保留原值并标歧义,第三行渠道 unknown 保留并标异常,订单号仍为字符串00123,公式数量仍为3。

常见失败

为什么“数据行数一致,工作簿仍可能损坏”还不能交付

数据行数一致,工作簿仍可能损坏

原因
只比较单元格值,遗漏公式、工作表和格式
怎么改
检查 sheet、行列、公式计数、关键样式与重开结果
验收方式

新文件、差异报告与异常行通过哪些检查才算完成

依据与范围

本页实际使用的资料