ARTICLE · 1087110
Python语法日报 第13期|Excel自动化开篇——批量处理多个Excel
上期整完了多sheet,这回来硬的——文件夹里躺几十个Excel,一个一个人工打开复制粘贴?那得干到猴年马月去。今天用代码全给它薅出来,揉成一张总表,完事儿泡杯茶等着就行。
一、先看家伙事儿:os模块
Python自带的os,专门跟文件夹和文件打交道。今天主要用俩功能:
os.listdir(文件夹):列出文件夹里所有文件名
os.path.join(文件夹, 文件名):把路径拼完整
import osfolder = r'F:\Desktop\部门报表'# 装Excel的文件夹files = os.listdir(folder)print(files)跑一下,文件夹里所有文件名都列出来了。但这里面啥都有,图片、txt、快捷方式,得筛一下,只要xlsx。
二、筛出Excel文件
excel_files = [f for f in os.listdir(folder) if f.endswith('.xlsx')]print(f'找到{len(excel_files)}个Excel')就这一行,把xlsx全薅出来。xls的老古董不认,要处理先另存为xlsx。
三、循环读取,堆到一张总表
假设每个Excel结构一样:第一行表头,第二行开始是数据。咱搞个总表,再加一列“来源文件”,以后查账知道哪行是从哪个文件来的。
from openpyxl import load_workbook, Workbookimport osfolder = r'F:\Desktop\部门报表'excel_files = [f for f in os.listdir(folder) if f.endswith('.xlsx')]# 搞个新工作簿装结果wb_out = Workbook()ws_out = wb_out.activews_out.title = '总表'# 先写表头,比原表多一列“来源文件”ws_out.append(['姓名', '部门', '工资', '来源文件'])for file in excel_files: file_path = os.path.join(folder, file)print(f'正在处理:{file}') wb_in = load_workbook(file_path) ws_in = wb_in.active# 从第二行开始读,跳过表头for row in ws_in.iter_rows(min_row=2, values_only=True): name, dept, salary = row ws_out.append([name, dept, salary, file])wb_out.save(os.path.join(folder, '汇总结果.xlsx'))print('全干完了,收工')四、踩过的坑
坑1:文件夹里混着临时文件
Excel打开的时候会生成~$开头的临时文件,也被.xlsx筛出来了,一读就报错。
excel_files = [f for f in os.listdir(folder) if f.endswith('.xlsx') and not f.startswith('~$')]坑2:表头列数不一样
有的表三列,有的表五列。name, dept, salary = row 直接崩。稳妥写法是判断长度:
for row in ws_in.iter_rows(min_row=2, values_only=True):if len(row) >= 3: name, dept, salary = row[0], row[1], row[2] ws_out.append([name, dept, salary, file])坑3:sheet名不统一
有的文件sheet叫“Sheet1”,有的叫“数据”。用wb.active拿默认激活的那个,一般没错。如果激活的不是你要的,得按名字取:
ws_in = wb_in['数据'] # 按名字坑4:空文件
有的文件是空的,一读就报错。加个try包一下:
try: wb_in = load_workbook(file_path)# 干活except Exception as e:print(f'{file}翻车了,跳过:{e}')continue五、进阶:合并后按部门分类
汇总完想按部门拆成不同sheet,也简单:
from collections import defaultdict# 按部门分组dept_data = defaultdict(list)for row in ws_out.iter_rows(min_row=2, values_only=True): name, dept, salary, source = row dept_data[dept].append([name, salary, source])# 每个部门建一个sheetfor dept, rows in dept_data.items(): ws_new = wb_out.create_sheet(dept) ws_new.append(['姓名', '工资', '来源'])for r in rows: ws_new.append(r)wb_out.save(os.path.join(folder, '汇总_分类.xlsx'))defaultdict是字典的升级版,key不存在自动建个空列表,省得判断。
六、今儿个知识点打包
列文件夹 | os.listdir(文件夹) |
拼路径 | os.path.join(文件夹, 文件名) |
筛xlsx | [f for f in files if f.endswith('.xlsx')] |
排除临时文件 | and not f.startswith('~$') |
循环读多个文件 | for file in excel_files: |
按部门分组 | defaultdict(list) |
已更Excel系列: