基于python代码自动生成关于建筑安全检测的报告

一. 所需要的库

Pywin32com 一个拥有微软365办公软件接口的自动生成报告的库,这里不再赘述,直接上完整代码。

二. 代码

前提:配置好虚拟环境并按照好相关的第三方库。

以下代码仅需修改第533行,填入合适的图片地址即可直接运行。

PS:保存生成报告的地址目前是D盘自动新建名为report的文件夹,可修改。

python 复制代码
​
import os
import datetime
import logging

# 导入 win32com 相关模块,用于通过 COM 接口操作 Microsoft Word
from win32com.client.gencache import EnsureDispatch
from win32com.client import constants

"""
脚本功能:自动生成一份「建筑健康报告」的 Word 文档,
         包括表格填写、用户输入交互、自动页码、表格样式控制等。
         主要使用 win32com 操作 Word COM 接口,生成 .docx 文件。
"""

# ======================
# 一、基础配置部分
# ======================

# 1. 设置报告保存的目标文件夹路径
save_folder = r"D:\report"

# 2. 配置日志记录(用于调试和过程追踪)
logging.basicConfig(level=logging.INFO)

# 3. 检查保存目录是否存在,不存在则创建
if not os.path.exists(save_folder):
    os.makedirs(save_folder)
    logging.debug("创建了保存文件夹")

# 4. 获取当前日期,用于报告命名和内容
now = datetime.datetime.now()
current_date = now.strftime("%Y_%m_%d")  # 格式如:2024_06_01


# ======================
# 二、报告文件命名与序号生成
# ======================

# 5. 定义函数:获取下一个可用的报告序号(用于文件名唯一性)
def get_next_sequence_number(folder_path):
    """
    遍历指定文件夹,查找符合命名模式的报告文件,
    提取其中的序号部分,找出最大序号并返回下一个序号(5位数字,如 00001)。
    """
    max_number = 0
    # 文件名前缀模式(用于筛选目标报告文件)
    pattern = f"建筑健康检测报告_"

    # 遍历文件夹中的所有文件
    for filename in os.listdir(folder_path):
        if filename.startswith(pattern) and filename.endswith(".docx"):
            try:
                # 提取文件名中序号部分(假设序号位于倒数第5位之前,如 xxxxx.docx -> xxxxx)
                number_part = filename[-10:-5]  # 取倒数第10到第5个字符,如 '00001'
                current_number = int(number_part)
                if current_number > max_number:
                    max_number = current_number
            except ValueError:
                continue  # 若转换失败(非数字),跳过该文件

    # 下一个序号 = 当前最大序号 + 1,并格式化为 5 位数字字符串(如 00002)
    next_number = max_number + 1
    return f"{next_number:05d}"

# 调用函数,获取下一个序号
sequence_number = get_next_sequence_number(save_folder)
logging.info(f"检测到最大序号,新文件序号为:{sequence_number}")

# 6. 拼接生成最终的报告文件名(含日期与序号)
report_name = f"建筑健康检测报告_{current_date}_{sequence_number}.docx"
full_path = os.path.join(save_folder, report_name)  # 完整保存路径

# 7. 生成一个报告编号,用于文档内部内容标识
report_id = f"{current_date}_{sequence_number}"


# ======================
# 三、启动 Word 应用程序 & 创建文档
# ======================

# 8. 启动 Word 应用程序(通过 COM 接口)
word_app = EnsureDispatch("Word.Application")
word_app.Visible = False  # 设置为后台运行(不显示 Word 界面)

# 9. 创建一个新的 Word 文档
doc = word_app.Documents.Add()

# 10. 添加页码到页脚(居中显示)
section = doc.Sections(1)
footer = section.Footers(1)  # 主要页脚(通常是第一页)
footer.Range.Fields.Add(footer.Range, 33, "")  # 33 = wdFieldPage,插入页码
footer.Range.ParagraphFormat.Alignment = constants.wdAlignParagraphCenter   # 居中


# ======================
# 四、添加报告标题与报告编号
# ======================

# 11. 在文档最开始添加主标题
title_range = doc.Range(0, 0)  # 文档起始位置
title_range.Text = "建筑健康检测报告\n"
title_range.Font.Name = "黑体"
title_range.Font.Size = 14
title_range.ParagraphFormat.Alignment = constants.wdAlignParagraphCenter
title_range.Font.Bold = True

# 12. 在标题后插入报告编号
id_range = doc.Range()
id_range.InsertAfter(f"报告编号:{report_id}\n")

# 13. 设置报告编号的字体格式(中英文字体分别设置)
title_length = len("建筑健康检测报告\n")
id_text_cn_length = len(f"报告编号:")
id_text_en_length = len(f"{report_id}\n")

id_cn_start = title_length
id_en_start = title_length + id_text_cn_length
id_en_end = title_length + id_text_cn_length + id_text_en_length

id_text_cn_range = doc.Range(id_cn_start, id_en_start)
id_text_en_range = doc.Range(id_en_start, id_en_end)

id_text_cn_range.Font.Name = "宋体"
id_text_cn_range.Font.Size = 12
id_text_cn_range.Font.Bold = False

id_text_en_range.Font.Name = "Times New Roman"
id_text_en_range.Font.Size = 12


# ======================
# 五、创建并设置主信息表格(12行4列)
# ======================

# 14. 定位到文档末尾,准备插入表格
table_range = doc.Range()
table_range.Collapse(constants.wdCollapseEnd)
logging.debug(f"段落目前框选范围起点为{table_range.Start},终点为{table_range.End}")

# 创建一个 12 行 4 列的表格
info_table = doc.Tables.Add(table_range, 12, 4)

# 设置表格样式为"网格型"
info_table.ApplyStyleDirectFormatting("网格型")

# 15. 设置所有行高为固定 34 pt,行高规则为"精确高度"
for row in info_table.Rows:
    row.Height = 34
    row.HeightRule = constants.wdRowHeightExactly

# 16. 设置第1列和第3列的宽度为 70 pt(约2.5 cm)
first_column = info_table.Columns(1)
first_column.Width = 70
third_column = info_table.Columns(3)
third_column.Width = 70

# 17. 设置整个表格宽度撑满页面(100% 宽度)
info_table.PreferredWidthType = constants.wdPreferredWidthPercent
info_table.PreferredWidth = 100

# 18. 单独设置第9行高度为 198 pt(约7 cm)
if info_table.Rows.Count >= 9:
    nine_row = info_table.Rows(9)
    nine_row.Height = 198
    nine_row.HeightRule = constants.wdRowHeightExactly

# 19. 设置表格所有边框为单实线,线宽 1.0 pt
for border_index in [
    constants.wdBorderTop,
    constants.wdBorderBottom,
    constants.wdBorderLeft,
    constants.wdBorderRight,
    constants.wdBorderHorizontal,
    constants.wdBorderVertical,
]:
    border = info_table.Borders(border_index)
    border.LineStyle = constants.wdLineStyleSingle
    border.LineWidth = constants.wdLineWidth100pt


# ======================
# 六、填充表格内容 & 用户输入交互
# ======================

# 20.输入表格文字
# 第一格
cell_range = info_table.Cell(1, 1).Range
cell_range.Text = str("委托单位")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 合并单元格(1,2)到(1,4),通过左上角那个小格子(Cell)去操作这个大格子
start_cell = info_table.Cell(1, 2)
end_cell = info_table.Cell(1, 4)
start_cell.Merge(end_cell)     # 合并这两个单元格(实际是合并一个矩形区域:2,2 到 2,4)
# 第二格
# 提示用户输入"委托单位"名称,并等待用户输入
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【委托单位】名称:")
cell_range = info_table.Cell(1, 2).Range
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第三格
cell_range = info_table.Cell(2, 1).Range
cell_range.Text = str("地址")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第四格
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【委托单位所在地址】:" )
cell_range = info_table.Cell(2, 2).Range
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第五格
cell_range = info_table.Cell(2, 3).Range
cell_range.Text = str("联系方式")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第六格
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【委托单位联系方式】:")
cell_range = info_table.Cell(2, 4).Range
cell_range.Text = str(user_input)
cell_range.Font.Name = "Times New Roman"
cell_range.Font.Size = 12

# 第七格
cell_range = info_table.Cell(3, 1).Range
cell_range.Text = str("工程名称")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第八格
start_cell = info_table.Cell(3, 2)
end_cell = info_table.Cell(3, 4)
start_cell.Merge(end_cell)
arch_name_input = input("(!!! 务必输入检测建筑名称,用于后续内容描述)\n"
                   "其输入检测建筑名称:")
eight_input = f"{arch_name_input}建筑健康检测工程"
cell_range = info_table.Cell(3, 2).Range
cell_range.Text = str(eight_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第九格
cell_range = info_table.Cell(4, 1).Range
cell_range.Text = str("工程地点")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第十格
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【工程检测地点位置】:")
cell_range = info_table.Cell(4, 2).Range
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12


# 第十一格
cell_range = info_table.Cell(4, 3).Range
cell_range.Text = str("工程编号")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第十二格
current_year = now.strftime("%Y")
cell_range = info_table.Cell(4, 4).Range
cell_range.Text = str(f"ARCH_{current_year}_{sequence_number}")
cell_range.Font.Name = "Times New Roman"
cell_range.Font.Size = 10
cell_range.Font.Bold = True

# 第十三格
cell_range = info_table.Cell(5, 1).Range
cell_range.Text = str("检测项目")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
cell_range.Font.Bold = False

# 第十四格
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【检测项目】:")
cell_range = info_table.Cell(5, 2).Range
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第十五格
cell_range = info_table.Cell(5, 3).Range
cell_range.Text = str("检测日期")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第十六格
cell_range = info_table.Cell(5, 4).Range
user_input = input("其输入检测日期,如不输入直接回车,则默认使用今天当天日期\n"
                   "请输入:")
if len(user_input) > 3:
    cell_range.Text = str(user_input)
else:
    cell_range.Text = str(f"{current_date}")
cell_range.Font.Name = "Times New Roman"
cell_range.Font.Size = 12

# 第十七格
cell_range = info_table.Cell(6, 1).Range
cell_range.Text = str("检测仪器")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第十八格
start_cell = info_table.Cell(6, 2)
end_cell = info_table.Cell(6, 4)
start_cell.Merge(end_cell)
cell_range = info_table.Cell(6, 2).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【检测仪器】:")
cell_range.Text = str(user_input)
cell_range.Font.Name = "Times New Roman"
cell_range.Font.Size = 12

# 第十九格
cell_range = info_table.Cell(7, 1).Range
cell_range.Text = str("检测依据")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十格
start_cell = info_table.Cell(7, 2)
end_cell = info_table.Cell(7, 4)
start_cell.Merge(end_cell)
cell_range = info_table.Cell(7, 2).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【检测依据】:")
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十一格
start_cell = info_table.Cell(8, 1)
end_cell = info_table.Cell(8, 4)
start_cell.Merge(end_cell)
cell_range = info_table.Cell(8, 1).Range
cell_range.Text = str("检测结论")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十二格
start_cell = info_table.Cell(9, 1)
end_cell = info_table.Cell(9, 4)
start_cell.Merge(end_cell)
cell_range = info_table.Cell(9, 1).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【检测结论】:")
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十三格
cell_range = info_table.Cell(10, 1).Range
cell_range.Text = str("检测单位")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十四格
cell_range = info_table.Cell(10, 2).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【检测单位】:")
cell_range.Text = str(user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十五格
cell_range = info_table.Cell(10, 3).Range
cell_range.Text = str("审核")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十七格
cell_range = info_table.Cell(11, 1).Range
cell_range.Text = str("检测员")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第二十九格
cell_range = info_table.Cell(11, 3).Range
cell_range.Text = str("批准")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第三十一格
cell_range = info_table.Cell(12, 1).Range
# 攥写报告的人:编制
cell_range.Text = str("编制")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第三十三格
cell_range = info_table.Cell(12, 3).Range
cell_range.Text = str(f"报告日期")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12

# 第三十四格
cell_range = info_table.Cell(12, 4).Range
cell_range.Text = str(f"{current_date}")
cell_range.Font.Name = "Times New Roman"
cell_range.Font.Size = 12


# ======================
# 七、生成第二张表格(六行一列,用于检测概况总结)
# ======================

# 21. 换页:在当前文档末尾插入分页符
selection = word_app.Selection
selection.EndKey(Unit=6)  # Unit=6 代表文档结尾(wdStory)
selection.TypeParagraph()
current_para = selection.Paragraphs(1)
current_para.Range.ParagraphFormat.PageBreakBefore = True

# 22. 创建第二张表格(6行1列),用于检测概况描述
table_range_2 = doc.Range()
table_range_2.Collapse(constants.wdCollapseEnd)
logging.debug(f"换页之后,段落目前框选范围起点为{table_range_2.Start},终点为{table_range_2.End}")

info_table_2 = doc.Tables.Add(table_range_2, 6, 1)

# 23. 设置第二张表格样式与边框
info_table_2.ApplyStyleDirectFormatting("网格型")
for border_index in [
    constants.wdBorderTop,
    constants.wdBorderBottom,
    constants.wdBorderLeft,
    constants.wdBorderRight,
    constants.wdBorderHorizontal,
    constants.wdBorderVertical,
]:
    border = info_table_2.Borders(border_index)
    border.LineStyle = constants.wdLineStyleSingle
    border.LineWidth = constants.wdLineWidth100pt

# 24. 设置每行高度 & 取消"段前分页"
for row_idx in range(1, info_table_2.Rows.Count + 1):
    row = info_table_2.Rows(row_idx)
    row.Height = 109
    cell = row.Cells(1)
    para = cell.Range.Paragraphs(1)
    para.Range.ParagraphFormat.PageBreakBefore = False

# 25. 设置文档末尾不分页
selection.EndKey(Unit=6)
current_para = selection.Paragraphs(1)
current_para.Range.ParagraphFormat.PageBreakBefore = False

# 26. 填充第二张表格内容
# 第一格
cell_range = info_table_2.Cell(1, 1).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【工程概况】:")
cell_range.Text = str("一、工程概况\n" + user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
row = info_table_2.Rows(1)
row.Height = 109
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow # 两端对齐

# 第二格:
cell_range = info_table_2.Cell(2, 1).Range
temperature_input = input("(请输入检测环境相关信息)(单位 °)请输入气温,无需输入单位:")
humidity_input = input("(请输入检测环境相关信息)(单位 %)请输入相对湿度,无需输入单位:")
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【其它检测环境】:")
cell_range.Text = str(f"二、检测环境\n气温 {temperature_input}℃、相对湿度 {humidity_input}%" + user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
row = info_table_2.Rows(2)
row.Height = 59
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow # 两端对齐

# 第三格
cell_range = info_table_2.Cell(3, 1).Range
user_input = input("(若直接回车默认无辅助措施) 请描述检测辅助措施:")
if user_input:
    cell_range.Text = str(f"三、检测辅助措施\n{user_input}")
else:
    cell_range.Text = str(f"三、检测辅助措施\n无")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
row = info_table_2.Rows(3)
row.Height = 59
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow # 两端对齐

# 第四格
cell_range = info_table_2.Cell(4, 1).Range
user_input = input("(若直接回车默认为建筑东南西北四个外立面) 请描述检测具体部位 (例如某某建筑屋顶):")
if user_input:
    cell_range.Text = str(f"四、检测具体部位\n{user_input}")
else:
    cell_range.Text = str(f"四、检测具体部位\n{arch_name_input}东西南北四个立面墙壁 ")
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
row = info_table_2.Rows(4)
row.Height = 59
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow # 两端对齐

# 第五格
cell_range = info_table_2.Cell(5, 1).Range
# 先清除单元格原有内容
# PS:这里是实现在表格单元先插入文字,再插入图片的重要步骤,没有会插入到错误位置
cell_range.Delete()
# 设置文字内容
cell_range.Text = "五、检测部分示例"
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
# 设置行高和对齐
row = info_table_2.Rows(5)
row.Height = 259
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow
# 在文字后插入段落标记(换行)
cell_range.Collapse(constants.wdCollapseEnd)  # 折叠到文字末尾
cell_range.InsertParagraphAfter()  # 插入段落标记
# 移动到新段落开始位置
cell_range.Collapse(constants.wdCollapseEnd)  # 折叠到新段落开头
# 在新段落中插入图片
img = cell_range.InlineShapes.AddPicture(r"注意:这里需要修改为合适的图片地址")
# 设置图片大小
if img:
    # 方法1:直接设置高宽(推荐)
    img.Height = 200  # 根据实际需要调整
    img.Width = 200

    # 方法2:或者使用缩放比例
    # img.ScaleHeight = 50
    # img.ScaleWidth = 50

# 第六格
cell_range = info_table_2.Cell(6, 1).Range
user_input = input("(注:可直接回车得到空白表格,打印后可手写)\n"
                   "请输入【结论】:")
cell_range.Text = str("六、结论\n" + user_input)
cell_range.Font.Name = "宋体"
cell_range.Font.Size = 12
row = info_table_2.Rows(6)
row.Height = 109
cell_range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustifyLow # 两端对齐


# ======================
# 八、保存 & 关闭文档
# ======================

# 27. 保存文档到指定路径
doc.SaveAs(full_path)

# 28. 关闭文档和 Word 应用程序
doc.Close()
word_app.Quit()

# 29. 输出保存成功日志
logging.info(f"报告已保存至:{full_path}")
logging.info("检测报告已创建完成")

​
相关推荐
程序员爱钓鱼2 小时前
Python 综合项目实战:学生成绩管理系统(命令行版)
后端·python·ipython
程序员爱钓鱼2 小时前
REST API 与前后端交互:让应用真正跑起来
后端·python·ipython
gCode Teacher 格码致知4 小时前
Python基础教学:Python的openpyxl和python-docx模块结合Excel和Word模板进行数据写入-由Deepseek产生
python·excel
Destiny_where6 小时前
Agent平台-RAGFlow(2)-源码安装
python·ai
molunnnn7 小时前
第四章 Agent的几种经典范式
开发语言·python
linuxxx1108 小时前
django测试缓存命令的解读
python·缓存·django
毕设源码-邱学长9 小时前
【开题答辩全过程】以 基于Python的Bilibili平台数据分析与可视化实现为例,包含答辩的问题和答案
开发语言·python·数据分析
咚咚王者9 小时前
人工智能之编程进阶 Python高级:第十一章 过渡项目
开发语言·人工智能·python