首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >超简单:用 Python 让 Excel 飞起来:用 openpyxl 把重复报表整理交给脚本

超简单:用 Python 让 Excel 飞起来:用 openpyxl 把重复报表整理交给脚本

原创
作者头像
小白学大数据
发布2026-09-03 16:58:56
发布2026-09-03 16:58:56
450
举报

1.为什么我想写这一篇?做办公自动化这几年,我见过太多这样的场景:每天早上的固定流程,是把十几个业务群发来的 Excel 下载下来,手动复制、粘贴、对齐格式、核对数字,最后拼成一份日报。整件事耗时约 40 分钟,其中真正需要"思考"的环节可能只有 5 分钟,其余 35 分钟都是在做低价值的机械搬运。这类工作,恰恰是 Python 最擅长接管的部分。《超简单:用 Python 让 Excel 飞起来》这本书给我的最大启发,不是某个具体函数的用法,而是一套判断标准:凡是"有规律、可重复、需批量"的 Excel 操作,都值得停下来问一句——它是不是本来就该由脚本完成?这一篇,我想聚焦其中最实用也最典型的一个场景:用 openpyxl 批量读取 Excel、规整数据、再写回新表。这是几乎所有 Excel 自动化的起点。掌握了它,合并报表、数据汇总、工作表拆分等需求,都可以顺着同一套模式扩展出去。

2. openpyxl 到底解决了什么问题?先澄清一个技术前提:.xlsx 文件本质是一个 ZIP 压缩包,内部封装了一组 XML 描述文件。人通过 Excel 软件来操作它,而程序可以直接解析它的内容。openpyxl 正是 Python 生态中专门承担这一职责的库——它不依赖 Excel 软件本身,甚至无需安装 Office,即可完成对 .xlsx 的读写。一个常见疑问是:pandas 不也能处理 Excel 吗?能,但两者的定位差异非常明显:pandas 长于计算——读取后即转换为 DataFrame,适合统计、筛选、建模等数据分析链路;openpyxl 长于控制——精确操作文件本身,单元格取值、样式、行高列宽、多工作表结构,皆在掌控范围之内。因此实践中的分工通常是:pandas 负责"把数据算出来",openpyxl 负责"把表整理成可以直接交付的样子"。两者各司其职、配合使用,才是完整的工程方案。3. 上手第一步:读取一个 Excel 文件安装只需一条命令:

读取文件的核心流程分三步:加载工作簿 → 定位工作表 → 遍历单元格。看一个最小可运行的例子:

代码语言:txt
复制
from openpyxl import load_workbook

# read_only=True:以只读流式模式加载,可显著降低大文件的内存占用
# data_only=True:读取公式单元格的缓存结果,而非公式表达式本身
wb = load_workbook("销售明细.xlsx", read_only=True, data_only=True)
ws = wb.active  # 获取当前默认激活的工作表

# 逐行迭代,每行以元组形式返回
for row in ws.iter_rows(min_row=2, values_only=True):
    print(row)  # 输出示例:(1, '华东', '笔记本', 32, 8999.0)

wb.close()

其中有三个参数,是我建议所有读者优先记住的:data_only=True:返回单元格的计算结果。若省略,读取含公式的单元格时,拿到的将是 "=SUM(B2:B10)" 这样的公式文本;read_only=True:启用流式读取,处理数万行的表格时不会因全量载入内存而卡顿;min_row=2:从第二行开始迭代,等价于跳过表头行,只取数据区。这三个参数是我早期踩坑最集中的地方——第一次处理报表时,金额列读出来全是公式字符串,排查许久才发现问题出在遗漏了 data_only。4. 实战:把散落的月度报表合并成一张汇总表场景设定如下:目录 reports/ 下存放了 12 个月的销售报表(2025-01.xlsx 至 2025-12.xlsx),各表列结构完全一致,目标是将它们合并为一张年度明细表,并追加一张按大区汇总的销售额统计表。首先实现数据收集环节:

代码语言:txt
复制
from pathlib import Path
from openpyxl import load_workbook

def collect_rows(folder: Path) -> list[tuple]:
    """遍历文件夹内全部月度报表,收集表头之外的所有数据行。

    Args:
        folder: 报表所在目录,文件名形如 2025-01.xlsx。

    Returns:
        各报表数据行组成的列表,行内顺序与源表一致。
    """
    all_rows: list[tuple] = []
    # sorted() 按文件名排序,从而保证合并顺序与时间顺序一致
    for file in sorted(folder.glob("2025-*.xlsx")):
        wb = load_workbook(file, read_only=True, data_only=True)
        ws = wb.active
        for row in ws.iter_rows(min_row=2, values_only=True):
            if row[0] is None:  # 报表末尾常有多余空行,遇空则跳过
                continue
            all_rows.append(row)
        wb.close()
    return all_rows

这里有一个值得固化的工程习惯:将"读数据"与"写数据"拆分为独立函数。收集环节只负责读取,输出环节只负责写入,统计逻辑单独成函数。模块边界一旦清晰,后续任何单一环节的调整都不会牵连全局。汇总逻辑同样保持简洁:

代码语言:txt
复制
from collections import defaultdict

def summarize_by_region(rows: list[tuple]) -> dict[str, float]:
    """按大区汇总销售额。列结构约定:(月份, 大区, 产品, 数量, 单价)。

    Args:
        rows: collect_rows 返回的原始数据行。

    Returns:
        大区名到销售额的映射。
    """
    region_sum: dict[str, float] = defaultdict(float)
    for _, region, _, qty, price in rows:
        # qty / price 可能为空值,统一按 0 兜底,避免 None 参与乘法运算
        amount = float(qty or 0) * float(price or 0)
        region_sum[region] += amount
    return dict(region_sum)

值得一提的是,真实业务中「表」并非唯一的数据入口。很多需要定期维护的 Excel 报表,其上游其实是网页数据——例如竞品价格、行业指数、公开榜单。这类数据往往需要定时抓取、清洗后再落盘为 Excel。而一旦采集达到一定规模,单 IP 高频请求极易触发目标站点的频率限制与反爬策略。此时稳定可靠的代理资源就成了刚需——实践中我通常搭配亿牛云代理这类成熟的代理服务,通过其动态轮换的住宅代理或隧道代理来分散请求压力,保证采集链路的长效稳定。这也意味着:掌握 openpyxl 只是打通了"最后一公里",上游数据管道同样值得用工程化手段去加固。5. 写出结果:数据与格式一次到位写入环节同样遵循固定模式:创建工作簿 → 操作工作表 → 保存文件。这里再进一步——将表头加粗、设置底色与列宽,使产出物达到可直接对外交付的标准:

代码语言:txt
复制
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill

def write_summary(rows: list[tuple], summary: dict[str, float], out_path: str) -> None:
    """将明细数据与汇总结果写入多工作表 Excel 文件。

    Args:
        rows: 合并后的明细数据行。
        summary: 按大区汇总的销售额映射。
        out_path: 输出文件的路径。
    """
    wb = Workbook()

    # 工作表一:合并后的完整明细
    detail = wb.active
    detail.title = "年度明细"
    detail.append(["月份", "大区", "产品", "数量", "单价"])
    for row in rows:
        detail.append(row)

    # 工作表二:按大区聚合结果
    region_sheet = wb.create_sheet("大区汇总")
    region_sheet.append(["大区", "销售额"])
    for region, amount in summary.items():
        region_sheet.append([region, round(amount, 2)])

    # 统一样式:表头加粗 + 浅灰底 + 居中对齐
    header_font = Font(bold=True)
    header_fill = PatternFill("solid", fgColor="D9D9D9")
    for sheet in (detail, region_sheet):
        for cell in sheet[1]:
            cell.font = header_font
            cell.fill = header_fill
            cell.alignment = Alignment(horizontal="center")
        sheet.column_dimensions["A"].width = 12

    wb.save(out_path)

def main() -> None:
    rows = collect_rows(Path("./reports"))
    summary = summarize_by_region(rows)
    write_summary(rows, summary, "2025年度汇总.xlsx")

if __name__ == "__main__":
    main()

几个关键写法的取舍说明:append() 以整行追加方式写入,代码量远小于逐单元格赋值,且执行效率更高;Font、PatternFill 等样式对象先创建后复用。若在每个单元格上重复实例化,行数较大时性能差异会非常明显;金额统一在写入前执行 round(amount, 2),避免交付端出现一长串浮点尾数。跑通之后,原本 40 分钟的手工流程被压缩为秒级执行,且彻底消除了人工复制粘贴导致的串行、漏行风险。6. 效果验证:如何确认脚本产出是正确的?自动化最危险的状态,不是脚本报错,而是它安静地算错。我习惯用"三重对照"来完成验收:小样本对照:先用 2~3 个文件试跑,并手工合并一次,逐行比对两侧结果;总量对照:脚本输出的年度总销售额,必须与各月小计再求和的结果完全一致,不允许分毫误差;行数对照:合并明细的行数应等于 12 张源表数据行数之和。若存在偏差,通常意味着源表中存在隐藏空行或重复表头。这三步看似笨拙,却能在数据对外发出前拦截绝大多数问题。尤其是行数对照,已多次帮我定位到报表中隐藏的空行与冗余表头。7. 常见问题和踩坑提醒第一个坑:目标文件被占用。 若脚本执行时 Excel 正打开着目标文件,save() 将直接抛出 PermissionError。建议在脚本入口给出明确提示,或在异常处理中捕获该错误并输出可读的引导信息,而非任其裸奔中断。第二个坑:日期字段类型不稳定。 openpyxl 通常将日期单元格读取为 datetime 对象,但部分数据源返回的是 Excel 内部序列号(浮点数)。当数据来源不可控时,应在写入前做统一的类型归一化,而非假定单一类型。第三个坑:只修改未保存。 所有单元格操作都发生在内存中,未调用 wb.save() 则全部失效;而 save() 覆盖原文件的行为不可逆——处理重要报表前务必先行备份。我的默认策略是输出至新文件名,绝不直接覆盖源文件。第四个坑:大文件导致内存暴涨。 数十万行的表格若未开启 read_only=True,openpyxl 会将整个工作簿载入内存,办公电脑极易卡死;写入方向则应对应使用 write_only=True 追加模式。读写两端均有对应的优化开关——用对了是"让 Excel 飞起来",用错了则是"让电脑趴下去"。第五个坑:上游数据获取的不确定性。 如前文所述,报表数据若来自网页采集,单点 IP 的稳定性会直接影响整个管线的产出质量。请求被限流或封禁时,脚本本身并不会报错,只会带回残缺的数据——这种"静默失败"比显式异常更难排查。为采集任务配置可靠的代理资源(如亿牛云的动态代理池),并把"抓取成功率"纳入巡检指标,才是对产出负责的做法。8. 总结提升:从跑通一个脚本,到沉淀一套模板本文的核心结论可以浓缩为三点:读表三参数:load_workbook 中的 data_only、read_only、min_row,决定了读取的正确性与性能;职责拆分:收集、统计、输出各自成函数,脚本才具备可维护、可交接的工程属性;产出必验:小样本、总量、行数三重对照缺一不可,宁可慢一步,不可错一分。但比结论更重要的,是模板意识。第一次编写合并报表脚本或许需要一小时;可一旦将其沉淀为带完整注释与类型标注的模板文件,下个月、下季度乃至换一批数据源时,往往只需改动数行配置即可复用。自动化的价值不在于第一次运行,而在于此后每一次运行所累积的时间复利。先跑通,再改造,再沉淀——把散落的报表交给脚本,把重复的采集交给可靠的管道,把省下来的时间留给自己。这才是"让 Excel 飞起来"的真正含义。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档