日常办公或数据处理中,我们经常会遇到需要复制Excel工作表(sheet)的场景------比如批量备份数据、合并多个Excel文件的sheet、重复生成格式一致的报表等。手动复制不仅耗时费力,还容易出现格式错乱、数据遗漏的问题,尤其面对多文件、多sheet的批量操作时,效率极低。
今天就给大家分享两种Python自动化复制Excel sheet表的实用方案,分别基于openpyxl和win32com实现,覆盖"轻量格式保留"和"完美格式保留"两种核心需求,同时对比两种方案的优劣性和适用场景,新手也能快速上手,彻底解放双手!
适用人群:Python新手、办公自动化从业者、需要批量处理Excel的职场人、数据分析师。
一、前置准备(环境+测试文件)
1.1 环境搭建
本次用到两个核心库,提前用pip安装即可,Python版本建议3.7及以上(兼容性更好),具体安装命令和库的作用如下:
python
# 安装openpyxl(轻量,支持.xlsx格式,可手动实现格式复制)
pip install openpyxl
# 安装pywin32(用于调用win32com,依赖Windows系统和本地Excel)
pip install pywin32
补充说明:
-
openpyxl:仅支持.xlsx格式,无需依赖本地Excel,跨平台(Windows、Mac、Linux)可用,需手动编写代码实现格式复制。
-
win32com:依赖Windows系统+本地已安装的Excel(2016及以上版本最佳),支持.xls和.xlsx两种格式,可完美保留Excel的所有格式(包括宏、图表、条件格式等高级特性)。
1.2 测试文件准备
为了方便大家实操,提前准备两个测试文件,建议使用绝对路径(避免中文乱码和路径识别错误):
- 源文件(source_file):包含1个或多个sheet,建议添加一些格式(字体、边框、合并单元格、数字格式等),测试格式复制效果,如下图,示例路径:
r"E:\PycharmProjects\ExcelSheetCopy\业务状况表.xls"(可自行修改)。

- 目标文件(target_file):用于接收复制的sheet,若文件不存在,代码会自动创建,示例路径:
r"E:\PycharmProjects\ExcelSheetCopy\业务状况表-copy.xlsx"(可自行修改)。
注意:win32com支持.xls和.xlsx格式,openpyxl仅支持.xlsx格式,测试时可根据方案选择对应格式的源文件。
二、核心实现方案(附完整可运行代码)
以下两个方案均提供完整代码,可直接复制修改文件路径后运行,代码中包含详细注释,新手也能轻松看懂每一步的作用。
方案一:使用openpyxl(轻量跨平台,手动实现格式复制)
2.1 核心原理
通过openpyxl加载源Excel文件和目标Excel文件,手动复制sheet的列宽、行高、合并单元格、单元格值及样式(字体、边框、填充等),最终保存目标文件,实现"可控的格式保留"。适合不需要高级格式(如宏、图表),且需要跨平台使用的场景。
2.2 完整可运行代码(带详细注释)
python
import openpyxl
from copy import copy
import os
def copy_sheet_with_format(source_file, target_file, sheet_name):
"""
跨Excel文件复制工作表(手动实现格式保留,支持.xlsx格式)
:param source_file: 源Excel文件绝对路径(必须存在,仅支持.xlsx)
:param target_file: 目标Excel文件绝对路径(不存在则自动创建)
:param sheet_name: 要复制的工作表名称(必须在源文件中存在)
:return: 无返回值,成功后打印提示信息
"""
# 1. 校验并加载源文件(判断文件是否存在、sheet是否存在)
if not os.path.exists(source_file):
# 抛出异常,提示文件不存在,便于排查问题
raise FileNotFoundError(f"源文件 {source_file} 不存在!请检查文件路径是否正确。")
# 加载源工作簿,data_only=False表示保留单元格格式(True仅保留数值)
source_wb = openpyxl.load_workbook(source_file, data_only=False)
# 判断指定sheet是否在源工作簿中
if sheet_name not in source_wb.sheetnames:
raise ValueError(f"源文件中没有名为 '{sheet_name}' 的工作表!请检查sheet名称是否正确。")
# 获取源工作表对象
source_sheet = source_wb[sheet_name]
# 2. 加载或创建目标文件
try:
# 尝试加载目标文件(若文件已存在)
target_wb = openpyxl.load_workbook(target_file)
except FileNotFoundError:
# 若目标文件不存在,新建工作簿
target_wb = openpyxl.Workbook()
# 删除新建工作簿默认的"Sheet"工作表(避免冗余)
target_wb.remove(target_wb.active)
# 3. 处理目标工作簿中的同名工作表(若存在则删除,避免冲突)
if sheet_name in target_wb.sheetnames:
target_wb.remove(target_wb[sheet_name])
# 在目标工作簿中创建同名工作表,用于接收复制的内容
target_sheet = target_wb.create_sheet(sheet_name)
# 4. 复制源sheet的列宽(保证格式一致)
for col in source_sheet.column_dimensions:
target_sheet.column_dimensions[col].width = source_sheet.column_dimensions[col].width
# 5. 复制源sheet的行高(保证格式一致)
for row in source_sheet.row_dimensions:
target_sheet.row_dimensions[row].height = source_sheet.row_dimensions[row].height
# 6. 复制源sheet的合并单元格(避免合并格式丢失)
for merged_range in source_sheet.merged_cells.ranges:
# 将源sheet的合并单元格范围,复制到目标sheet
target_sheet.merge_cells(str(merged_range))
# 7. 复制每个单元格的值和样式(核心步骤,逐 cell 复制)
for row in source_sheet.iter_rows():
for cell in row:
# 复制单元格的值
new_cell = target_sheet.cell(row=cell.row, column=cell.column, value=cell.value)
# 复制单元格样式(若有)
if cell.has_style:
# 使用copy()避免样式对象跨工作簿引用报错
new_cell.font = copy(cell.font) # 字体
new_cell.border = copy(cell.border) # 边框
new_cell.fill = copy(cell.fill) # 填充色
new_cell.number_format = cell.number_format # 数字格式(如日期、百分比)
new_cell.protection = copy(cell.protection) # 保护设置
new_cell.alignment = copy(cell.alignment) # 对齐方式
# 8. 保存目标文件(完成复制)
target_wb.save(target_file)
print(f"✅ 成功将工作表 '{sheet_name}' 从 '{source_file}' 复制到 '{target_file}',格式已保留。")
# 【核心调用代码】(修改以下路径和sheet名称即可运行)
if __name__ == "__main__":
# 源文件路径(仅支持.xlsx格式,绝对路径)
SOURCE_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表.xlsx"
# 目标文件路径(绝对路径,不存在会自动创建)
TARGET_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表-copy.xlsx"
# 要复制的工作表名称(必须与源文件中的sheet名称一致)
SHEET_NAME = "业务状况表(日报)"
# 调用函数,执行复制操作
copy_sheet_with_format(SOURCE_EXCEL, TARGET_EXCEL, SHEET_NAME)
运行结果如下:

2.3 关键注意点
-
格式支持:可保留字体、边框、填充、合并单元格、数字格式等基础格式,但不支持宏、图表、条件格式等高级特性。
-
文件格式:仅支持.xlsx格式,若源文件是.xls格式,需先转换为.xlsx,或使用win32com方案。
-
路径问题:必须使用绝对路径,避免中文路径(若需使用中文,确保Python环境编码为utf-8)。
-
性能:适合中小型Excel文件(10万行以内),大型文件可能会出现卡顿(可优化为分块读取)。
方案二:使用win32com(Windows专属,完美保留所有格式)
2.1 核心原理
通过win32com调用Windows系统中的Excel应用程序(需本地安装Excel),模拟人工操作Excel的"复制-粘贴"流程,可完美保留Excel的所有格式,包括宏、图表、条件格式、数据验证等高级特性,适合对格式要求极高的场景。
2.2 完整可运行代码(带详细注释)
python
import os
import win32com.client as win32
def copy_sheet_via_excel(source_file, target_file, sheet_name, overwrite=True):
"""
通过Excel应用程序复制工作表(完美保留全部格式,支持.xls和.xlsx)
:param source_file: 源Excel文件绝对路径(必须存在)
:param target_file: 目标Excel文件绝对路径(不存在则自动创建)
:param sheet_name: 要复制的工作表名称(必须在源文件中存在)
:param overwrite: 目标工作簿存在同名sheet时,是否覆盖(True=覆盖,False=报错)
:return: (bool, str) 第一个元素表示是否成功,第二个元素为错误信息(成功时为None)
"""
# 1. 参数校验(提前排查基础错误)
if not os.path.isfile(source_file):
error_info = f"❌ 错误:源文件不存在 - {source_file},请检查路径是否正确。"
return False, error_info
if not sheet_name:
error_info = "❌ 错误:工作表名称不能为空!"
return False, error_info
# 初始化Excel应用程序和工作簿对象(避免资源泄露,用finally释放)
excel = None
source_wb = None
target_wb = None
try:
# 2. 启动Excel应用程序(Visible=False表示不显示Excel窗口,后台运行)
excel = win32.gencache.EnsureDispatch('Excel.Application')
excel.Visible = False
excel.DisplayAlerts = False # 禁止弹出提示框(如覆盖确认、格式兼容提示)
# 3. 打开源工作簿(只读模式,避免修改源文件)
print(f"📂 正在打开源文件:{source_file}")
source_wb = excel.Workbooks.Open(source_file, ReadOnly=True)
# 检查源工作簿中是否存在指定工作表
try:
source_sheet = source_wb.Worksheets(sheet_name)
except Exception as e:
error_info = f"❌ 错误:源工作簿中不存在名为 '{sheet_name}' 的工作表 - {str(e)}"
return False, error_info
# 4. 打开或创建目标工作簿
print(f"📂 正在打开/创建目标文件:{target_file}")
if os.path.isfile(target_file):
# 目标文件已存在,直接打开
target_wb = excel.Workbooks.Open(target_file)
else:
# 目标文件不存在,新建工作簿并保存
target_wb = excel.Workbooks.Add()
target_wb.SaveAs(target_file)
print(f"✅ 已创建新工作簿:{target_file}")
# 5. 处理目标工作簿中的同名工作表(避免冲突)
sheet_names = [ws.Name for ws in target_wb.Worksheets]
if sheet_name in sheet_names:
if overwrite:
# 允许覆盖,删除目标工作簿中的同名sheet
print(f"⚠️ 目标工作簿中已存在同名工作表 '{sheet_name}',正在删除...")
target_wb.Worksheets(sheet_name).Delete()
print(f"✅ 已删除原工作表 '{sheet_name}'")
else:
# 不允许覆盖,直接报错退出
error_info = f"❌ 错误:目标工作簿中已存在同名工作表 '{sheet_name}',且未设置覆盖模式。"
return False, error_info
# 6. 复制工作表到目标工作簿(核心步骤,完美保留格式)
# After参数:指定复制到目标工作簿的最后一个工作表之后
after_sheet = target_wb.Worksheets(target_wb.Worksheets.Count)
source_sheet.Copy(After=after_sheet)
print(f"✅ 已复制工作表 '{sheet_name}' 到目标工作簿")
# 7. 保存目标工作簿,完成复制
target_wb.Save()
print(f"✅ 目标工作簿已保存:{target_file}")
# 8. 关闭源工作簿(不保存修改,避免误改源文件)
source_wb.Close(SaveChanges=False)
print("✅ 源工作簿已关闭")
# 复制成功,返回结果
success_info = f"🎉 成功将工作表 '{sheet_name}' 从 '{source_file}' 复制到 '{target_file}',格式已完美保留。"
return True, success_info
except Exception as e:
# 捕获复制过程中的所有异常,返回错误信息
error_info = f"❌ 复制过程中发生错误:{str(e)}"
return False, error_info
finally:
# 确保释放资源(无论是否发生异常,都关闭工作簿和Excel应用)
if source_wb:
try:
source_wb.Close(SaveChanges=False)
except:
pass
if target_wb:
try:
target_wb.Close(SaveChanges=False) # 已保存,无需再次保存
except:
pass
if excel:
try:
excel.Quit() # 关闭Excel应用程序
except:
pass
del excel # 释放COM对象引用,避免内存泄露
# 【核心调用代码】(修改以下路径和sheet名称即可运行)
if __name__ == "__main__":
# 源文件路径(支持.xls和.xlsx格式,绝对路径)
SOURCE_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表.xls"
# 目标文件路径(绝对路径,不存在会自动创建)
TARGET_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表-copy.xlsx"
# 要复制的工作表名称(必须与源文件中的sheet名称一致)
SHEET_NAME = "业务状况表(日报)"
# 调用函数,执行复制操作,允许覆盖同名sheet
res = copy_sheet_via_excel(SOURCE_EXCEL, TARGET_EXCEL, SHEET_NAME, overwrite=True)
# 打印执行结果
print(res[1])
运行结果如下:

2.3 关键注意点
-
环境依赖:仅支持Windows系统,且本地必须安装Excel(2016及以上版本最佳),Mac/Linux系统无法使用。
-
格式支持:完美保留所有格式,包括宏、图表、条件格式、数据验证、公式等,是格式要求极高场景的首选。
-
资源释放:必须在finally中关闭工作簿和Excel应用程序,否则会导致Excel进程后台残留(可在任务管理器中结束)。
-
权限问题:若报错"权限不足",需关闭目标文件,或用管理员身份运行Python脚本。
三、两种方案优劣性+使用场景对比(重点)
很多同学会纠结"该选哪种方案",这里整理了详细的对比表格,结合自身需求选择即可,一目了然:
| 对比维度 | openpyxl方案 | win32com方案 |
|---|---|---|
| 格式保留 | 支持基础格式(字体、边框、合并单元格等),不支持宏、图表等高级特性 | 完美保留所有格式(包括宏、图表、条件格式等高级特性) |
| 文件格式支持 | 仅支持.xlsx格式 | 支持.xls和.xlsx两种格式 |
| 运行环境 | 跨平台(Windows、Mac、Linux),无需安装Excel | 仅支持Windows,必须安装Excel |
| 操作难度 | 中等(需手动编写格式复制代码) | 简单(调用Excel接口,无需手动处理格式) |
| 性能表现 | 中小型文件(10万行以内)流畅,大型文件易卡顿 | 适配各类文件大小,性能更稳定(依赖Excel自身处理能力) |
| 资源占用 | 轻量,占用内存少 | 较重,需启动Excel进程,占用内存较多 |
| 适用场景 | 1. 跨平台使用;2. 仅需保留基础格式;3. 中小型Excel文件;4. 无本地Excel环境 | 1. Windows系统;2. 需完美保留所有格式(含宏、图表);3. 大型Excel文件;4. 对格式要求极高的办公场景 |
总结建议:若你是Windows系统、有Excel环境、对格式要求高,优先选win32com;若需要跨平台、仅需基础格式、无Excel环境,选openpyxl即可。
四、常见应用场景(贴合实际,直接复用)
结合两种方案的特点,整理4个最常见的应用场景,可直接修改代码复用:
场景1:同一工作簿内复制sheet并重命名
需求:将"业务状况表(日报)"复制一份,重命名为"业务状况表(周报)",用于后续编辑。
实现思路:无需额外处理,只需将目标文件路径改为源文件路径(同一工作簿),复制后修改sheet名称即可(openpyxl和win32com均可实现)。
场景2:不同工作簿间批量复制多个sheet
需求:将源文件中的"日报""周报""月报"3个sheet,批量复制到目标文件中。
实现思路:循环调用上述两个方案的函数,遍历需要复制的sheet名称列表,批量执行复制操作。
python
# 示例(以win32com为例,openpyxl同理)
if __name__ == "__main__":
SOURCE_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表.xls"
TARGET_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表-copy.xlsx"
# 需要批量复制的sheet名称列表
SHEET_NAMES = ["业务状况表(日报)", "业务状况表(周报)", "业务状况表(月报)"]
for sheet in SHEET_NAMES:
res = copy_sheet_via_excel(SOURCE_EXCEL, TARGET_EXCEL, sheet, overwrite=True)
print(f"sheet '{sheet}':{res[1]}")
场景3:复制sheet时筛选特定数据
需求:复制"业务状况表(日报)",但仅保留"销售额>10000"的行数据,同时保留原有格式。
实现思路:在openpyxl方案中,复制单元格时添加条件判断,仅复制符合条件的单元格;win32com方案可先复制整个sheet,再通过Excel接口筛选数据。
场景4:定时自动复制(每日/每周备份)
需求:每天固定时间(如18:00)自动复制当天的业务报表sheet,实现自动备份。
实现思路:结合schedule库,定时调用复制函数,示例代码(需安装schedule:pip install schedule):
python
import schedule
import time
# 定义定时任务
def auto_copy_sheet():
SOURCE_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\业务状况表.xls"
TARGET_EXCEL = r"E:\PycharmProjects\ExcelSheetCopy\备份\业务状况表-{}.xlsx".format(time.strftime("%Y%m%d"))
SHEET_NAME = "业务状况表(日报)"
res = copy_sheet_via_excel(SOURCE_EXCEL, TARGET_EXCEL, SHEET_NAME, overwrite=True)
print(f"定时备份结果:{res[1]}")
# 每天18:00执行备份任务
schedule.every().day.at("18:00").do(auto_copy_sheet)
# 持续运行定时任务
while True:
schedule.run_pending()
time.sleep(60) # 每60秒检查一次任务
五、常见问题与解决方案(避坑指南)
实操过程中可能会遇到一些问题,整理了最常见的5个问题及解决方案,帮大家快速避坑:
问题1:运行代码报错"文件不存在"
原因:文件路径错误(相对路径识别失败)、文件名拼写错误、文件被占用。
解决方案:1. 统一使用绝对路径(复制文件路径后,在前面加r,如r"E:\test.xlsx");2. 检查文件名和sheet名称是否一致;3. 关闭打开的Excel文件,释放占用。
问题2:复制后格式错乱/数据丢失
原因:openpyxl方案未手动复制某类格式(如合并单元格、数字格式);win32com方案未关闭Excel提示框。
解决方案:1. openpyxl方案检查代码中是否包含列宽、行高、合并单元格、样式的复制代码;2. win32com方案确保添加excel.DisplayAlerts = False。
问题3:win32com报错"无法创建Excel应用程序"
原因:本地未安装Excel、Excel版本不兼容、权限不足。
解决方案:1. 安装Excel 2016及以上版本;2. 用管理员身份运行Python脚本;3. 重新安装pywin32(pip uninstall pywin32 && pip install pywin32)。
问题4:中文路径/中文sheet名称报错
原因:Python环境编码不支持中文,或路径中包含特殊字符。
解决方案:1. 路径前面加r(如r"E:\测试文件.xlsx");2. 确保Python环境编码为utf-8(可在脚本开头添加# -*- coding: utf-8 -*-)。
问题5:Excel进程后台残留(关闭Python后,Excel仍在任务管理器中)
原因:win32com方案未正确释放资源(未关闭工作簿或Excel应用)。
解决方案:1. 确保代码中finally块正确关闭source_wb、target_wb和excel;2. 手动在任务管理器中结束"EXCEL.EXE"进程。
六、进阶优化(可复用性提升)
为了让代码更具复用性,适合实际工作场景,可对上述代码进行以下优化:
优化1:封装为可复用函数(已实现)
两种方案均已封装为函数,可直接导入其他脚本调用,只需传入源文件路径、目标文件路径、sheet名称即可。
优化2:添加日志记录(便于排查问题)
使用logging库,记录复制过程、成功/失败信息,避免每次运行都手动查看打印结果,示例:
python
import logging
# 配置日志(保存到文件,同时打印到控制台)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.FileHandler("excel_copy_log.log"), logging.StreamHandler()]
)
# 在函数中使用日志替代print
logging.info(f"正在打开源文件:{source_file}")
logging.error(error_info)
优化3:批量处理多文件夹Excel文件
遍历指定文件夹下的所有Excel文件,自动复制每个文件中的指定sheet到目标文件,适合批量合并场景(可结合os.walk()实现)。
优化4:添加异常重试机制
对于网络文件、易被占用的文件,添加重试机制,避免因临时错误导致复制失败:
python
from retry import retry # 需安装:pip install retry
# 重试机制:失败后重试3次,每次间隔2秒
@retry(tries=3, delay=2)
def copy_sheet_via_excel(source_file, target_file, sheet_name, overwrite=True):
# 原函数代码不变
pass
七、总结与展望
本文分享了Python自动化复制Excel sheet表的两种核心方案,分别解决"轻量跨平台"和"完美格式保留"的需求:
-
openpyxl:跨平台、轻量,适合基础格式保留,无需Excel环境,新手易上手。
-
win32com:Windows专属,完美保留所有格式,适合对格式要求极高的办公场景。
通过两种方案的对比和实操代码,相信大家能快速根据自身需求选择合适的方法,彻底摆脱手动复制的繁琐工作。
后续拓展方向:结合Python的数据清洗、可视化功能,实现Excel全流程自动化(如复制sheet后自动统计数据、生成图表);也可以封装为桌面工具,方便非技术人员使用。
如果大家在实操过程中遇到问题,或者有其他Excel自动化的需求,欢迎在评论区留言交流,一起提升办公效率!
八、附录(补充资源)
-
核心库官方文档:
-
openpyxl官方文档:https://openpyxl.readthedocs.io/
-
pywin32官方文档:https://pypi.org/project/pywin32/
-
-
完整代码下载:可将本文中的代码复制到本地,修改文件路径后直接运行。