Python自动化办公实例:批量重命名文件与Excel数据处理脚本
本文提供基于Python标准库pathlib的文件批量重命名脚本,以及基于pandas的多Excel工作簿自动化合并清洗脚本,包含完整代码、防覆盖冲突机制与数据校验流程。
pathlib模块可以构建零依赖、跨平台的文件重命名方案,配合pandas与openpyxl库则能快速实现数十个Excel文件的自动对齐、清洗与合并。本文直接提供这两个典型场景下的完整可执行脚本,详细拆解规则设计、冲突处理与结果校验步骤。
一、运行环境准备与脚本依赖
完成本文任务需要Python 3.8或更高版本。批量重命名脚本完全基于Python标准库,无需额外安装模块;Excel批处理脚本采用数据分析领域通用的pandas与底层的openpyxl引擎进行表格读写。
在开始编写代码前,通过终端或命令行安装所需依赖:
pip install pandas openpyxl
为了保证脚本执行时路径明确且互不干扰,建议建立如下目录结构。输入文件和输出结果分开存储,既方便查看效果,也能防止误修改原始素材:
project_workspace/
│
├── batch_rename.py # 文件批量重命名脚本
├── process_excel.py # Excel合并清洗脚本
│
├── raw_files/ # 待重命名文件存放目录
│ ├── invoice_scan_01.pdf
│ └── memo_temp.docx
│
└── raw_excels/ # 待汇总的Excel报表存放目录
├── 2024_01_华东区销售.xlsx
├── 2024_01_华北区销售.xlsx
└── output/ # 汇总导出文件目录
二、实例一:批量重命名文件脚本实战
重命名文件常见的问题是命名逻辑混乱、误覆盖同名文件以及缺乏执行前的预演。使用pathlib.Path处理路径比传统的os.path更面向对象,支持直接提取文件的纯文件名(stem)与后缀名(suffix)。
1. 重命名规则设计与安全防范
本实例的目标是将指定目录下的杂乱文件统一规范为:[业务前缀]_[修改日期]_[原文件名或自增编号].[原扩展名]。为了防止由于重名导致旧文件被静默覆盖,脚本在重命名阶段执行目标存在性检测。如果目标文件已存在,则自动添加自增数字后缀进行消歧;同时内置dry_run模拟执行参数,首次运行仅打印改名计划,核对无误后再实际写入磁盘。
2. 批量重命名完整代码实现
创建 batch_rename.py 脚本,并将目标文件夹路径传入 batch_rename_files 函数:
import datetime
from pathlib import Path
def batch_rename_files(
target_dir: str,
prefix: str = "DOC",
include_date: bool = True,
dry_run: bool = True,
) -> None:
"""批量重命名指定目录下的文件
:param target_dir: 待处理的目标文件夹绝对或相对路径
:param prefix: 重命名后的业务前缀,如 INV, REPORT, CONTRACT
:param include_date: 是否在文件名中加入最后修改日期
:param dry_run: 为True时仅打印预览,不实际修改文件;确认无误后改为False执行
"""
folder = Path(target_dir)
if not folder.exists() or not folder.is_dir():
print(f"[错误] 目标目录不存在或非有效文件夹: {target_dir}")
return
# 按文件创建/修改时间正向排序,确保命名序号相对稳定
files = [f for f in folder.iterdir() if f.is_file() and not f.name.startswith(".")]
files.sort(key=lambda item: item.stat().st_mtime)
print(f"[*] 发现待处理文件数: {len(files)} (dry_run 模式: {dry_run})")
print("-" * 65)
renamed_count = 0
for idx, file_path in enumerate(files, start=1):
suffix = file_path.suffix.lower()
parts = [prefix]
if include_date:
mtime = file_path.stat().st_mtime
date_str = datetime.datetime.fromtimestamp(mtime).strftime("%Y%m%d")
parts.append(date_str)
# 构造基准新名称,如 DOC_20241030_001.pdf
base_name = f"{'_'.join(parts)}_{idx:03d}"
new_filename = f"{base_name}{suffix}"
target_path = folder / new_filename
# 安全防覆盖:如果目标文件已存在且不是自己,添加碰撞消歧后缀
collision_idx = 1
while target_path.exists() and target_path != file_path:
target_path = folder / f"{base_name}_{collision_idx}{suffix}"
collision_idx += 1
if target_path == file_path:
print(f"[跳过] 命名已符合规范: {file_path.name}")
continue
if dry_run:
print(f"[预演] {file_path.name} -> {target_path.name}")
else:
file_path.rename(target_path)
print(f"[完成] {file_path.name} -> {target_path.name}")
renamed_count += 1
print("-" * 65)
if dry_run:
print("[提示] 预演完毕,未写入磁盘。如确认无误,请传入 dry_run=False 正式重命名。")
else:
print(f"[成功] 批量重命名完成,共修改 {renamed_count} 个文件。")
if __name__ == "__main__":
# 执行示例:首次运行保持 dry_run=True 进行预演
target_folder = "./raw_files"
batch_rename_files(
target_dir=target_folder,
prefix="REPORT",
include_date=True,
dry_run=True,
)
rename() 会抛出 PermissionError。建议在执行脚本前关闭所有相关软件。
3. 执行结果示例输出
将 dry_run 设置为 True 时,终端输出如下所示:
三、实例二:多Excel文件合并与数据清洗脚本
在跨部门协作或定期统计中,各分支机构常上报单独的Excel表格。这些表格往往存在几类普遍问题:
- 空行与脏数据:表格末尾常有空白行,或由于编辑不慎遗留的空格符。
- 临时小计/总计干扰:各分表自带“本页小计”或“汇总”行,若直接简单合并会导致统计总数翻倍。
- 来源信息缺失:合并后若不额外补充一列“数据归属文件”,将无法追溯每条记录的具体部门或发生地。
1. 数据合并与清洗核心代码
编写 process_excel.py 脚本,支持批量检索指定文件夹下的所有 .xlsx 文件,并进行针对性清洗:
from pathlib import Path
from typing import List
import pandas as pd
def clean_single_dataframe(df: pd.DataFrame, source_filename: str) -> pd.DataFrame:
"""对单个Excel读取出的DataFrame进行通用清洗"""
# 1. 剔除全空行与全空列
df = df.dropna(how="all").dropna(axis=1, how="all")
if df.empty:
return df
# 2. 规范列名:去除首尾空格,统一转为字符串
df.columns = [str(col).strip() for col in df.columns]
# 3. 过滤典型小计/合计行(针对首列包含'合计'或'小计'关键词的记录)
first_col = df.columns[0]
df = df[~df[first_col].astype(str).str.contains("小计|合计|总计", na=False)]
# 4. 关键类型规范化示例:如果存在'销售金额'或'数量'列,转换为数值型,非数值设为0
for num_col in ["销售金额", "金额", "数量"]:
if num_col in df.columns:
df[num_col] = pd.to_numeric(df[num_col], errors="coerce").fillna(0.0)
# 5. 关键日期列规范化示例:统一为 YYYY-MM-DD
for date_col in ["日期", "下单时间", "销售日期"]:
if date_col in df.columns:
df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.strftime("%Y-%m-%d")
# 6. 追加来源标签列,便于排查数据源头
df["数据来源"] = source_filename
return df
def merge_excel_files(input_dir: str, output_file: str, sheet_name: str = 0) -> None:
"""批量合并目录下所有Excel文件,并输出至指定目标
:param input_dir: 包含待合并Excel文件的目录
:param output_file: 导出的合并总表路径
:param sheet_name: 读取的Sheet名称或索引,默认读取第1张Sheet
"""
source_folder = Path(input_dir)
if not source_folder.exists() or not source_folder.is_dir():
print(f"[错误] 目录不存在: {input_dir}")
return
# 过滤掉以 ~$ 开头的Excel临时锁定文件
excel_files: List[Path] = [
f for f in source_folder.glob("*.xlsx")
if not f.name.startswith("~$")
]
if not excel_files:
print("[提示] 指定目录下未发现任何可合并的 .xlsx 文件。")
return
print(f"[*] 找到 {len(excel_files)} 个Excel文件,开始提取与清洗...")
print("-" * 65)
data_frames = []
total_raw_rows = 0
for file_path in excel_files:
try:
# 使用 openpyxl 引擎读取
raw_df = pd.read_excel(file_path, sheet_name=sheet_name, engine="openpyxl")
total_raw_rows += len(raw_df)
cleaned_df = clean_single_dataframe(raw_df, file_path.name)
if not cleaned_df.empty:
data_frames.append(cleaned_df)
print(f"[读取] {file_path.name}: 原始 {len(raw_df)} 行 -> 清洗后 {len(cleaned_df)} 行")
else:
print(f"[跳过] {file_path.name}: 数据清洗后为空表格")
except Exception as err:
print(f"[警告] 读取文件失败 {file_path.name}: {err}")
if not data_frames:
print("[错误] 未能成功提取任何有效数据。")
return
# 纵向堆叠合并(对齐列名,缺失列自动填充为 NaN)
master_df = pd.concat(data_frames, ignore_index=True)
# 确保输出目录存在
out_path = Path(output_file)
out_path.parent.mkdir(parents=True, exist_ok=True)
# 导出至Excel,不保留Pandas自带的数字索引
master_df.to_excel(out_path, index=False, engine="openpyxl")
print("-" * 65)
print(f"[完成] 所有表格合并完毕!")
print(f" • 输入文件总数: {len(excel_files)}")
print(f" • 原始记录总行数: {total_raw_rows}")
print(f" • 清洗后最终行数: {len(master_df)}")
print(f" • 结果已保存至: {out_path.resolve()}")
if __name__ == "__main__":
input_folder = "./raw_excels"
target_output = "./raw_excels/output/2024年度销售数据总汇.xlsx"
merge_excel_files(input_dir=input_folder, output_file=target_output)
当某个Excel文件在WPS或Microsoft Excel中处于打开状态时,操作系统会在同一目录下生成一个隐藏的以
~$ 开头的同名临时文件(例如 ~$2024_01_华东区销售.xlsx)。如果不进行显式过滤,Pandas尝试读取它时会直接抛出 BadZipFile 错误导致脚本中断。代码中使用 if not f.name.startswith("~$") 是关键防护点。
2. 运行结果示例展示
四、自动化办公工作流串联与异常防护
重命名与Excel批处理不仅可以独立执行,还可以组合为自动化流水线:先通过重命名脚本把外部上报的任意命名报表按统一命名规范重新归档,随后批处理脚本直接根据归一化后的名称进行正则过滤与批量合并,形成完整闭环。
五、常见问题排查与优化建议
| 常见现象 / 报错 | 根本原因 | 针对性解决办法 |
|---|---|---|
PermissionError: [WinError 32] |
文件被另一个进程占用(如Excel窗口处于打开状态) | 关闭被打开的Excel或PDF文件后再运行脚本;在代码中捕获该异常跳过或打印提示 |
BadZipFile: File is not a zip file |
读取到了以 ~$ 开头的临时锁文件,或者文件损坏、非真xlsx格式 |
严格在文件遍历中增加 not f.name.startswith("~$") 条件过滤 |
合并后数字列显示为 0.0 或空白 |
原Excel中存在千分位逗号(如 "1,234.50")导致转数值失败 |
先执行 str.replace(",", "") 去掉逗号,再调用 pd.to_numeric() |
日期列出现 1970-01-01 或时间戳数字 |
Excel中的数字型序列日期未被解析,或者单元格格式为纯文本 | 使用 pd.to_datetime(df['日期'], origin='1899-12-30', unit='D') 进行Excel序列号转换 |
通过合理配置pathlib进行原子性安全操作,结合pandas的向量化清洗能力,即可将以往耗费大量人力的文件归档与表格汇总工作固化为标准化脚本。在实际工程落地时,建议始终先在测试目录下使用少量样本进行预演校验,确认清洗规则覆盖所有异常分支后,再批量投入日常办公环境。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









