使用Python对Excel工作簿中的所有工作表分别求和并自动生成结果

 更新时间:2026年06月30日 08:46:24   作者:杨利杰YJlio  
本文介绍了如何用Python自动对Excel工作簿中的所有工作表进行求和汇总,通过遍历每个工作表,识别金额列并计算合计值,脚本会在每张表末尾追加合计行,并生成一个汇总表集中展示所有结果,有需要的小伙伴可以了解下

1. 问题背景:几十个 Sheet 都要合计,手工做很痛苦

这一篇继续整理《超简单:用 Python 让 Excel 飞起来》第 6 章中的案例内容,主题是 对一个工作簿中的所有工作表分别求和。这个场景非常贴近真实办公:一个 Excel 工作簿里按月份、部门、项目或区域拆了很多 Sheet,每张表结构类似,都有一列金额,现在需要分别计算每张表的合计值。

手工当然也能做。打开第一张表,找到金额列,写一个 SUM;再打开第二张表,重复一次;几十张表下来,本质就是重复点鼠标、重复复制公式、重复检查结果。表少的时候还能忍,表一多就容易漏算、错算、重复算。

这张图展示了本文的整体主题:使用 Python 对一个工作簿中的所有工作表分别求和,并自动生成结果。

从这张图中可以看出,本文的重点不是单独计算某一个 Sheet,而是把“遍历所有 Sheet → 指定列求和 → 写回合计结果 → 生成汇总表”做成一条完整自动化流程。真正有价值的不是 sum() 这一个函数,而是把求和任务变成可重复执行的批处理模板。

这里最容易犯的错误,是把这个案例理解成简单求和。实际工作中更麻烦的是:有的 Sheet 是空表,有的 Sheet 缺少目标列,有的金额看起来是数字,其实是文本,还有的工作簿已经存在“汇总”Sheet。脚本要能处理这些边界,才算真正可用。

2. 目标效果:运行一次脚本想看到什么

这个案例的目标效果可以拆成两层。第一层是在每张业务工作表底部自动追加一行 合计,并把指定金额列的合计值写进去。第二层是额外生成一个 汇总 工作表,把每张 Sheet 的合计结果集中展示出来。

这张图展示了第一层效果:脚本会在每张工作表底部自动写入合计行。

从这张图中可以看出,合计结果不是覆盖原始数据,而是追加在表格末尾。这个设计比较稳,因为原数据结构不会被破坏,读者打开每张表时,也能直接看到该表自己的合计结果。

推荐把合计结果写在表尾,而不是直接插入到数据中间。这样既方便阅读,也减少破坏原有数据结构的风险。如果后续要再次处理原始明细,表尾合计行也更容易识别和排除。

最终我们希望得到这样的交付结果:

1. 每张业务 Sheet:

  • 表尾追加“合计”行
  • 指定金额列写入合计值

2. 汇总 Sheet:

  • 列出每张工作表名称
  • 列出每张表的金额合计
  • 最后一行给出总计

这套输出适合交付领导或业务同事:既能看每张表的局部结果,也能在汇总表里横向对比所有 Sheet。

3. 实现思路:把求和变成标准化流水线

要想让脚本稳定,就不能只盯着“求和”这一步。完整流程应该是:打开工作簿,遍历所有工作表,读取表格数据,清洗金额列,计算合计,写回当前 Sheet,记录到汇总列表,最后生成汇总 Sheet 并保存。

这张图展示了自动求和的完整流程,从打开工作簿到生成汇总表,每一步都对应脚本中的关键动作。

从这张图中可以看出,一个可靠的自动化脚本必须具备“遍历、清洗、计算、写回、汇总”五个动作。如果缺少清洗,金额可能算错;如果缺少写回,单表结果不直观;如果缺少汇总,领导仍然看不到整体对比。

我把这一节理解成一个可复用模块。输入是工作簿路径和要合计的列名,输出是每个 Sheet 的合计行和一个总汇总表。后续如果要计算最大值、最小值、平均值,其实也能沿用同一套框架,只是把计算函数换掉。

4. 环境准备:pandas 负责计算,xlwings 负责写回 Excel

这个案例里我使用的组合是 pandas + xlwings。其中 pandas 负责数据读取后的计算和清洗,xlwings 负责打开工作簿、遍历工作表、把结果写回 Excel。

pandas 擅长算数据,xlwings 擅长操作 Excel 应用。这两个工具组合在一起,适合处理这种“既要计算,又要写回原工作簿结构”的任务。

安装命令如下:

pip install pandas xlwings

如果你的电脑没有安装 Excel,或者 Excel 被安全策略、加载项、弹窗卡住,xlwings 可能无法正常工作。这不是 Python 语法问题,而是 Excel 应用环境问题。在企业桌面环境中,这一点要提前确认。

推荐先复制一份测试工作簿,不要直接对正式文件运行脚本。尤其是脚本涉及写回、保存、另存为这些动作时,先用样本文件跑通,再处理正式数据。

5. 完整代码:对所有 Sheet 分别求和并生成汇总表

下面这份代码是一个相对完整的版本,重点考虑了几个真实场景:自动跳过空表,自动跳过缺少目标列的 Sheet,自动跳过 汇总 Sheet,金额列支持 ¥12,345.67 这类文本数字,写回时只在表尾追加合计行,不覆盖原始明细数据。

import pandas as pd
import xlwings as xw


def clean_to_number(s: pd.Series) -> pd.Series:
    """
    把带货币符号、逗号、空格的文本金额转换成数值。
    例如:¥12,345.67 -> 12345.67
    """
    s = s.astype(str).str.strip()
    s = s.str.replace(",", "", regex=False)
    s = s.str.replace(r"[¥¥$ ]", "", regex=True)
    s = s.str.replace(r"[^0-9\.\-]", "", regex=True)
    return pd.to_numeric(s, errors="coerce")


def sum_all_sheets_in_workbook(
    input_xlsx: str,
    sum_col: str = "销售利润",
    summary_sheet_name: str = "汇总",
    start_cell: str = "A1",
    save_as: str | None = None,
) -> None:
    """
    对一个工作簿中的所有工作表分别对 sum_col 求和:
    1. 在每个 Sheet 末尾追加“合计”行
    2. 生成或覆盖一个“汇总”Sheet,列出每个 Sheet 的合计和总计

    save_as=None:覆盖保存原文件
    save_as=路径:另存为新文件
    """

    app = xw.App(visible=False, add_book=False)
    app.display_alerts = False
    app.screen_updating = False

    try:
        wb = app.books.open(input_xlsx)
        results = []

        for sht in wb.sheets:

            # 跳过汇总 Sheet,避免二次运行时把汇总表也拿去求和
            if sht.name == summary_sheet_name:
                continue

            rng = sht.range(start_cell).expand("table")

            if rng.value is None:
                print(f"[SKIP] {sht.name}: 空表")
                continue

            df = rng.options(pd.DataFrame).value

            if df is None or df.empty:
                print(f"[SKIP] {sht.name}: 无有效数据")
                continue

            if sum_col not in df.columns:
                print(f"[SKIP] {sht.name}: 缺少列 '{sum_col}'")
                continue

            # 清洗金额列并求和
            num = clean_to_number(df[sum_col]).fillna(0)
            total = float(num.sum())

            # 写回:在当前表格最后一行下面追加合计行
            last_cell = rng.last_cell
            total_row = last_cell.row + 1

            # 找到 sum_col 在表格中的列序号,xlwings 使用 1-based 列号
            col_idx = df.columns.get_loc(sum_col) + 1

            sht.range((total_row, 1)).value = "合计"
            sht.range((total_row, col_idx)).value = total

            # 给合计行加粗,便于阅读
            try:
                sht.range((total_row, 1), (total_row, col_idx)).api.Font.Bold = True
            except Exception:
                pass

            results.append({
                "工作表": sht.name,
                f"{sum_col}合计": total
            })

            print(f"[OK] {sht.name}: {sum_col} 合计 = {total}")

        # 生成汇总 Sheet
        summary_df = pd.DataFrame(results)

        if summary_df.empty:
            raise RuntimeError("未得到任何可汇总结果,请检查列名、数据区域或是否为空表。")

        total_col = f"{sum_col}合计"
        grand_total = float(summary_df[total_col].sum())

        summary_df = summary_df.sort_values(by=total_col, ascending=False)

        # 如果已存在汇总 Sheet,则清空;不存在则新建
        try:
            sum_sht = wb.sheets[summary_sheet_name]
            sum_sht.clear()
        except Exception:
            sum_sht = wb.sheets.add(summary_sheet_name, before=wb.sheets[0])

        sum_sht.range("A1").options(index=False).value = summary_df

        # 写入总计
        last = sum_sht.range("A1").expand("table").last_cell
        total_row = last.row + 1

        sum_sht.range((total_row, 1)).value = "总计"
        sum_sht.range((total_row, 2)).value = grand_total

        try:
            sum_sht.range((1, 1), (total_row, 2)).api.Columns.AutoFit()
            sum_sht.range((total_row, 1), (total_row, 2)).api.Font.Bold = True
        except Exception:
            pass

        if save_as:
            wb.save(save_as)
            print(f"[DONE] 已另存为:{save_as}")
        else:
            wb.save()
            print(f"[DONE] 已覆盖保存:{input_xlsx}")

        wb.close()

    finally:
        app.quit()


if __name__ == "__main__":
    sum_all_sheets_in_workbook(
        input_xlsx="产品销售统计表.xlsx",
        sum_col="销售利润",
        summary_sheet_name="汇总",
        start_cell="A1",
        save_as="产品销售统计表_已求和.xlsx",
    )

这份代码的结构并不复杂,但边界处理比较重要。它不是简单读取所有 Sheet 后直接求和,而是先排除汇总表,再判断是否为空表,再判断目标列是否存在,最后才进入金额清洗和求和逻辑。

如果你直接把所有 Sheet 都拿来求和,下一次运行脚本时,汇总表也可能被重复计算,结果会越来越怪。所以跳过 summary_sheet_name 不是锦上添花,而是必须保留的安全判断。

6. 关键点拆解:金额列看着像数字,其实可能是字符串

这个案例最容易翻车的地方,不是 sum() 不会用,而是金额列的数据类型不稳定。Excel 里很多金额看起来像数字,但实际可能是文本,例如 ¥12,345.67、12,345、 8000 ,甚至混有空格和货币符号。

这张图展示了金额清洗的核心过程:把原始金额文本去掉符号、逗号和无效字符,再转换成真正可以求和的数值。

从这张图中可以看出,求和前的关键动作是“清洗转换”。如果金额列没有先转成数值,脚本可能得到 0、NaN,或者产生错误结果。这类问题表面上像是计算错误,实际上是数据类型问题。

清洗函数的核心代码如下:

def clean_to_number(s: pd.Series) -> pd.Series:
    s = s.astype(str).str.strip()
    s = s.str.replace(",", "", regex=False)
    s = s.str.replace(r"[¥¥$ ]", "", regex=True)
    s = s.str.replace(r"[^0-9\.\-]", "", regex=True)
    return pd.to_numeric(s, errors="coerce")

这段代码做了四件事:第一,把数据统一转成字符串;第二,去掉逗号;第三,去掉人民币符号、美元符号和空格;第四,只保留数字、小数点和负号,再用 pd.to_numeric() 转成数值。

涉及金额统计时,我建议永远先做类型清洗,再做求和。不要相信 Excel 里“看起来像数字”的显示效果。脚本处理的是底层数据类型,不是你眼睛看到的表格样式。

7. 效果验证:如何确认脚本真的成功

脚本运行完成,不代表结果一定正确。对这种批量求和脚本,至少要验证三件事:每张业务 Sheet 是否写入了合计行;汇总 Sheet 是否生成;汇总 Sheet 的总计是否等于各 Sheet 合计之和。

这张图展示了最终汇总效果:多个工作表的合计结果集中到一张汇总表中,并可以横向对比。

从这张图中可以看出,汇总表不只是把结果堆在一起,它还承担了横向对比的作用。哪个部门、哪个月份、哪个项目金额最高,一眼就能看出来。这才是自动生成汇总表的真正价值:减少人工统计,也减少人工解释。

建议验证时按下面几个点检查:

1. 打开每个业务 Sheet,确认表尾是否出现“合计”行

2. 检查目标金额列是否写入正确合计值

3. 打开“汇总”Sheet,确认每张表都有一条汇总记录

4. 检查“总计”是否等于所有 Sheet 合计之和

5. 抽查 1 到 2 张 Sheet,用 Excel 自带 SUM 手工核对一次

如果想在脚本中增加简单验证,也可以打印每个 Sheet 的处理日志:

print(f"[OK] {sht.name}: {sum_col} 合计 = {total}")

推荐保留控制台日志。批量脚本不应该静默运行。哪些 Sheet 成功、哪些 Sheet 跳过、跳过原因是什么,都应该能从日志里看出来。这是后续复盘和排错的基础。

8. 常见问题与踩坑记录

8.1 expand(“table”) 依赖连续表格

sht.range(start_cell).expand("table") 的好处是方便,它会从起始单元格自动扩展读取连续区域。但它也有前提:表格中间不能有完全空白行或空白列。

如果你的表格中间有空行,expand 可能读不全。这种情况下,建议先统一模板,或者改成固定读取范围,例如 A1:H2000。

8.2 汇总 Sheet 必须跳过

如果脚本第一次运行后生成了 汇总 Sheet,第二次再运行时,如果不跳过它,脚本可能会把汇总表也当成业务表继续求和。

if sht.name == summary_sheet_name:
    continue

这行代码非常关键。只要脚本会生成结果 Sheet,就应该在遍历时明确跳过结果 Sheet。

8.3 不要默认每张表都有目标列

真实工作簿里经常会出现模板不统一的问题。有的 Sheet 叫 销售利润,有的可能叫 利润 或 销售金额。如果不判断列名,脚本会直接报错。

if sum_col not in df.columns:
    print(f"[SKIP] {sht.name}: 缺少列 '{sum_col}'")
    continue

这个判断的意义,是让异常 Sheet 被识别并跳过,而不是让一个异常 Sheet 中断整个工作簿的处理。

8.4 不建议直接覆盖原文件

虽然代码支持 save_as=None 覆盖保存原文件,但我不建议初次使用时这么做。尤其是脚本会写回每张表、生成汇总 Sheet,一旦逻辑有误,原文件就可能被污染。

推荐使用另存为模式:

save_as="产品销售统计表_已求和.xlsx"

这样原始文件不会被破坏,处理结果也更方便对比。

9. 总结提升:这节真正要学的是批量计算框架

这一节看起来只是对每张工作表求和,但真正值得带走的是一套批量计算框架:遍历 Sheet、识别目标列、清洗数据、执行计算、写回结果、生成汇总表、最后验证输出。

如果只会写 sum(),遇到真实办公数据很快就会卡住;如果理解了这套流程,后续要做最大值、最小值、平均值、按条件求和、多列汇总,其实都是在同一个框架上替换计算逻辑。

办公自动化脚本的价值,不是让代码看起来复杂,而是让重复动作变得稳定、可验证、可复盘。这一点比单纯记住某个函数更重要。

最后再提醒一次:批量写回 Excel 前一定要先备份。自动化脚本跑得越快,错误扩散得也越快。先用样本文件测试,确认合计行、汇总表、总计结果都正确,再处理正式工作簿。

以上就是使用Python对Excel工作簿中的所有工作表分别求和并自动生成结果的详细内容,更多关于Python Excel工作表求和的资料请关注脚本之家其它相关文章!

相关文章

  • YOLOv5目标检测之anchor设定

    YOLOv5目标检测之anchor设定

    在训练yolo网络检测目标时,需要根据待检测目标的位置大小分布情况对anchor进行调整,使其检测效果尽可能提高,下面这篇文章主要给大家介绍了关于YOLOv5目标检测之anchor设定的相关资料,需要的朋友可以参考下
    2022-05-05
  • Python可视化绘制图表的教程详解

    Python可视化绘制图表的教程详解

    python 有许多可视化工具,但本文主要为大家介绍一下Matplotlib。Matplotlib是一种2D的绘图库,它可以支持硬拷贝和跨系统的交互,感兴趣的可以了解一下
    2022-10-10
  • PyCharm新建项目时如何配置项目的Python解释器详解

    PyCharm新建项目时如何配置项目的Python解释器详解

    在PyCharm中配置Python环境是开发者日常工作中的一项重要任务,尤其当接手已有项目时,这篇文章主要给大家介绍了关于PyCharm新建项目时如何配置项目的Python解释器的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-06-06
  • Python输出汉字字库及将文字转换为图片的方法

    Python输出汉字字库及将文字转换为图片的方法

    这篇文章主要介绍了Python输出汉字字库及将文字转换为图片的方法,分别用到了codecs模块和pygame模块,需要的朋友可以参考下
    2016-06-06
  • 关于Numpy中argsort()函数的用法解读

    关于Numpy中argsort()函数的用法解读

    这篇文章主要介绍了关于Numpy中argsort()函数的用法解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Python正则表达式教程之一:基础篇

    Python正则表达式教程之一:基础篇

    正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。下面这篇文章主要介绍了关于Python正则表达式基础的相关资料,需要的朋友可以参考下。
    2017-03-03
  • python实现简单日期工具类

    python实现简单日期工具类

    这篇文章主要为大家详细介绍了python实现简单日期工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • python面向对象值元类的声明周期详解

    python面向对象值元类的声明周期详解

    这篇文章主要介绍python的元类生命周期,我们可以和之前探讨类的生命中周期一样,我们写一个案例,使用print来输出一些信息,来判断如果基于元类而言,那么生命周期是怎么样的,文中有详细的代码示例,需要的朋友可以参考下
    2023-05-05
  • Django中使用haystack+whoosh实现搜索功能

    Django中使用haystack+whoosh实现搜索功能

    这篇文章主要介绍了Django之使用haystack+whoosh实现搜索功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • 提升Python程序性能的7个习惯

    提升Python程序性能的7个习惯

    这篇文章主要介绍了提升Python程序性能的7个习惯,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04

最新评论