|
一、问题的提出
今天,有人在Word群里中提出这样的问题,收到提交的多个参会人员表,均为word格式,现在想把这些表格

问题的提出。
提取出来,存到Excel中进行汇总。有人提出用VBA的方法,有人说把数据转化为excel再合并。经过分析后,我认为用Python中的Python-docx和openpyxl模块来解决这个问题更合适。
二、分析问题
我们要汇总以下文件内容,如下图所示,均为一些参会的回执。需要提取的是这些文件中的表格内容:包括表头、每一行的数据,如果有空行,还需要把空行删除。

汇总的文档样例
汇总后的结果如下图:

汇总后的结果
经过分析我们按以下步骤来实现我们要的功能:
- 导入docx, openpyxl模块;
- 用openpyxl生成一个工作表对象sheet, 读取所有docx文件中的表格,把每一行数据添加到一个列表中,然后用append的方法,写入到sheet中。
- 删除工作表中的所以空行。
- 插入工作表的表头,只插入一次。
- 最后保留工作表
三、代码实现
通过Python,我们可以实现docx文件的读取,表格的快速提取,xlsx文件对象的生成和写入,执行效率非常高。代码如下:
import os
import docx
from openpyxl import Workbook
# 创建Excel文档
workbook = Workbook()
sheet = workbook.active
# 获取当前目录下所有的.docx文件
docx_files = [file for file in os.listdir() if file.endswith('.docx')]
# 获取一个文件的表头
document = docx.Document(docx_files[0])
header = [cell.text for cell in document.tables[0].rows[0].cells]
#循环处理每个.docx文件
for file in docx_files:
# 打开docx文件
doc = docx.Document(file)
# 处理每个表格
for table in doc.tables:
# 循环遍历表格中的行和列,并将数据写入Excel表中
for row in table.rows[1:]: # 不包括第一行
row_data = []
for cell in row.cells:
row_data.append(cell.text)
sheet.append(row_data)
#插入表头
sheet.insert_rows(0,1)
for i in range(len(header)):
sheet.cell(1,i+1).value = header
# 删除Excel中的空行
rows_to_delete = []
for i, row in enumerate(sheet.iter_rows()):
if all([cell.value is None or cell.value == '' for cell in row]):
rows_to_delete.append(i+1) # 记录要删除的行号
for index in reversed(rows_to_delete):
sheet.delete_rows(index)
# 保存Excel文档
workbook.save('汇总表.xlsx')三、代码优化
写完本文的第二天早上,我又思考了一下算法,感觉上面代码还有提升的空间。
原算法是在添加完所有数据后再插入一行,再加入表头。优化后的代码可以在定义完工作表对象后就用append插入表头数据,而不是最后再插入表头,这样可以把插入表头的代码由三行减少为一行,更能加快写入速度。同时,我们还要增加二行代码,获取每个回执的单位信息,然后写入到Excel表中,以下是优化后的代码。
import os
import docx
from openpyxl import Workbook
# 创建Excel文档
workbook = Workbook()
sheet = workbook.active
# 获取当前目录下所有的.docx文件
docx_files = [file for file in os.listdir() if file.endswith('.docx')]
# 获取表头,并添加到Excel表中
document = docx.Document(docx_files[0])
header = ["单位"]+[cell.text for cell in document.tables[0].rows[0].cells]
sheet.append(header)
#循环处理每个.docx文件
for file in docx_files:
# 打开docx文件
doc = docx.Document(file)
# 提取单位信息
unit = [p.text for p in doc.paragraphs if p.text.startswith("单位")]
unit_name = unit[0].split(":")[1]
# 处理每个表格
for table in doc.tables:
# 循环遍历表格中的行和列,并将数据写入Excel表中
for row in table.rows[1:]: # 不包括第一行
row_data = [unit_name]
for cell in row.cells:
row_data.append(cell.text)
sheet.append(row_data)
#删除Excel中的空行
rows_to_delete = []
for i, row in enumerate(sheet.iter_rows()):
if any([cell.value is None or cell.value == '' for cell in row]):
rows_to_delete.append(i+1) # 记录要删除的行号
for index in reversed(rows_to_delete):
sheet.delete_rows(index)
# 保存Excel文档
workbook.save('汇总表.xlsx')四、附加问题
1. 格式转化
以上代码仅适用于docx文件,如果提交的文件中还有doc文件,需要把doc文件转化为docx文件,可以加入以下代码:
from win32com.client import Dispatch
import os
def doc_to_docx(file):
w = win32com.client.Dispatch('Word.Application')
w.Visible = 0
w.DisplayAlerts = 0
path=os.path.join(os.getcwd(),file) #获取doc文件路径信息
doc = w.Documents.Open(path)
newpath = os.path.splitext(path)[0] + '.docx' #生成docx文件路径信息
doc.SaveAs(newpath, 12, False, "", True, "", False, False, False, False)
doc.Close() #关闭文件
w.Quit()
os.remove(path)#删除原文件
print(f'{file} is converted successfully!')
return newpath
doc_to_docx(file)2. 快捷运行
生成Python代码后,如果不用pyinstaller打包成exe,可以创建一个bat文件,里面写上以下代码,如图所示。这样可以双击bat文件,直接运行py文件,而省去了打开py文件并运行的麻烦。
python -m sumupWord

五、学后反思
- 以上编程结果借助了ChatGPT的辅助,只要给予足够充分的问题描述,就可以得到非常精确的编程代码。
- 插入表头的算法是个人最后添加的,稍微有点儿麻烦,应该还有更为简洁的办法。人工与AI合作魅力无穷。
- 这个代码的应用场景非常多。因为平时,我们要求的汇总表格都是word格式的,尤其是参会人员名单等,因此这个代码就非常的实用,一次运行,就可以完美生成我们想要的内容。再用Excel汇总就非常的方便快捷。
- 这种方法似乎与邮件合并的方法正相反,但其批量功能非常强大,可以帮助我们省去人工复制粘贴和删除,节省我们大量的时间。
- 代码编写要考虑多方面的问题。由于Python运行速度慢,所以要尽可能减少运行步骤,比如缩减代码、优化算法、格式统一等等。
|
|