需求背景
每当一个企业人比较多了之后,每周就会有大量的人入职离职。入职的时候需要把入职信息,主要是一些平台的账号密码,和一些说明发给新员工。
手动输入肯定是不可能的,动不动就入职十几个人。
我们一开始是用word的批量打印功能,从excel导入数据然后批量打印那个,但感觉那个操作起来也有点烦,所以想着用python写个自动生成入职单。
工作步骤分解
- 在Excel文件中录入入职人员信息
- 读取Excel文件
- 读取Word模板文件
- 按人数做循环:替换占位内容
- 保存至新文件,生成N个文档
- 合并文档到一个文档,方便打印
1&2.从Excel读取入职信息
数据位置对应如下:
科目 | 键值 | 所在列 | 示例值 |
---|---|---|---|
工号 | id | A | 06479 |
姓名 | name_cn | B | 刘起 |
英文名 | name_en | C | Kelly Liu |
部门 | dep | E | RM |
分机号 | tel | I | 021-5229-8706 |
计算机名 | PC | J | CAP-2020 |
邮箱 | ad_account | K | kel.liu |
邮箱密码 | password | L | abc@1234 |
def read_from_excel():
"""
从入职信息excel读取信息
:return: 返回得到的员工信息列表
"""
# 从入职信息读取workbook,再获取sheet
wb = openpyxl.load_workbook("resources/入职信息.xlsx") # type: Workbook
sheet = wb["Sheet1"] # type:Worksheet
employees = []
for row_num in range(2, sheet.max_row+1):
employee = {
"id": sheet[f"A{row_num}"].value,
"name_cn": sheet[f"B{row_num}"].value,
"name_en": sheet[f"C{row_num}"].value,
"dep": sheet[f"D{row_num}"].value,
"tel": sheet[f"I{row_num}"].value,
"PC": sheet[f"J{row_num}"].value,
"ad_account": sheet[f"K{row_num}"].value,
"password": sheet[f"L{row_num}"].value
}
employees.append(employee)
return employees
345.获取word模板,生成n个入职单
def read_word_temp():
"""
读取word模板
:return: 返回Document对象
"""
doc = Document("resources/入职信息模板.docx")
return doc
def make_onboard_words(employees):
"""
根据员工数量生成n张入职单
:param employees: 员工信息的列表
:return: 成功返回True
"""
for employee in employees:
doc = read_word_temp() # type:Doc
# 替换表格中的占位符
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for key, value in employee.items():
if key in cell.text:
cell.text = cell.text.replace(key, value)
# 替换文本框中的占位符
children = doc.element.body.iter()
for child in children:
if child.tag.endswith('txbx'): # 获取所有文本框的tag
for ci in child.iter():
if ci.tag.endswith('main}t'): # 感觉是获取所有的行
for key, value in employee.items():
if key in ci.text:
ci.text = ci.text.replace(key, value)
doc.save(f"onboard_words/入职单{employee['name_en']}.docx")
return True
6.合并到一个文件
用到这个包:
pip install docxcompose
最好保证文档刚好一页,这样就不需要加空白页
def get_files_list(source_path):
"""
获取指定文件路径的文件名列表
:param source_path: 文件夹路径
:return: 文件名列表
"""
source_files_list = os.listdir(source_path)
source_files = []
for file in source_files_list:
source_files.append(source_path + file)
return source_files
def make_words_one(source_files, target_file):
"""
将多个word合并成一个
:param source_files: 源文件列表
:param target_file: 合并的目标文件路径+名称
:return: 成功返回True
"""
# 新建一个文档对象作为第一页
target_doc_first = Document(source_files[0]) # type: Doc
# target_doc_first.add_page_break()
target_composer = Composer(target_doc_first)
# 从第二个文档开始循环,加入到新文档中
for file in source_files[1:]:
page_new = Document(file) # type:Doc
# page_new.add_page_break()
target_composer.append(page_new)
# 保存新文档
target_composer.save(target_file)
return True
主程序:调用以上方法,实现最终目的
def onboard_main():
# 从入职信息excel读取信息
employees = read_from_excel()
print(f"获取到{len(employees)}条入职信息--->")
# 根据入职信息生成N份入职表单
if make_onboard_words(employees):
print("生成入职单成功--->")
source_path = "onboard_words/" # 源文件路径
target_file = "resources/入职单打印.docx" # 目标路径
# 获取源文件夹的文件列表,合并为一个新文档
make_words_one(get_files_list(source_path), target_file)
print(f"合并成功---^_^")
if __name__ == '__main__':
onboard_main()
打包发布
为了让这个程序可以方便的在别的电脑上运行,用pyinstaller打包成exe文件
如果没安装过这个包,需要先安装:
pip install pyinstaller
然后在控制台用以下语句打包成exe文件:
pyinstaller --collect-data "docxcompose" --onefile -F -i kayotin.ico create_onboard_files.py
为什么打包的语句和平时不一样呢,因为需要额外导入下docxcompose这个包,否则运行exe程序时会报错找不到这个包的相关文件。
参考了这个答案:
Read_Me
已经生成EXE文件了,接下来说明下如何使用
程序同目录下有两个文件夹:
- resources用来放入职信息.xlsx、入职信息模板.docx
- on_board_words用来放生成的多个入职word文件
首先,在入职信息里录入入职的人的信息,如下格式:
然后,运行主程序create_onboard_files.exe即可
生成的多个入职单,保存在on_board_words
生成的 入职单打印.docx,保存在resources里,需要打印时,打印该文件即可。