Python 自动化办公适合从只读任务开始:先列出文件,再检查表头,最后生成独立汇总结果。你每天把几个部门发来的表格打开、复制、加总,真正重复的往往是同一套筛选规则,而不是鼠标动作本身。把规则写清,才有条件让程序替你做。

本文用两份 CSV 订单表演示三个连续任务:发现待处理文件、验证金额字段、按来源生成汇总。示例仅使用 Python 3.12 及以上版本的标准库。输入文件保留不动,结果写入新的文件名;它不读取 Excel 工作簿中的公式或样式,也不修改你原有的办公文件。
一、先约定目录和表格格式
为练习新建一个目录,在其中创建 inbox 子目录。把 east.csv 与 west.csv 放进去,程序文件 report.py 放在 inbox 外面。这样输入和输出从物理位置上分开,下一次扫描不会把昨天的汇总再次算进去。
CSV 是文本表格,不是 xlsx 工作簿。下面两段分别保存为 east.csv、west.csv,均使用 UTF-8 编码。表头必须是 order_id 和 amount,金额单位统一为元。
order_id,amount
E001,12.50
E002,7.50
order_id,amount
W001,3.20
W002,6.80
这两份输入应分别得到二十元和十元。先用手算确定结果,再写自动化程序,比拿一大份真实报表盲目调试更容易发现问题。金额为空、包含额外货币符号或有三位小数,都需要事先定义处理规则。
还不熟悉文件对象与循环时,可先对照 Python3 教程 阅读 with 和 for 的作用。with 用于管理文件生命周期;循环用于逐行处理数据,它们解决的是不同问题。
二、任务一:列文件,确认扫描边界
pathlib 用路径对象表达目录和文件,避免你手工拼接反斜杠。程序以自身所在目录定位 inbox,因此即使从别的工作目录启动,也能找到同一份输入。
from pathlib import Path
base = Path(__file__).resolve().parent
files = sorted((base / "inbox").glob("*.csv"))
for path in files:
if path.is_file():
print(path.name)
把这段单独保存为 list_files.py 运行,应按文件名顺序列出 east.csv 和 west.csv。这里用 glob 只扫描 inbox 的直接子项;换成 rglob 会递归进入子目录,不能在不了解目录结构时随意替换。
文件清单是自动化的重要输出。如果列表是空的,先检查目录位置与后缀,不要直接生成零元报告。空目录可能代表今天没有数据,也可能是程序找错了文件夹;这两种情形需要你自己确认,程序不应偷偷选择其中一种。
三、任务二:读表头,验证金额再求和
下面是完整 report.py。它用 Decimal 计算十进制金额,拒绝非有限数、负金额和超过两位小数的数据,并检查同一文件内的订单号重复。
import csv
from decimal import Decimal, InvalidOperation
from pathlib import Path
def summarize(path):
total = Decimal("0")
seen = set()
with path.open(encoding="utf-8-sig", newline="") as file:
reader = csv.DictReader(file)
if reader.fieldnames != ["order_id", "amount"]:
raise ValueError(f"{path.name}: 表头不匹配")
for row in reader:
number = reader.line_num
if None in row or any(v is None for v in row.values()):
raise ValueError(f"{path.name}:{number}: 列数不符")
order = row["order_id"].strip()
if not order or order in seen:
raise ValueError(f"{path.name}:{number}: 订单号空或重复")
try:
amount = Decimal(row["amount"])
except InvalidOperation as exc:
raise ValueError(f"{path.name}:{number}: 金额格式错误") from exc
if (not amount.is_finite() or amount < 0
or amount.as_tuple().exponent < -2):
raise ValueError(f"{path.name}:{number}: 金额范围或精度错误")
seen.add(order)
total += amount
return len(seen), total
def main():
base = Path(__file__).resolve().parent
paths = sorted(p for p in (base / "inbox").glob("*.csv") if p.is_file())
if not paths:
raise ValueError("inbox 中没有 CSV 文件")
results = [(p.name, *summarize(p)) for p in paths]
target = base / "summary.csv"
with target.open("x", encoding="utf-8-sig", newline="") as file:
writer = csv.writer(file)
writer.writerow(["source", "orders", "total"])
for source, count, amount in results:
writer.writerow([source, count, f"{amount:.2f}"])
print(f"已生成 {target.name},来源文件 {len(results)} 个")
if __name__ == "__main__":
main()
utf-8-sig 兼容带 BOM 的 UTF-8 文件,newline 交给 csv 模块处理换行。它们各有用途,不能用忽略编码错误的方式掩盖坏数据。DictReader 按表头创建字典,所以第一行并不参与金额相加。
程序先把所有输入验证完,再创建结果文件。某一行出错时,异常里保留来源文件名和 CSV 读取器的行号,便于返回原表修正。没有把错误金额替换成零,也没有用宽泛异常捕获把坏行静默跳过。
金额和字典相关语法可对照 Python 速查手册。正式业务中还要规定退单、税费与多币种处理,本例只演示同币种非负订单汇总。
四、任务三:核对输出,再决定是否批量使用
在练习目录运行 python report.py。成功后,summary.csv 应有表头和两条来源记录:east.csv 对应两单、20.00;west.csv 对应两单、10.00。输出保留来源文件名,让你能追溯哪张表贡献了哪部分金额。
接着做三次有目的的反例测试。把一条金额改成空值,程序应失败;把同一文件内的订单号重复一次,程序应失败;不修改结果文件而直接重跑,程序应提示目标已存在。最后一项来自写入模式 x,它不会覆盖旧结果。
如果需要再次生成,请为旧结果改名归档后重跑。不要为了省事改成追加模式,否则重复执行可能造成汇总重复。大量输入时也应考虑逐文件输出和事务性处理;当前示例把结果保存在内存,更适合规模较小的办公表格。
| 现象 | 先检查什么 |
|---|---|
| 没有找到输入 | report.py 旁是否有 inbox |
| 表头不匹配 | 列名、顺序和空格是否符合约定 |
| 金额报错 | 空值、负数、小数位和特殊文本 |
| 结果已存在 | 是否应该生成新的批次文件 |

总结
验证重复执行时,也要确认输入文件内容没有改变。可以在首次运行前后比较文件大小和内容,或者对输入计算摘要。这里的只读模式保证程序不主动写入原表,但无法阻止另一位同事同时编辑文件;需要严格批次一致性时,应先固定输入副本,再开始汇总。
Python 自动化办公的第一步,是把人工处理规则变成可核对的数据流程。文件清单确定范围,表头和字段检查保证输入符合约定,汇总输出保留来源,三步缺一不可。
这份练习没有修改原表,也没有自动处理未知格式。你确认两个样本的结果后,再加入另一份相同表头的文件,检查报告是否新增对应记录。等规则稳定后再考虑读取 xlsx、定时执行或发送报表,这样每次扩大能力都有清晰的输入边界。
延伸学习
- Python 学习 可补充文件与异常处理知识。
- Python 数据分析实战 可作为汇总之后的数据展示学习方向。
- Python 基础语法实例 可辅助理解循环、字典与函数之间的组合。
常见问题
Q:CSV 可以保留 Excel 公式吗?
它保存的是文本字段,不等同于保留工作簿计算能力。若任务依赖公式、合并单元格或多个工作表,应选用处理 xlsx 的工具,并重新定义读取规则。
Q:同一订单号出现在不同文件会被拦截吗?
不会,本例的去重范围是单个文件。跨部门订单号全局唯一时,需要把已见订单集合提升到批次层级,并明确重复数据应如何处置。
Q:读取失败后能忽略错误继续统计吗?
只有业务明确接受部分结果时才适合这样做。届时必须输出失败清单并标注结果不完整,不能把“有几张表成功”写成“全部处理成功”。
技术依据:Python csv 官方文档。

免费 AI IDE



