
一、背景需求
开学前期,需要做一系列资料。前几天已经收集了“在线填写的班级信息表”,先做个《点名册》
可以原来电脑坏了,打不开,但是之前已经复制出了代码。
二、制作过程
(一)修改py模版


打开上学期专用,里面没有“假日汉字”,把下学期的“假日汉字”复制一份到上学期

修改代码里面的日期
把里面的2025改成2026就可以了
节假日修改


中秋节是9月第二张公布表的第10天,为了居中显示,可以写11天
国庆节是10月第1张工作表的第1天,为了居中,可以写第2-5(根据生成样式再调整)
元旦节是1月第1张工作表的第1天,为了居中,可以写第2(根据生成样式再调整)

修改表名

上学期没有2月,共4个月,这个学期还是5个月

对照校历修改灰色日期






重新制定路径,更新每个文件的名称(序号)




(二)重新制作Excel模版
需要模版,但是电脑坏了,原来的模版没有导出来。
以前和同事的聊天记录里面有一份样例(还是第一版的:教师在第一页输入名字,容易出现0)
【办公类-54-03】20240828班级点名册模版(双休国定假涂成灰色)2024学年第一学期
https://mp.csdn.net/mp_blog/creation/editor/141687789
‘


,需要根据之前发布的CSDN内容,逐步xlsx修改成“模版”
更改文件名和格式

改名,它是xls,打开 另存为xlsx

另存为xlsx



内部怎么修改参考

一点点修改模版(取消合并单元格、设置标题居左,添加上半月和下半月的日期)

模版最后的效果(经过后续反复测试)

(0)页面设置,列宽,行高、页眉
















做一个模版后,再复制一个,变成下午,这两个模版依次复制5分,修改文件名

页眉内容设置


(1)取消所有合并格,全部是单独的单元格




9-1月的10张表格中的标题都是居左设置

前10张工作表,第三行班级性别月份,全选,居中设置

(三)文件整理,文件名修改

设置一个文件夹,并在里面放班级信息表



更改导出文件的文件名,全部添加序号,便于依次排列

三、内容调试
(一)10月16日位置微调

看到10月上的表格的16日灰色,10月下的16日为白色。考虑14、15、16是一周的,应该连在一起。修改数字


(二)无法保存PDF












我发现每次生成Excel,会弹出“激活向导”。因为这个电脑上的office是360软件管家里面下载的
而且打开生成Excel,会出现两个弹窗。 

所以我问问是不是因为我没有装正版的office,所以出现问题



检查模版里面有没有“合并单元格”,把所有的单元格都变成单独单元格

的确有合并格子,去模版Excel取消










LibreOffice 容量太大了,是不是还是要装正版micosoft office?
它说推荐已经安装的WPS

不死心,还是想用微软office

不行,还是失败





终于顺利做出了PDF(用金山WPS的Excel而不是微软office的Excel打开)

五、设计空白统计表
平时班主任还需要一张统计表,用来计算“物品收集(植物、纸巾)”“收费(居民医保)”

所以我还想在最后一页做一个“统计表”(第11张表)
复制一个工作表

我想把格子拉宽一倍






11个表格,所以最后一个工作表也改名“2026-09表空”,2026-09空


统计表的标题修改

就是删掉Excel模版,第3行的所有信息。

代码里面也不要在最后一个表里面写入、班级、性别、年月



后来发现会超页,所以改成A-T合并。
模版样式:这一页统计表的标题要“居中”,前面10张工作表标题要“居左”






六、 其他问题




最终代码
1.(原电脑)用win32+micosoft office微软正版Excel打开并保存PDF
'''
上学期点名册批量(灰色)
1、修改原始模版,更改年月、标题、页眉
2、读取所有的EXCEL,批量制作EXCEL多月
3、添加“清明节放假”等汉字
4、每页标题包含园区)
5、添加最后一张空白统计表
6、微软正版Excel打开 转成PDF,便于打印
deepseek、豆包、阿夏
20260808
'''
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment
from datetime import datetime, timedelta
import os
from win32com.client import Dispatch
import traceback
import time
import psutil
# ===================== 基础配置 =====================
day = '202609'
title1 = '2026学年第一学期'
title2 = '上海市闵行区天天幼儿园'
names = '天天'
# 文件路径配置
base_path = os.path.abspath(r'D:\Python最终内容\20260901开学点名册批量制作\00上学期名单')
template_file = os.path.join(base_path, '00(模版)原始点名表.xlsx')
class_info_file = os.path.join(base_path, '01 班级信息表', '20260805班级信息表.xlsx')
output_template = os.path.join(base_path, f'02 {day}点名册模版_{names}.xlsx')
output_dir = os.path.join(base_path, f'03 {day}{names}所有点名册')
# 节假日配置中秋节放假是第10天,但是为了让文字靠中间,写在11天的位置上
holidays_config = {
'2026-09下': {11: '中秋节放假', },
'2026-10上': {4: '国庆节放假', },
'2027-01上': {2: '元旦节放假', }
}
# ===================== 样式配置(核心修复:节假日文字黑+背景灰) =====================
# 1. 双休日样式:灰色背景(原配置不变)
gray_fill = PatternFill(start_color='D3D3D3', end_color='D3D3D3', fill_type='solid')
# 2. 节假日样式:文字黑色粗体 + 灰色背景(关键修复)
holiday_font = Font(
name='宋体',
size=10,
bold=False, # 不加粗
color='000000' # 文字颜色:纯黑色(RGB代码)
)
holiday_fill = PatternFill(
start_color='D3D3D3', # 背景颜色:灰色(与双休日同色,也可改为其他灰色如'E6E6E6')
end_color='D3D3D3',
fill_type='solid'
)
# 3. 对齐样式:文字居中(原配置不变)
center_alignment = Alignment(horizontal='center', vertical='center')
# ===================== Excel进程清理工具 =====================
def kill_excel_processes():
try:
excel_procs = []
for proc in psutil.process_iter(['name', 'cmdline']):
try:
proc_name = proc.name().lower()
if 'excel' in proc_name and any('office' in cmd.lower() for cmd in proc.cmdline()):
excel_procs.append(proc)
except (psutil.NoSuchProcess, psutil.AccessDenied, IndexError):
continue
if excel_procs:
print(f"\n⚠️ 发现 {len(excel_procs)} 个残留Excel进程,开始清理...")
for proc in excel_procs:
try:
proc.terminate()
proc.wait(timeout=2)
print(f" ✅ 关闭Excel进程: PID={proc.pid}")
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
except Exception as e:
print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
else:
print("\n✅ 未发现残留Excel进程")
except Exception as e:
print(f"❌ 清理Excel进程失败: {str(e)}")
# ===================== 核心工具函数 =====================
# ===================== Excel转PDF【路线1:加重试,每个文件独立启动Excel】 =====================
def excel_to_pdf(input_file, max_retry=2):
if not os.path.exists(input_file):
print(f"❌ PDF转换失败:文件不存在 - {input_file}")
return False
pdf_file = os.path.splitext(input_file)[0] + '.pdf'
for attempt in range(max_retry + 1):
kill_excel_processes()
time.sleep(0.8)
excel_app = None
wb = None
try:
excel_app = Dispatch("Excel.Application")
excel_app.Visible = False
excel_app.DisplayAlerts = False
excel_app.EnableEvents = False
input_abs = os.path.abspath(input_file)
wb = excel_app.Workbooks.Open(input_abs)
for ws in wb.Worksheets:
ws.PageSetup.Orientation = 1
ws.PageSetup.Zoom = False
ws.PageSetup.FitToPagesTall = 1
ws.PageSetup.FitToPagesWide = 1
ws.PageSetup.CenterHorizontally = True
ws.PageSetup.CenterVertically = True
ws.PageSetup.LeftMargin = excel_app.CentimetersToPoints(1)
ws.PageSetup.RightMargin = excel_app.CentimetersToPoints(1)
ws.PageSetup.TopMargin = excel_app.CentimetersToPoints(1)
ws.PageSetup.BottomMargin = excel_app.CentimetersToPoints(1)
ws.PageSetup.HeaderMargin = excel_app.CentimetersToPoints(1.2)
ws.PageSetup.FooterMargin = excel_app.CentimetersToPoints(0.5)
ws.PageSetup.CenterHeader = f"&\"宋体,10\"{title2}"
pdf_abs = os.path.abspath(pdf_file)
wb.ExportAsFixedFormat(Type=0, Filename=pdf_abs, Quality=1)
print(f"✅ PDF转换完成(竖版+页眉): {os.path.basename(pdf_file)}")
return True
except Exception as e:
print(f"⚠️ 第{attempt+1}次转换失败: {str(e)}")
traceback.print_exc()
finally:
if wb:
try:
wb.Close(SaveChanges=False)
except:
pass
if excel_app:
try:
excel_app.Quit()
except:
pass
kill_excel_processes()
time.sleep(0.5)
print(f"❌ {os.path.basename(input_file)} 全部重试失败")
return False
# ===================== 节假日标记函数(应用新样式) =====================
def add_holiday_marks(workbook):
print("\n=== 开始添加节假日标记(文字黑+背景灰) ===")
for sheet_name in workbook.sheetnames:
ws = workbook[sheet_name]
if sheet_name in holidays_config:
holiday_days = holidays_config[sheet_name]
print(f"📅 工作表 {sheet_name}: 处理节假日 {list(holiday_days.keys())}日")
for day_num, holiday_text in holiday_days.items():
# 计算日期列(日期显示列)和状态列(节假日文字列)
date_col = 3 + (day_num - 1) * 2 # 日期列(如1日对应第3列)
status_col = date_col + 1 # 状态列(节假日文字所在列)
if date_col <= ws.max_column and status_col <= ws.max_column:
# 遍历所有学生行(第5-34行) 只要一行
for row in range(5, 6):
# 1. 处理节假日文字列(核心:应用文字黑+背景灰)
status_cell = ws.cell(row=row, column=status_col)
status_cell.value = holiday_text # 写入节假日文字
status_cell.font = holiday_font # 文字:黑色粗体
status_cell.fill = holiday_fill # 背景:灰色
status_cell.alignment = center_alignment # 文字居中
# 2. 处理日期列(可选:日期列也添加灰色背景,与文字列统一)
date_cell = ws.cell(row=row, column=date_col)
date_cell.fill = holiday_fill # 日期列背景灰
date_cell.alignment = center_alignment # 日期居中
else:
print(f"⚠️ {sheet_name}工作表 {day_num}日列位置无效,跳过处理")
print("=== 节假日标记添加完成 ===")
return workbook
# ===================== 主流程执行 =====================
def main():
print("="*50)
print("🏫 幼儿园点名册批量生成系统(节假日样式修复版)")
print(f"📅 处理周期: {day} - 2026年6月")
print(f"🏢 园区名称: {title2}")
print(f"📄 样式配置: 节假日(文字黑+背景灰)| 双休日(背景灰)")
print("="*50)
print("\n=== 初始化:清理残留Excel进程 ===")
kill_excel_processes()
# 1. 创建输出目录
os.makedirs(output_dir, exist_ok=True)
print(f"\n📁 输出目录准备完成: {output_dir}")
# 2. 生成基础点名表模板
print("\n=== 步骤1: 生成基础点名表模板 ===")
template_wb = None
try:
if not os.path.exists(template_file):
print(f"❌ 模板生成失败:模板文件不存在 - {template_file}")
return
template_wb = openpyxl.load_workbook(template_file)
sheet_names = template_wb.sheetnames
sheet_count = len(sheet_names)
print(f"📋 原始模板工作表: {sheet_names} (共{sheet_count}个)")
months = ['2026-09', '2026-09', '2026-10', '2026-10',
'2026-11', '2026-11', '2026-12', '2026-12','2027-01', '2027-01',"2026-09"]
if len(months) != sheet_count:
months = months[:sheet_count]
print(f"⚠️ 日期列表已调整为 {len(months)} 个,与工作表数量匹配")
new_sheet_names = []
for i in range(sheet_count):
suffix = sheet_names[i][-1:] if len(sheet_names[i]) >= 1 else ''
new_name = f"{months[i]}{suffix}"
new_sheet_names.append(new_name)
print(f"🔖 新工作表名称: {new_sheet_names}")
for i in range(min(len(sheet_names), len(new_sheet_names))):
old_name = sheet_names[i]
new_name = new_sheet_names[i]
template_wb[old_name].title = new_name
print(f" ✅ 重命名: {old_name} → {new_name}")
# 双休日标记,读取第一张表格(上半月)上半月没有16,但是为了表格好看,把16位置也加灰,下半月的31日要变灰,11没有31日
xx = [
[5,6,12,13,16], [19,25,26,27,31],
[1,2,3,4,5,6,7,11,], [16,17,18,24,25,31],
[1,7,8,14,15,16], [21,22,28,29,31],
[5,6,12,13,16], [19,20,26,27,],
[1,2,3,9,10,16], [16,17,23,24,25,26,27,28,29,30,31],
[],
]
if len(xx) < sheet_count:
while len(xx) < sheet_count:
xx.append(xx[-1])
print(f"⚠️ 双休日配置已补充至 {len(xx)} 个")
for bg_idx in range(sheet_count):
if bg_idx < len(template_wb.worksheets):
ws = template_wb.worksheets[bg_idx]
current_sheet = new_sheet_names[bg_idx] if bg_idx < len(new_sheet_names) else f"Sheet{bg_idx+1}"
if len(current_sheet) >= 7:
ws['AB3'] = current_sheet[-3:-1]
ws['W3'] = current_sheet[:4]
else:
ws['AB3'] = '09'
ws['W3'] = '2026'
ws['A2'] = f"{title1} {title2} 点名表"
ws.merge_cells('A2:AH2')
if bg_idx < len(xx):
target_days = xx[bg_idx]
else:
target_days = []
print(f"⚠️ 工作表{bg_idx+1}无双休日配置")
for day_num in target_days:
try:
if bg_idx % 2 == 0:
col_start = day_num * 2 + 1
col_end = day_num * 2 + 2
else:
col_start = (day_num - 15) * 2 + 1
col_end = (day_num - 15) * 2 + 2
if col_start <= ws.max_column and col_end <= ws.max_column:
for row in range(4, 43):
for col in range(col_start, col_end + 1):
ws.cell(row=row, column=col).fill = gray_fill
else:
print(f" ⚠️ 列超出范围: 开始{col_start}, 结束{col_end}, 最大{ws.max_column}")
except Exception as e:
print(f" ❌ 处理日期{day_num}失败: {str(e)}")
# 添加节假日标记(应用新样式)
template_wb = add_holiday_marks(template_wb)
template_wb.save(output_template)
print(f"✅ 基础模板生成完成: {os.path.basename(output_template)}")
except Exception as e:
print(f"❌ 模板生成失败: {str(e)}")
traceback.print_exc()
finally:
if template_wb:
try:
template_wb.close()
print(f"✅ 关闭模板工作簿")
except Exception as e:
print(f"❌ 关闭模板工作簿失败: {str(e)}")
kill_excel_processes()
# 3. 批量生成班级点名表
print("\n=== 步骤2: 批量生成班级点名表 ===")
class_info_wb = None
try:
if not os.path.exists(class_info_file):
print(f"❌ 班级点名表生成失败:班级信息表不存在 - {class_info_file}")
return
class_info_wb = openpyxl.load_workbook(class_info_file)
class_sheets = class_info_wb.worksheets[1:] if len(class_info_wb.worksheets) > 1 else []
counter = 0
print(f"📥 读取到 {len(class_sheets)} 个班级信息")
for class_sheet in class_sheets:
current_class_wb = None
try:
class_name = class_sheet.title
print(f"\n🏫 处理班级: {class_name}")
campus_info = class_sheet['B2'].value if class_sheet['B2'].value else ""
student_names = []
for row in range(2, 37):
try:
name_val = class_sheet.cell(row=row, column=4).value
student_names.append(name_val if name_val is not None else "")
except Exception as e:
print(f" ⚠️ 读取行{row}姓名失败: {str(e)}")
student_names.append("")
male_count = 0
female_count = 0
for row in range(2, 37):
try:
gender = class_sheet.cell(row=row, column=5).value
if gender == "男":
male_count += 1
elif gender == "女":
female_count += 1
except Exception as e:
print(f" ⚠️ 读取行{row}性别失败: {str(e)}")
class_sheet['E37'] = female_count
class_sheet['E38'] = male_count
print(f"👥 学生统计: 男{male_count}人, 女{female_count}人 (共{male_count+female_count}人)")
if not os.path.exists(output_template):
print(f" ❌ 加载模板失败:模板文件不存在 - {output_template}")
continue
current_class_wb = openpyxl.load_workbook(output_template)
if len(class_name) >= 2:
formatted_class = f"{class_name[0]}({class_name[1]})班"
else:
formatted_class = f"{class_name}班"
total_sheets = len(current_class_wb.worksheets)
for ws_idx, ws in enumerate(current_class_wb.worksheets):
try:
if ws_idx == total_sheets - 1:
# ==========最后一张统计表【修复:先取消旧合并A2:AH2】==========
# 解除模板自带的A2:AH2大合并
ws.unmerge_cells("A2:AH2")
# 设置标题文字
ws['A2'] = f"{title1} {formatted_class} 统计单"
# 重新合并为A2:T2
ws.merge_cells('A2:T2')
#清空W3、AB3,清除年月数字
ws['W3'] = None
ws['AB3'] = None
# 写入B列姓名(✅修改:30→35)
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
print(f" 📌 最后一张统计表【{ws.title}】标题:{title1} {formatted_class} 统计单,已取消A2:AH2,合并A2:T2,清除年月")
continue
# ==========普通点名表(前面所有月份)==========
ws['A2'] = f"{title1} {title2}({campus_info}) 点名册"
ws.merge_cells('A2:AH2')
ws['C3'] = formatted_class
ws.merge_cells('C3:G3')
ws['L3'] = male_count
ws.merge_cells('L3:M3')
ws['S3'] = female_count
ws.merge_cells('S3:T3')
ws.merge_cells('W3:Z3')
ws.merge_cells('AB3:AC3')
# 写入学生姓名(✅修改:30→35)
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
else:
print(f" ⚠️ 行{idx+5}超出表格范围,跳过写入")
for i in range(16):
start_col = 3 + 2 * i
end_col = 3 + 2 * i + 1
if start_col <= ws.max_column and end_col <= ws.max_column:
ws.merge_cells(start_row=4, start_column=start_col,
end_row=4, end_column=end_col)
else:
print(f" ⚠️ 合并列超出范围: {start_col}-{end_col},跳过")
except Exception as e:
print(f" ❌ 配置工作表失败: {str(e)}")
class_excel_path = os.path.join(output_dir, f"01_{day}_班级点名表_{formatted_class[0]}{formatted_class[2]}班_{names}.xlsx")
try:
current_class_wb.save(class_excel_path)
print(f"✅ Excel文件生成(节假日样式:文字黑+背景灰): {os.path.basename(class_excel_path)}")
excel_to_pdf(class_excel_path)
counter += 1
except Exception as e:
print(f" ❌ 保存Excel文件失败: {str(e)}")
traceback.print_exc()
except Exception as e:
print(f"❌ 处理班级{class_name}失败: {str(e)}")
traceback.print_exc()
finally:
if current_class_wb:
try:
current_class_wb.close()
print(f" ✅ 关闭班级模板工作簿")
except Exception as e:
print(f" ❌ 关闭班级工作簿失败: {str(e)}")
kill_excel_processes()
class_info_wb.save(class_info_file)
print(f"\n=== 批量处理完成 ===")
print(f"📊 总计处理班级: {counter} 个")
print(f"📁 所有文件保存路径: {output_dir}")
except Exception as e:
print(f"❌ 班级点名表批量生成失败: {str(e)}")
traceback.print_exc()
finally:
if class_info_wb:
try:
class_info_wb.close()
print(f"✅ 关闭班级信息表工作簿")
except Exception as e:
print(f"❌ 关闭班级信息表失败: {str(e)}")
print("\n=== 最终清理:确认无残留Excel进程 ===")
kill_excel_processes()
print(f"\n✅ 所有操作完成!")
# ===================== 执行主程序 =====================
if __name__ == "__main__":
required_packages = ['openpyxl', 'pywin32', 'psutil']
missing_packages = []
for pkg in required_packages:
try:
__import__(pkg)
except ImportError:
missing_packages.append(pkg)
if missing_packages:
print(f"⚠️ 发现缺失依赖包: {', '.join(missing_packages)},正在自动安装...")
import subprocess
import sys
for pkg in missing_packages:
subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
print("✅ 所有依赖包安装完成")
main()
2.(原电脑)用win32+金山WPS的Excel打开并保存PDF
'''
上学期点名册批量(灰色)
1、修改原始模版,更改年月、标题、页眉
2、读取所有的EXCEL,批量制作EXCEL多月
3、添加“清明节放假”等汉字
4、每页标题包含园区)
5、添加最后一张空白统计表
6、WPS打开 转成PDF,便于打印
deepseek、豆包、阿夏
20260808
'''
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment
from datetime import datetime, timedelta
import os
from win32com.client import Dispatch
import traceback
import time
import psutil
# ===================== 基础配置 =====================
day = '202609'
title1 = '2026学年第一学期'
title2 = '上海市闵行区蓝田花花幼儿园'
names = '花花'
# 文件路径配置
base_path = os.path.abspath(r'D:\Python最终内容\20260901开学点名册批量制作\00上学期名单')
template_file = os.path.join(base_path, '00(模版)原始点名表.xlsx')
class_info_file = os.path.join(base_path, '01 班级信息表', '20260805班级信息表.xlsx')
output_template = os.path.join(base_path, f'02 {day}点名册模版_{names}.xlsx')
output_dir = os.path.join(base_path, f'03 {day}{names}所有点名册')
# 节假日配置中秋节放假是第10天,但是为了让文字靠中间,写在11天的位置上
holidays_config = {
'2026-09下': {11: '中秋节放假', },
'2026-10上': {4: '国庆节放假', },
'2027-01上': {2: '元旦节放假', }
}
# ===================== 样式配置 =====================
gray_fill = PatternFill(start_color='D3D3D3', end_color='D3D3D3', fill_type='solid')
holiday_font = Font(
name='宋体',
size=10,
bold=False,
color='000000'
)
holiday_fill = PatternFill(
start_color='D3D3D3',
end_color='D3D3D3',
fill_type='solid'
)
center_alignment = Alignment(horizontal='center', vertical='center')
# ===================== WPS进程清理工具(改:excel→wps/et) =====================
def kill_wps_processes():
try:
wps_procs = []
for proc in psutil.process_iter(['name']):
try:
proc_name = proc.name().lower()
# WPS主进程 wps.exe,表格子进程 et.exe
if proc_name in ('wps.exe', 'et.exe', 'wpp.exe'):
wps_procs.append(proc)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if wps_procs:
print(f"\n⚠️ 发现 {len(wps_procs)} 个残留WPS进程,开始清理...")
for proc in wps_procs:
try:
proc.terminate()
proc.wait(timeout=2)
print(f" ✅ 关闭WPS进程: PID={proc.pid} ({proc.name()})")
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
except Exception as e:
print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
else:
print("\n✅ 未发现残留WPS进程")
except Exception as e:
print(f"❌ 清理WPS进程失败: {str(e)}")
# ===================== Excel转PDF【WPS版本】 =====================
def excel_to_pdf(input_file, max_retry=2):
if not os.path.exists(input_file):
print(f"❌ PDF转换失败:文件不存在 - {input_file}")
return False
pdf_file = os.path.splitext(input_file)[0] + '.pdf'
for attempt in range(max_retry + 1):
kill_wps_processes()
time.sleep(0.8)
wps_app = None
wb = None
try:
# ===== 关键改动:WPS表格 COM ProgID =====
# Ket.Application = WPS表格(对应原 Excel.Application)
# 若报"无法创建对象",说明WPS是精简版,需重装完整版WPS
wps_app = Dispatch("Ket.Application")
wps_app.Visible = False
wps_app.DisplayAlerts = False
wps_app.EnableEvents = False
input_abs = os.path.abspath(input_file)
wb = wps_app.Workbooks.Open(input_abs)
# 先让WPS重新保存一次xlsx,消除openpyxl可能遗留的隐形格式/分页异常
try:
wb.Save()
except Exception as save_e:
print(f" ⚠️ WPS保存Excel失败(不影响PDF导出): {str(save_e)}")
for ws in wb.Worksheets:
ws.PageSetup.Orientation = 1 # 1=纵向, 2=横向
ws.PageSetup.Zoom = False
ws.PageSetup.FitToPagesTall = 1
ws.PageSetup.FitToPagesWide = 1
ws.PageSetup.CenterHorizontally = True
ws.PageSetup.CenterVertically = True
ws.PageSetup.LeftMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.RightMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.TopMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.BottomMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.HeaderMargin = wps_app.CentimetersToPoints(1.2)
ws.PageSetup.FooterMargin = wps_app.CentimetersToPoints(0.5)
ws.PageSetup.CenterHeader = f"&10&\"宋体\"{title2}"
# ws.PageSetup.CenterHeader = f"{title2}"
pdf_abs = os.path.abspath(pdf_file)
# WPS兼容Excel的ExportAsFixedFormat,Type=0 即PDF
wb.ExportAsFixedFormat(Type=0, Filename=pdf_abs, Quality=1)
print(f"✅ PDF转换完成(WPS导出+竖版+页眉): {os.path.basename(pdf_file)}")
return True
except Exception as e:
print(f"⚠️ 第{attempt+1}次转换失败: {str(e)}")
traceback.print_exc()
finally:
if wb:
try:
wb.Close(SaveChanges=False)
except:
pass
if wps_app:
try:
wps_app.Quit()
except:
pass
kill_wps_processes()
time.sleep(0.5)
print(f"❌ {os.path.basename(input_file)} 全部重试失败")
return False
# ===================== 节假日标记函数 =====================
def add_holiday_marks(workbook):
print("\n=== 开始添加节假日标记(文字黑+背景灰) ===")
for sheet_name in workbook.sheetnames:
ws = workbook[sheet_name]
if sheet_name in holidays_config:
holiday_days = holidays_config[sheet_name]
print(f"📅 工作表 {sheet_name}: 处理节假日 {list(holiday_days.keys())}日")
for day_num, holiday_text in holiday_days.items():
date_col = 3 + (day_num - 1) * 2
status_col = date_col + 1
if date_col <= ws.max_column and status_col <= ws.max_column:
for row in range(5, 6):
status_cell = ws.cell(row=row, column=status_col)
status_cell.value = holiday_text
status_cell.font = holiday_font
status_cell.fill = holiday_fill
status_cell.alignment = center_alignment
date_cell = ws.cell(row=row, column=date_col)
date_cell.fill = holiday_fill
date_cell.alignment = center_alignment
else:
print(f"⚠️ {sheet_name}工作表 {day_num}日列位置无效,跳过处理")
print("=== 节假日标记添加完成 ===")
return workbook
# ===================== 主流程执行 =====================
def main():
print("="*50)
print("🏫 幼儿园点名册批量生成系统(WPS导出版)")
print(f"📅 处理周期: {day}")
print(f"🏢 园区名称: {title2}")
print(f"📄 样式配置: 节假日(文字黑+背景灰)| 双休日(背景灰)")
print("="*50)
print("\n=== 初始化:清理残留WPS进程 ===")
kill_wps_processes()
os.makedirs(output_dir, exist_ok=True)
print(f"\n📁 输出目录准备完成: {output_dir}")
# 步骤1: 生成基础点名表模板
print("\n=== 步骤1: 生成基础点名表模板 ===")
template_wb = None
try:
if not os.path.exists(template_file):
print(f"❌ 模板生成失败:模板文件不存在 - {template_file}")
return
template_wb = openpyxl.load_workbook(template_file)
sheet_names = template_wb.sheetnames
sheet_count = len(sheet_names)
print(f"📋 原始模板工作表: {sheet_names} (共{sheet_count}个)")
months = ['2026-09', '2026-09', '2026-10', '2026-10',
'2026-11', '2026-11', '2026-12', '2026-12',
'2027-01', '2027-01', "2026-09"]
if len(months) != sheet_count:
months = months[:sheet_count]
print(f"⚠️ 日期列表已调整为 {len(months)} 个,与工作表数量匹配")
new_sheet_names = []
for i in range(sheet_count):
suffix = sheet_names[i][-1:] if len(sheet_names[i]) >= 1 else ''
new_name = f"{months[i]}{suffix}"
new_sheet_names.append(new_name)
print(f"🔖 新工作表名称: {new_sheet_names}")
for i in range(min(len(sheet_names), len(new_sheet_names))):
old_name = sheet_names[i]
new_name = new_sheet_names[i]
template_wb[old_name].title = new_name
print(f" ✅ 重命名: {old_name} → {new_name}")
xx = [
[5,6,12,13,16], [19,25,26,27,31],
[1,2,3,4,5,6,7,11,], [16,17,18,24,25,31],
[1,7,8,14,15,16], [21,22,28,29,31],
[5,6,12,13,16], [19,20,26,27,],
[1,2,3,9,10,16], [16,17,23,24,25,26,27,28,29,30,31],
[],
]
if len(xx) < sheet_count:
while len(xx) < sheet_count:
xx.append(xx[-1])
print(f"⚠️ 双休日配置已补充至 {len(xx)} 个")
for bg_idx in range(sheet_count):
if bg_idx < len(template_wb.worksheets):
ws = template_wb.worksheets[bg_idx]
current_sheet = new_sheet_names[bg_idx] if bg_idx < len(new_sheet_names) else f"Sheet{bg_idx+1}"
if len(current_sheet) >= 7:
ws['AB3'] = current_sheet[-3:-1]
ws['W3'] = current_sheet[:4]
else:
ws['AB3'] = '09'
ws['W3'] = '2026'
ws['A2'] = f"{title1} {title2} 点名表"
ws.merge_cells('A2:AH2')
if bg_idx < len(xx):
target_days = xx[bg_idx]
else:
target_days = []
print(f"⚠️ 工作表{bg_idx+1}无双休日配置")
for day_num in target_days:
try:
if bg_idx % 2 == 0:
col_start = day_num * 2 + 1
col_end = day_num * 2 + 2
else:
col_start = (day_num - 15) * 2 + 1
col_end = (day_num - 15) * 2 + 2
if col_start <= ws.max_column and col_end <= ws.max_column:
for row in range(4, 43):
for col in range(col_start, col_end + 1):
ws.cell(row=row, column=col).fill = gray_fill
else:
print(f" ⚠️ 列超出范围: 开始{col_start}, 结束{col_end}, 最大{ws.max_column}")
except Exception as e:
print(f" ❌ 处理日期{day_num}失败: {str(e)}")
template_wb = add_holiday_marks(template_wb)
template_wb.save(output_template)
print(f"✅ 基础模板生成完成: {os.path.basename(output_template)}")
except Exception as e:
print(f"❌ 模板生成失败: {str(e)}")
traceback.print_exc()
finally:
if template_wb:
try:
template_wb.close()
print(f"✅ 关闭模板工作簿")
except Exception as e:
print(f"❌ 关闭模板工作簿失败: {str(e)}")
kill_wps_processes()
# 步骤2: 批量生成班级点名表
print("\n=== 步骤2: 批量生成班级点名表 ===")
class_info_wb = None
try:
if not os.path.exists(class_info_file):
print(f"❌ 班级点名表生成失败:班级信息表不存在 - {class_info_file}")
return
class_info_wb = openpyxl.load_workbook(class_info_file)
class_sheets = class_info_wb.worksheets[1:] if len(class_info_wb.worksheets) > 1 else []
counter = 0
print(f"📥 读取到 {len(class_sheets)} 个班级信息")
for class_sheet in class_sheets:
current_class_wb = None
try:
class_name = class_sheet.title
print(f"\n🏫 处理班级: {class_name}")
campus_info = class_sheet['B2'].value if class_sheet['B2'].value else ""
student_names = []
for row in range(2, 37):
try:
name_val = class_sheet.cell(row=row, column=4).value
student_names.append(name_val if name_val is not None else "")
except Exception as e:
print(f" ⚠️ 读取行{row}姓名失败: {str(e)}")
student_names.append("")
male_count = 0
female_count = 0
for row in range(2, 37):
try:
gender = class_sheet.cell(row=row, column=5).value
if gender == "男":
male_count += 1
elif gender == "女":
female_count += 1
except Exception as e:
print(f" ⚠️ 读取行{row}性别失败: {str(e)}")
class_sheet['E37'] = female_count
class_sheet['E38'] = male_count
print(f"👥 学生统计: 男{male_count}人, 女{female_count}人 (共{male_count+female_count}人)")
if not os.path.exists(output_template):
print(f" ❌ 加载模板失败:模板文件不存在 - {output_template}")
continue
current_class_wb = openpyxl.load_workbook(output_template)
if len(class_name) >= 2:
formatted_class = f"{class_name[0]}({class_name[1]})班"
else:
formatted_class = f"{class_name}班"
total_sheets = len(current_class_wb.worksheets)
for ws_idx, ws in enumerate(current_class_wb.worksheets):
try:
if ws_idx == total_sheets - 1:
# 最后一张统计表
ws.unmerge_cells("A2:AH2")
ws['A2'] = f"{title1} {formatted_class} 统计单"
ws.merge_cells('A2:T2')
ws['W3'] = None
ws['AB3'] = None
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
print(f" 📌 最后一张统计表【{ws.title}】标题:{title1} {formatted_class} 统计单")
continue
# 普通点名表
ws['A2'] = f"{title1} {title2}({campus_info}) 点名册"
ws.merge_cells('A2:AH2')
ws['C3'] = formatted_class
ws.merge_cells('C3:G3')
ws['L3'] = male_count
ws.merge_cells('L3:M3')
ws['S3'] = female_count
ws.merge_cells('S3:T3')
ws.merge_cells('W3:Z3')
ws.merge_cells('AB3:AC3')
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
else:
print(f" ⚠️ 行{idx+5}超出表格范围,跳过写入")
for i in range(16):
start_col = 3 + 2 * i
end_col = 3 + 2 * i + 1
if start_col <= ws.max_column and end_col <= ws.max_column:
ws.merge_cells(start_row=4, start_column=start_col,
end_row=4, end_column=end_col)
else:
print(f" ⚠️ 合并列超出范围: {start_col}-{end_col},跳过")
except Exception as e:
print(f" ❌ 配置工作表失败: {str(e)}")
class_excel_path = os.path.join(output_dir, f"01_{day}_班级点名表_{formatted_class[0]}{formatted_class[2]}班_{names}.xlsx")
try:
current_class_wb.save(class_excel_path)
print(f"✅ Excel文件生成: {os.path.basename(class_excel_path)}")
# ===== WPS 打开 → 保存 → 导出PDF =====
excel_to_pdf(class_excel_path)
counter += 1
except Exception as e:
print(f" ❌ 保存Excel文件失败: {str(e)}")
traceback.print_exc()
except Exception as e:
print(f"❌ 处理班级{class_name}失败: {str(e)}")
traceback.print_exc()
finally:
if current_class_wb:
try:
current_class_wb.close()
print(f" ✅ 关闭班级模板工作簿")
except Exception as e:
print(f" ❌ 关闭班级工作簿失败: {str(e)}")
kill_wps_processes()
class_info_wb.save(class_info_file)
print(f"\n=== 批量处理完成 ===")
print(f"📊 总计处理班级: {counter} 个")
print(f"📁 所有文件保存路径: {output_dir}")
except Exception as e:
print(f"❌ 班级点名表批量生成失败: {str(e)}")
traceback.print_exc()
finally:
if class_info_wb:
try:
class_info_wb.close()
print(f"✅ 关闭班级信息表工作簿")
except Exception as e:
print(f"❌ 关闭班级信息表失败: {str(e)}")
print("\n=== 最终清理:确认无残留WPS进程 ===")
kill_wps_processes()
print(f"\n✅ 所有操作完成!")
# ===================== 执行主程序 =====================
if __name__ == "__main__":
required_packages = ['openpyxl', 'pywin32', 'psutil']
missing_packages = []
for pkg in required_packages:
try:
__import__(pkg)
except ImportError:
missing_packages.append(pkg)
if missing_packages:
print(f"⚠️ 发现缺失依赖包: {', '.join(missing_packages)},正在自动安装...")
import subprocess
import sys
for pkg in missing_packages:
subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
print("✅ 所有依赖包安装完成")
main()
最后我做了一个合并版(隐藏微软的部分)


'''
上学期点名册批量(灰色)
1、修改原始模版,更改年月、标题、页眉
2、读取所有的EXCEL,批量制作EXCEL多月
3、添加“清明节放假”等汉字
4、每页标题包含园区)
5、添加最后一张空白统计表
6、用微软office或金山WPS打开(根据电脑上装的软件自选,建议用WPS) 转成PDF,便于打印
deepseek、豆包、阿夏
20260808
'''
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment
from datetime import datetime, timedelta
import os
from win32com.client import Dispatch
import traceback
import time
import psutil
# ===================== 基础配置 =====================
day = '202609'
title1 = '2026学年第一学期'
title2 = '上海市闵行区太阳蓝天幼儿园'
names = '太阳'
# 文件路径配置
base_path = os.path.abspath(r'D:\Python最终内容\20260901开学点名册批量制作\00上学期名单')
template_file = os.path.join(base_path, '00(模版)原始点名表.xlsx')
class_info_file = os.path.join(base_path, '01 班级信息表', '20260805班级信息表.xlsx')
output_template = os.path.join(base_path, f'02 {day}点名册模版_{names}.xlsx')
output_dir = os.path.join(base_path, f'03 {day}{names}所有点名册')
# 节假日配置中秋节放假是第10天,但是为了让文字靠中间,写在11天的位置上
holidays_config = {
'2026-09下': {11: '中秋节放假', },
'2026-10上': {4: '国庆节放假', },
'2027-01上': {2: '元旦节放假', }
}
# ===================== 样式配置 =====================
gray_fill = PatternFill(start_color='D3D3D3', end_color='D3D3D3', fill_type='solid')
holiday_font = Font(
name='宋体',
size=10,
bold=False,
color='000000'
)
holiday_fill = PatternFill(
start_color='D3D3D3',
end_color='D3D3D3',
fill_type='solid'
)
center_alignment = Alignment(horizontal='center', vertical='center')
# ===================== WPS进程清理工具(改:excel→wps/et) =====================
def kill_wps_processes():
try:
wps_procs = []
for proc in psutil.process_iter(['name']):
try:
proc_name = proc.name().lower()
# WPS主进程 wps.exe,表格子进程 et.exe
if proc_name in ('wps.exe', 'et.exe', 'wpp.exe'):
wps_procs.append(proc)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if wps_procs:
print(f"\n⚠️ 发现 {len(wps_procs)} 个残留WPS进程,开始清理...")
for proc in wps_procs:
try:
proc.terminate()
proc.wait(timeout=2)
print(f" ✅ 关闭WPS进程: PID={proc.pid} ({proc.name()})")
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
except Exception as e:
print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
else:
print("\n✅ 未发现残留WPS进程")
except Exception as e:
print(f"❌ 清理WPS进程失败: {str(e)}")
# # ===================== 微软Excel进程清理工具 =====================
# def kill_excel_processes():
# try:
# excel_procs = []
# for proc in psutil.process_iter(['name', 'cmdline']):
# try:
# proc_name = proc.name().lower()
# if 'excel' in proc_name and any('office' in cmd.lower() for cmd in proc.cmdline()):
# excel_procs.append(proc)
# except (psutil.NoSuchProcess, psutil.AccessDenied, IndexError):
# continue
# if excel_procs:
# print(f"\n⚠️ 发现 {len(excel_procs)} 个残留Excel进程,开始清理...")
# for proc in excel_procs:
# try:
# proc.terminate()
# proc.wait(timeout=2)
# print(f" ✅ 关闭Excel进程: PID={proc.pid}")
# except (psutil.NoSuchProcess, psutil.TimeoutExpired):
# print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
# except Exception as e:
# print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
# else:
# print("\n✅ 未发现残留Excel进程")
# except Exception as e:
# print(f"❌ 清理Excel进程失败: {str(e)}")
# ===================== Excel转PDF【WPS版本】 =====================
def excel_to_pdf(input_file, max_retry=2):
if not os.path.exists(input_file):
print(f"❌ PDF转换失败:文件不存在 - {input_file}")
return False
pdf_file = os.path.splitext(input_file)[0] + '.pdf'
for attempt in range(max_retry + 1):
kill_wps_processes()
time.sleep(0.8)
wps_app = None
wb = None
try:
# ===== 关键改动:WPS表格 COM ProgID =====
# Ket.Application = WPS表格(对应原 Excel.Application)
# 若报"无法创建对象",说明WPS是精简版,需重装完整版WPS
wps_app = Dispatch("Ket.Application")
wps_app.Visible = False
wps_app.DisplayAlerts = False
wps_app.EnableEvents = False
input_abs = os.path.abspath(input_file)
wb = wps_app.Workbooks.Open(input_abs)
# 先让WPS重新保存一次xlsx,消除openpyxl可能遗留的隐形格式/分页异常
try:
wb.Save()
except Exception as save_e:
print(f" ⚠️ WPS保存Excel失败(不影响PDF导出): {str(save_e)}")
for ws in wb.Worksheets:
ws.PageSetup.Orientation = 1 # 1=纵向, 2=横向
ws.PageSetup.Zoom = False
ws.PageSetup.FitToPagesTall = 1
ws.PageSetup.FitToPagesWide = 1
ws.PageSetup.CenterHorizontally = True
ws.PageSetup.CenterVertically = True
ws.PageSetup.LeftMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.RightMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.TopMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.BottomMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.HeaderMargin = wps_app.CentimetersToPoints(1.2)
ws.PageSetup.FooterMargin = wps_app.CentimetersToPoints(0.5)
ws.PageSetup.CenterHeader = f"&10&\"宋体\"{title2}"
# ws.PageSetup.CenterHeader = f"{title2}"
pdf_abs = os.path.abspath(pdf_file)
# WPS兼容Excel的ExportAsFixedFormat,Type=0 即PDF
wb.ExportAsFixedFormat(Type=0, Filename=pdf_abs, Quality=1)
print(f"✅ PDF转换完成(WPS导出+竖版+页眉): {os.path.basename(pdf_file)}")
return True
except Exception as e:
print(f"⚠️ 第{attempt+1}次转换失败: {str(e)}")
traceback.print_exc()
finally:
if wb:
try:
wb.Close(SaveChanges=False)
except:
pass
if wps_app:
try:
wps_app.Quit()
except:
pass
kill_wps_processes()
time.sleep(0.5)
print(f"❌ {os.path.basename(input_file)} 全部重试失败")
return False
# ===================== 节假日标记函数 =====================
def add_holiday_marks(workbook):
print("\n=== 开始添加节假日标记(文字黑+背景灰) ===")
for sheet_name in workbook.sheetnames:
ws = workbook[sheet_name]
if sheet_name in holidays_config:
holiday_days = holidays_config[sheet_name]
print(f"📅 工作表 {sheet_name}: 处理节假日 {list(holiday_days.keys())}日")
for day_num, holiday_text in holiday_days.items():
date_col = 3 + (day_num - 1) * 2
status_col = date_col + 1
if date_col <= ws.max_column and status_col <= ws.max_column:
for row in range(5, 6):
status_cell = ws.cell(row=row, column=status_col)
status_cell.value = holiday_text
status_cell.font = holiday_font
status_cell.fill = holiday_fill
status_cell.alignment = center_alignment
date_cell = ws.cell(row=row, column=date_col)
date_cell.fill = holiday_fill
date_cell.alignment = center_alignment
else:
print(f"⚠️ {sheet_name}工作表 {day_num}日列位置无效,跳过处理")
print("=== 节假日标记添加完成 ===")
return workbook
# ===================== 主流程执行 =====================
def main():
print("="*50)
print("🏫 幼儿园点名册批量生成系统(WPS导出版)")
print(f"📅 处理周期: {day}")
print(f"🏢 园区名称: {title2}")
print(f"📄 样式配置: 节假日(文字黑+背景灰)| 双休日(背景灰)")
print("="*50)
print("\n=== 初始化:清理残留WPS进程 ===")
kill_wps_processes()
os.makedirs(output_dir, exist_ok=True)
print(f"\n📁 输出目录准备完成: {output_dir}")
# 步骤1: 生成基础点名表模板
print("\n=== 步骤1: 生成基础点名表模板 ===")
template_wb = None
try:
if not os.path.exists(template_file):
print(f"❌ 模板生成失败:模板文件不存在 - {template_file}")
return
template_wb = openpyxl.load_workbook(template_file)
sheet_names = template_wb.sheetnames
sheet_count = len(sheet_names)
print(f"📋 原始模板工作表: {sheet_names} (共{sheet_count}个)")
months = ['2026-09', '2026-09', '2026-10', '2026-10',
'2026-11', '2026-11', '2026-12', '2026-12',
'2027-01', '2027-01', "2026-09"]
if len(months) != sheet_count:
months = months[:sheet_count]
print(f"⚠️ 日期列表已调整为 {len(months)} 个,与工作表数量匹配")
new_sheet_names = []
for i in range(sheet_count):
suffix = sheet_names[i][-1:] if len(sheet_names[i]) >= 1 else ''
new_name = f"{months[i]}{suffix}"
new_sheet_names.append(new_name)
print(f"🔖 新工作表名称: {new_sheet_names}")
for i in range(min(len(sheet_names), len(new_sheet_names))):
old_name = sheet_names[i]
new_name = new_sheet_names[i]
template_wb[old_name].title = new_name
print(f" ✅ 重命名: {old_name} → {new_name}")
xx = [
[5,6,12,13,16], [19,25,26,27,31],
[1,2,3,4,5,6,7,11,], [16,17,18,24,25,31],
[1,7,8,14,15,16], [21,22,28,29,31],
[5,6,12,13,16], [19,20,26,27,],
[1,2,3,9,10,16], [16,17,23,24,25,26,27,28,29,30,31],
[],
]
if len(xx) < sheet_count:
while len(xx) < sheet_count:
xx.append(xx[-1])
print(f"⚠️ 双休日配置已补充至 {len(xx)} 个")
for bg_idx in range(sheet_count):
if bg_idx < len(template_wb.worksheets):
ws = template_wb.worksheets[bg_idx]
current_sheet = new_sheet_names[bg_idx] if bg_idx < len(new_sheet_names) else f"Sheet{bg_idx+1}"
if len(current_sheet) >= 7:
ws['AB3'] = current_sheet[-3:-1]
ws['W3'] = current_sheet[:4]
else:
ws['AB3'] = '09'
ws['W3'] = '2026'
ws['A2'] = f"{title1} {title2} 点名表"
ws.merge_cells('A2:AH2')
if bg_idx < len(xx):
target_days = xx[bg_idx]
else:
target_days = []
print(f"⚠️ 工作表{bg_idx+1}无双休日配置")
for day_num in target_days:
try:
if bg_idx % 2 == 0:
col_start = day_num * 2 + 1
col_end = day_num * 2 + 2
else:
col_start = (day_num - 15) * 2 + 1
col_end = (day_num - 15) * 2 + 2
if col_start <= ws.max_column and col_end <= ws.max_column:
for row in range(4, 43):
for col in range(col_start, col_end + 1):
ws.cell(row=row, column=col).fill = gray_fill
else:
print(f" ⚠️ 列超出范围: 开始{col_start}, 结束{col_end}, 最大{ws.max_column}")
except Exception as e:
print(f" ❌ 处理日期{day_num}失败: {str(e)}")
template_wb = add_holiday_marks(template_wb)
template_wb.save(output_template)
print(f"✅ 基础模板生成完成: {os.path.basename(output_template)}")
except Exception as e:
print(f"❌ 模板生成失败: {str(e)}")
traceback.print_exc()
finally:
if template_wb:
try:
template_wb.close()
print(f"✅ 关闭模板工作簿")
except Exception as e:
print(f"❌ 关闭模板工作簿失败: {str(e)}")
kill_wps_processes()
# 步骤2: 批量生成班级点名表
print("\n=== 步骤2: 批量生成班级点名表 ===")
class_info_wb = None
try:
if not os.path.exists(class_info_file):
print(f"❌ 班级点名表生成失败:班级信息表不存在 - {class_info_file}")
return
class_info_wb = openpyxl.load_workbook(class_info_file)
class_sheets = class_info_wb.worksheets[1:] if len(class_info_wb.worksheets) > 1 else []
counter = 0
print(f"📥 读取到 {len(class_sheets)} 个班级信息")
for class_sheet in class_sheets:
current_class_wb = None
try:
class_name = class_sheet.title
print(f"\n🏫 处理班级: {class_name}")
campus_info = class_sheet['B2'].value if class_sheet['B2'].value else ""
student_names = []
for row in range(2, 37):
try:
name_val = class_sheet.cell(row=row, column=4).value
student_names.append(name_val if name_val is not None else "")
except Exception as e:
print(f" ⚠️ 读取行{row}姓名失败: {str(e)}")
student_names.append("")
male_count = 0
female_count = 0
for row in range(2, 37):
try:
gender = class_sheet.cell(row=row, column=5).value
if gender == "男":
male_count += 1
elif gender == "女":
female_count += 1
except Exception as e:
print(f" ⚠️ 读取行{row}性别失败: {str(e)}")
class_sheet['E37'] = female_count
class_sheet['E38'] = male_count
print(f"👥 学生统计: 男{male_count}人, 女{female_count}人 (共{male_count+female_count}人)")
if not os.path.exists(output_template):
print(f" ❌ 加载模板失败:模板文件不存在 - {output_template}")
continue
current_class_wb = openpyxl.load_workbook(output_template)
if len(class_name) >= 2:
formatted_class = f"{class_name[0]}({class_name[1]})班"
else:
formatted_class = f"{class_name}班"
total_sheets = len(current_class_wb.worksheets)
for ws_idx, ws in enumerate(current_class_wb.worksheets):
try:
if ws_idx == total_sheets - 1:
# 最后一张统计表
ws.unmerge_cells("A2:AH2")
ws['A2'] = f"{title1} {formatted_class} 统计单"
ws.merge_cells('A2:T2')
ws['W3'] = None
ws['AB3'] = None
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
print(f" 📌 最后一张统计表【{ws.title}】标题:{title1} {formatted_class} 统计单")
continue
# 普通点名表
ws['A2'] = f"{title1} {title2}({campus_info}) 点名册"
ws.merge_cells('A2:AH2')
ws['C3'] = formatted_class
ws.merge_cells('C3:G3')
ws['L3'] = male_count
ws.merge_cells('L3:M3')
ws['S3'] = female_count
ws.merge_cells('S3:T3')
ws.merge_cells('W3:Z3')
ws.merge_cells('AB3:AC3')
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
else:
print(f" ⚠️ 行{idx+5}超出表格范围,跳过写入")
for i in range(16):
start_col = 3 + 2 * i
end_col = 3 + 2 * i + 1
if start_col <= ws.max_column and end_col <= ws.max_column:
ws.merge_cells(start_row=4, start_column=start_col,
end_row=4, end_column=end_col)
else:
print(f" ⚠️ 合并列超出范围: {start_col}-{end_col},跳过")
except Exception as e:
print(f" ❌ 配置工作表失败: {str(e)}")
class_excel_path = os.path.join(output_dir, f"01_{day}_班级点名表_{formatted_class[0]}{formatted_class[2]}班_{names}.xlsx")
try:
current_class_wb.save(class_excel_path)
print(f"✅ Excel文件生成: {os.path.basename(class_excel_path)}")
# ===== WPS 打开 → 保存 → 导出PDF =====
excel_to_pdf(class_excel_path)
counter += 1
except Exception as e:
print(f" ❌ 保存Excel文件失败: {str(e)}")
traceback.print_exc()
except Exception as e:
print(f"❌ 处理班级{class_name}失败: {str(e)}")
traceback.print_exc()
finally:
if current_class_wb:
try:
current_class_wb.close()
print(f" ✅ 关闭班级模板工作簿")
except Exception as e:
print(f" ❌ 关闭班级工作簿失败: {str(e)}")
kill_wps_processes()
class_info_wb.save(class_info_file)
print(f"\n=== 批量处理完成 ===")
print(f"📊 总计处理班级: {counter} 个")
print(f"📁 所有文件保存路径: {output_dir}")
except Exception as e:
print(f"❌ 班级点名表批量生成失败: {str(e)}")
traceback.print_exc()
finally:
if class_info_wb:
try:
class_info_wb.close()
print(f"✅ 关闭班级信息表工作簿")
except Exception as e:
print(f"❌ 关闭班级信息表失败: {str(e)}")
print("\n=== 最终清理:确认无残留WPS进程 ===")
kill_wps_processes()
print(f"\n✅ 所有操作完成!")
# ===================== 执行主程序 =====================
if __name__ == "__main__":
required_packages = ['openpyxl', 'pywin32', 'psutil']
missing_packages = []
for pkg in required_packages:
try:
__import__(pkg)
except ImportError:
missing_packages.append(pkg)
if missing_packages:
print(f"⚠️ 发现缺失依赖包: {', '.join(missing_packages)},正在自动安装...")
import subprocess
import sys
for pkg in missing_packages:
subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
print("✅ 所有依赖包安装完成")
main()

感悟:
只要想得到,就没有AI编程做不到。设计“统计表”,全部依靠AI编程来实现。
我搭档骨折要修养到10月中旬,我应该还是进中2班当班主任,这些批量表单就能够真实实用,感知它们的效果和后续要调整优化的思路。
为了确保安全,我在这份CSDN里面把这次辛辛苦苦调整的“Excel模版”和“收集班级幼儿信息的Excel(做共享编辑)”也上传,避免下次再重做模版。

上传后等5分钟。再点击浏览网页

资源在顶部

下载自己的资源,可以免费

晕,只下载了第二次上传的班级信息收集表,第一次上传的点名册模版没有了,

只能上传一个,所以两个Excel要打包成一个rar


保存页面,再打开浏览,还是这个名字

下载内容是打包文件

因为下载的总是最后一份,所以到下载里面吧文件删除,重新上传


再次上传一个rar

--------20260816修改--------
制作圆牌时,发现需要凑满6的倍数。那么
年级 | 最大班额 | 圆牌每页几张 | 最少几页 | 共多少圆牌人数 |
托班 | 20 | 6 | 4 | 24 |
小班 | 25 | 6 | 5 | 30 |
中班 | 30 | 6 | 5 | 30 |
大班 | 35 | 6 | 6 | 36 |




修改


再加一个时间计算
最后代码
'''
上学期点名册批量(灰色)
1、修改原始模版,更改年月、标题、页眉
2、读取所有的EXCEL,批量制作EXCEL多月
3、添加“清明节放假”等汉字
4、每页标题包含园区)
5、添加最后一张空白统计表
6、用微软office或金山WPS打开(根据电脑上装的软件自选,建议用WPS) 转成PDF,便于打印
deepseek、豆包、阿夏
20260808
'''
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment
from datetime import datetime, timedelta
import os
from win32com.client import Dispatch
import traceback
import time
import psutil
# ========== 记录程序开始时间 ==========
import time
start_time = time.time()
# ===================== 基础配置 =====================
day = '202609'
title1 = '2026学年第一学期'
title2 = '上海市XXXX幼儿园'
names = 'XX'
# 文件路径配置
base_path = os.path.abspath(r'D:\Python最终内容\20260901开学点名册批量制作\00上学期名单')
template_file = os.path.join(base_path, '00(模版)原始点名表.xlsx')
class_info_file = os.path.join(base_path, '01 20260805班级信息表.xlsx')
output_template = os.path.join(base_path, f'02 {day}点名册模版_{names}.xlsx')
output_dir = os.path.join(base_path, f'03 {day}{names}所有点名册')
# 节假日配置中秋节放假是第10天,但是为了让文字靠中间,写在11天的位置上
holidays_config = {
'2026-09下': {11: '中秋节放假', },
'2026-10上': {4: '国庆节放假', },
'2027-01上': {2: '元旦节放假', }
}
# ===================== 样式配置 =====================
gray_fill = PatternFill(start_color='D3D3D3', end_color='D3D3D3', fill_type='solid')
holiday_font = Font(
name='宋体',
size=10,
bold=False,
color='000000'
)
holiday_fill = PatternFill(
start_color='D3D3D3',
end_color='D3D3D3',
fill_type='solid'
)
center_alignment = Alignment(horizontal='center', vertical='center')
# ===================== WPS进程清理工具(改:excel→wps/et) =====================
def kill_wps_processes():
try:
wps_procs = []
for proc in psutil.process_iter(['name']):
try:
proc_name = proc.name().lower()
# WPS主进程 wps.exe,表格子进程 et.exe
if proc_name in ('wps.exe', 'et.exe', 'wpp.exe'):
wps_procs.append(proc)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if wps_procs:
print(f"\n⚠️ 发现 {len(wps_procs)} 个残留WPS进程,开始清理...")
for proc in wps_procs:
try:
proc.terminate()
proc.wait(timeout=2)
print(f" ✅ 关闭WPS进程: PID={proc.pid} ({proc.name()})")
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
except Exception as e:
print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
else:
print("\n✅ 未发现残留WPS进程")
except Exception as e:
print(f"❌ 清理WPS进程失败: {str(e)}")
# # ===================== 微软Excel进程清理工具 =====================
# def kill_excel_processes():
# try:
# excel_procs = []
# for proc in psutil.process_iter(['name', 'cmdline']):
# try:
# proc_name = proc.name().lower()
# if 'excel' in proc_name and any('office' in cmd.lower() for cmd in proc.cmdline()):
# excel_procs.append(proc)
# except (psutil.NoSuchProcess, psutil.AccessDenied, IndexError):
# continue
# if excel_procs:
# print(f"\n⚠️ 发现 {len(excel_procs)} 个残留Excel进程,开始清理...")
# for proc in excel_procs:
# try:
# proc.terminate()
# proc.wait(timeout=2)
# print(f" ✅ 关闭Excel进程: PID={proc.pid}")
# except (psutil.NoSuchProcess, psutil.TimeoutExpired):
# print(f" ⚠️ 进程 {proc.pid} 已退出或超时")
# except Exception as e:
# print(f" ❌ 关闭进程 {proc.pid} 失败: {str(e)}")
# else:
# print("\n✅ 未发现残留Excel进程")
# except Exception as e:
# print(f"❌ 清理Excel进程失败: {str(e)}")
# ===================== Excel转PDF【WPS版本】 =====================
def excel_to_pdf(input_file, max_retry=2):
if not os.path.exists(input_file):
print(f"❌ PDF转换失败:文件不存在 - {input_file}")
return False
pdf_file = os.path.splitext(input_file)[0] + '.pdf'
for attempt in range(max_retry + 1):
kill_wps_processes()
time.sleep(0.8)
wps_app = None
wb = None
try:
# ===== 关键改动:WPS表格 COM ProgID =====
# Ket.Application = WPS表格(对应原 Excel.Application)
# 若报"无法创建对象",说明WPS是精简版,需重装完整版WPS
wps_app = Dispatch("Ket.Application")
wps_app.Visible = False
wps_app.DisplayAlerts = False
wps_app.EnableEvents = False
input_abs = os.path.abspath(input_file)
wb = wps_app.Workbooks.Open(input_abs)
# 先让WPS重新保存一次xlsx,消除openpyxl可能遗留的隐形格式/分页异常
try:
wb.Save()
except Exception as save_e:
print(f" ⚠️ WPS保存Excel失败(不影响PDF导出): {str(save_e)}")
for ws in wb.Worksheets:
ws.PageSetup.Orientation = 1 # 1=纵向, 2=横向
ws.PageSetup.Zoom = False
ws.PageSetup.FitToPagesTall = 1
ws.PageSetup.FitToPagesWide = 1
ws.PageSetup.CenterHorizontally = True
ws.PageSetup.CenterVertically = True
ws.PageSetup.LeftMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.RightMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.TopMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.BottomMargin = wps_app.CentimetersToPoints(1)
ws.PageSetup.HeaderMargin = wps_app.CentimetersToPoints(1.2)
ws.PageSetup.FooterMargin = wps_app.CentimetersToPoints(0.5)
ws.PageSetup.CenterHeader = f"&10&\"宋体\"{title2}"
# ws.PageSetup.CenterHeader = f"{title2}"
pdf_abs = os.path.abspath(pdf_file)
# WPS兼容Excel的ExportAsFixedFormat,Type=0 即PDF
wb.ExportAsFixedFormat(Type=0, Filename=pdf_abs, Quality=1)
print(f"✅ PDF转换完成(WPS导出+竖版+页眉): {os.path.basename(pdf_file)}")
return True
except Exception as e:
print(f"⚠️ 第{attempt+1}次转换失败: {str(e)}")
traceback.print_exc()
finally:
if wb:
try:
wb.Close(SaveChanges=False)
except:
pass
if wps_app:
try:
wps_app.Quit()
except:
pass
kill_wps_processes()
time.sleep(0.5)
print(f"❌ {os.path.basename(input_file)} 全部重试失败")
return False
# ===================== 节假日标记函数 =====================
def add_holiday_marks(workbook):
print("\n=== 开始添加节假日标记(文字黑+背景灰) ===")
for sheet_name in workbook.sheetnames:
ws = workbook[sheet_name]
if sheet_name in holidays_config:
holiday_days = holidays_config[sheet_name]
print(f"📅 工作表 {sheet_name}: 处理节假日 {list(holiday_days.keys())}日")
for day_num, holiday_text in holiday_days.items():
date_col = 3 + (day_num - 1) * 2
status_col = date_col + 1
if date_col <= ws.max_column and status_col <= ws.max_column:
for row in range(5, 6):
status_cell = ws.cell(row=row, column=status_col)
status_cell.value = holiday_text
status_cell.font = holiday_font
status_cell.fill = holiday_fill
status_cell.alignment = center_alignment
date_cell = ws.cell(row=row, column=date_col)
date_cell.fill = holiday_fill
date_cell.alignment = center_alignment
else:
print(f"⚠️ {sheet_name}工作表 {day_num}日列位置无效,跳过处理")
print("=== 节假日标记添加完成 ===")
return workbook
# ===================== 主流程执行 =====================
def main():
print("="*50)
print("🏫 幼儿园点名册批量生成系统(WPS导出版)")
print(f"📅 处理周期: {day}")
print(f"🏢 园区名称: {title2}")
print(f"📄 样式配置: 节假日(文字黑+背景灰)| 双休日(背景灰)")
print("="*50)
print("\n=== 初始化:清理残留WPS进程 ===")
kill_wps_processes()
os.makedirs(output_dir, exist_ok=True)
print(f"\n📁 输出目录准备完成: {output_dir}")
# 步骤1: 生成基础点名表模板
print("\n=== 步骤1: 生成基础点名表模板 ===")
template_wb = None
try:
if not os.path.exists(template_file):
print(f"❌ 模板生成失败:模板文件不存在 - {template_file}")
return
template_wb = openpyxl.load_workbook(template_file)
sheet_names = template_wb.sheetnames
sheet_count = len(sheet_names)
print(f"📋 原始模板工作表: {sheet_names} (共{sheet_count}个)")
months = ['2026-09', '2026-09', '2026-10', '2026-10',
'2026-11', '2026-11', '2026-12', '2026-12',
'2027-01', '2027-01', "2026-09"]
if len(months) != sheet_count:
months = months[:sheet_count]
print(f"⚠️ 日期列表已调整为 {len(months)} 个,与工作表数量匹配")
new_sheet_names = []
for i in range(sheet_count):
suffix = sheet_names[i][-1:] if len(sheet_names[i]) >= 1 else ''
new_name = f"{months[i]}{suffix}"
new_sheet_names.append(new_name)
print(f"🔖 新工作表名称: {new_sheet_names}")
for i in range(min(len(sheet_names), len(new_sheet_names))):
old_name = sheet_names[i]
new_name = new_sheet_names[i]
template_wb[old_name].title = new_name
print(f" ✅ 重命名: {old_name} → {new_name}")
xx = [
[5,6,12,13,16], [19,25,26,27,31],
[1,2,3,4,5,6,7,11,], [16,17,18,24,25,31],
[1,7,8,14,15,16], [21,22,28,29,31],
[5,6,12,13,16], [19,20,26,27,],
[1,2,3,9,10,16], [16,17,23,24,25,26,27,28,29,30,31],
[],
]
if len(xx) < sheet_count:
while len(xx) < sheet_count:
xx.append(xx[-1])
print(f"⚠️ 双休日配置已补充至 {len(xx)} 个")
for bg_idx in range(sheet_count):
if bg_idx < len(template_wb.worksheets):
ws = template_wb.worksheets[bg_idx]
current_sheet = new_sheet_names[bg_idx] if bg_idx < len(new_sheet_names) else f"Sheet{bg_idx+1}"
if len(current_sheet) >= 7:
ws['AB3'] = current_sheet[-3:-1]
ws['W3'] = current_sheet[:4]
else:
ws['AB3'] = '09'
ws['W3'] = '2026'
ws['A2'] = f"{title1} {title2} 点名表"
ws.merge_cells('A2:AH2')
if bg_idx < len(xx):
target_days = xx[bg_idx]
else:
target_days = []
print(f"⚠️ 工作表{bg_idx+1}无双休日配置")
for day_num in target_days:
try:
if bg_idx % 2 == 0:
col_start = day_num * 2 + 1
col_end = day_num * 2 + 2
else:
col_start = (day_num - 15) * 2 + 1
col_end = (day_num - 15) * 2 + 2
if col_start <= ws.max_column and col_end <= ws.max_column:
for row in range(4, 43):
for col in range(col_start, col_end + 1):
ws.cell(row=row, column=col).fill = gray_fill
else:
print(f" ⚠️ 列超出范围: 开始{col_start}, 结束{col_end}, 最大{ws.max_column}")
except Exception as e:
print(f" ❌ 处理日期{day_num}失败: {str(e)}")
template_wb = add_holiday_marks(template_wb)
template_wb.save(output_template)
print(f"✅ 基础模板生成完成: {os.path.basename(output_template)}")
except Exception as e:
print(f"❌ 模板生成失败: {str(e)}")
traceback.print_exc()
finally:
if template_wb:
try:
template_wb.close()
print(f"✅ 关闭模板工作簿")
except Exception as e:
print(f"❌ 关闭模板工作簿失败: {str(e)}")
kill_wps_processes()
# 步骤2: 批量生成班级点名表
print("\n=== 步骤2: 批量生成班级点名表 ===")
class_info_wb = None
try:
if not os.path.exists(class_info_file):
print(f"❌ 班级点名表生成失败:班级信息表不存在 - {class_info_file}")
return
class_info_wb = openpyxl.load_workbook(class_info_file)
# 从第一张表开始[1:],现在从[0:]开始
class_sheets = class_info_wb.worksheets[:] if len(class_info_wb.worksheets) > 1 else []
counter = 0
print(f"📥 读取到 {len(class_sheets)} 个班级信息")
for class_sheet in class_sheets:
current_class_wb = None
try:
class_name = class_sheet.title
print(f"\n🏫 处理班级: {class_name}")
campus_info = class_sheet['B2'].value if class_sheet['B2'].value else ""
student_names = []
for row in range(2, 37):
try:
name_val = class_sheet.cell(row=row, column=4).value
student_names.append(name_val if name_val is not None else "")
except Exception as e:
print(f" ⚠️ 读取行{row}姓名失败: {str(e)}")
student_names.append("")
male_count = 0
female_count = 0
for row in range(2, 37):
try:
gender = class_sheet.cell(row=row, column=5).value
if gender == "男":
male_count += 1
elif gender == "女":
female_count += 1
except Exception as e:
print(f" ⚠️ 读取行{row}性别失败: {str(e)}")
class_sheet['E40'] = female_count
class_sheet['E41'] = male_count
print(f"👥 学生统计: 男{male_count}人, 女{female_count}人 (共{male_count+female_count}人)")
if not os.path.exists(output_template):
print(f" ❌ 加载模板失败:模板文件不存在 - {output_template}")
continue
current_class_wb = openpyxl.load_workbook(output_template)
if len(class_name) >= 2:
formatted_class = f"{class_name[0]}({class_name[1]})班"
else:
formatted_class = f"{class_name}班"
total_sheets = len(current_class_wb.worksheets)
for ws_idx, ws in enumerate(current_class_wb.worksheets):
try:
if ws_idx == total_sheets - 1:
# 最后一张统计表
ws.unmerge_cells("A2:AH2")
ws['A2'] = f"{title1} {formatted_class} 统计单"
ws.merge_cells('A2:T2')
ws['W3'] = None
ws['AB3'] = None
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
print(f" 📌 最后一张统计表【{ws.title}】标题:{title1} {formatted_class} 统计单")
continue
# 普通点名表
ws['A2'] = f"{title1} {title2}({campus_info}) 点名册"
ws.merge_cells('A2:AH2')
ws['C3'] = formatted_class
ws.merge_cells('C3:G3')
ws['L3'] = male_count
ws.merge_cells('L3:M3')
ws['S3'] = female_count
ws.merge_cells('S3:T3')
ws.merge_cells('W3:Z3')
ws.merge_cells('AB3:AC3')
for idx, name in enumerate(student_names[:35]):
if idx + 5 <= ws.max_row:
ws.cell(row=idx + 5, column=2, value=name)
else:
print(f" ⚠️ 行{idx+5}超出表格范围,跳过写入")
for i in range(16):
start_col = 3 + 2 * i
end_col = 3 + 2 * i + 1
if start_col <= ws.max_column and end_col <= ws.max_column:
ws.merge_cells(start_row=4, start_column=start_col,
end_row=4, end_column=end_col)
else:
print(f" ⚠️ 合并列超出范围: {start_col}-{end_col},跳过")
except Exception as e:
print(f" ❌ 配置工作表失败: {str(e)}")
class_excel_path = os.path.join(output_dir, f"01_{day}_班级点名表_{formatted_class[0]}{formatted_class[2]}班_{names}.xlsx")
try:
current_class_wb.save(class_excel_path)
print(f"✅ Excel文件生成: {os.path.basename(class_excel_path)}")
# ===== WPS 打开 → 保存 → 导出PDF =====
excel_to_pdf(class_excel_path)
counter += 1
except Exception as e:
print(f" ❌ 保存Excel文件失败: {str(e)}")
traceback.print_exc()
except Exception as e:
print(f"❌ 处理班级{class_name}失败: {str(e)}")
traceback.print_exc()
finally:
if current_class_wb:
try:
current_class_wb.close()
print(f" ✅ 关闭班级模板工作簿")
except Exception as e:
print(f" ❌ 关闭班级工作簿失败: {str(e)}")
kill_wps_processes()
class_info_wb.save(class_info_file)
print(f"\n=== 批量处理完成 ===")
print(f"📊 总计处理班级: {counter} 个")
print(f"📁 所有文件保存路径: {output_dir}")
except Exception as e:
print(f"❌ 班级点名表批量生成失败: {str(e)}")
traceback.print_exc()
finally:
if class_info_wb:
try:
class_info_wb.close()
print(f"✅ 关闭班级信息表工作簿")
except Exception as e:
print(f"❌ 关闭班级信息表失败: {str(e)}")
print("\n=== 最终清理:确认无残留WPS进程 ===")
kill_wps_processes()
print(f"\n✅ 所有操作完成!")
# ===================== 执行主程序 =====================
if __name__ == "__main__":
required_packages = ['openpyxl', 'pywin32', 'psutil']
missing_packages = []
for pkg in required_packages:
try:
__import__(pkg)
except ImportError:
missing_packages.append(pkg)
if missing_packages:
print(f"⚠️ 发现缺失依赖包: {', '.join(missing_packages)},正在自动安装...")
import subprocess
import sys
for pkg in missing_packages:
subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
print("✅ 所有依赖包安装完成")
main()
# 计算并显示运行时间
end_time = time.time()
total_seconds = end_time - start_time
minutes = int(total_seconds // 60)
seconds = int(total_seconds % 60)
print(f"\n程序运行时间: {minutes}分{seconds}秒 (共{total_seconds:.2f}秒)")














&spm=1001.2101.3001.5002&articleId=163762300&d=1&t=3&u=4cfb5f62faa445ab86e7fa26ebc510dc)
327

被折叠的 条评论
为什么被折叠?



