第 18 课 | 报告自动生成:python-docx + matplotlib 生成 Word 周报
第 17 课 LLM 生成了洞察,但洞察是 JSON 数据——老板要的是排版精美的 Word 文档。这节课,我们用 python-docx 和 matplotlib 把数据变成直接能发的周报。
一、业务价值:从洞察到决策
1.1 洞察 != 报告
第 17 课的输出是一个 JSON 文件:
{"insights":[{"title":"苹果 iOS 19 全面 AI 化","importance":"高",...},...]}老板不会看 JSON。他需要的是:排版精美、图表清晰、可直接转发给管理层的 Word 文档。
1.2 自动化报告的价值
| 维度 | 人工 | 自动化 | 提升 |
|---|---|---|---|
| 编写时间 | 2-3 小时/周 | 10 秒 | 1000x |
| 格式一致性 | 因人而异 | 100% 统一 | 品质保证 |
| 图表生成 | 手动 Excel 截图 | 自动生成 PNG | 零操作 |
| 修改成本 | 重新排版 | 改代码重新生成 | 秒级迭代 |
| 人力成本 | 1 人/天/周 | 0 | 释放核心人力 |
核心价值:不是"省了 2 小时",而是"让分析师的精力从排版中解放出来,去做更有价值的深度分析"。
二、python-docx 基础:Word 文档操控
2.1 安装
uv pip install python-docx matplotlib2.2 核心概念
python-docx 的文档对象模型:
关键概念:
- Document:整个 Word 文档
- Paragraph:一个段落,可以有标题样式(Heading 1/2/3)
- Run:段落内的一个文本片段,可以有独立的字体、颜色、加粗
- Table:表格,支持合并单元格、设置样式
- Section:页面设置(纸张大小、页边距)
2.3 创建文档
fromdocximportDocumentfromdocx.sharedimportInches,Pt,Cm,RGBColorfromdocx.enum.textimportWD_ALIGN_PARAGRAPHfromdocx.enum.styleimportWD_STYLE_TYPE doc=Document()# 标题doc.add_heading("竞品监控周报",level=0)# 副标题subtitle=doc.add_paragraph()subtitle.alignment=WD_ALIGN_PARAGRAPH.CENTER run=subtitle.add_run("2026年8月9日 - 2026年8月15日")run.font.size=Pt(12)run.font.color.rgb=RGBColor(100,100,100)# 正文段落doc.add_heading("一、本周概述",level=1)doc.add_paragraph("本周科技行业焦点集中在 AI 能力升级...")# 保存doc.save("竞品监控周报.docx")2.4 表格
# 创建表格table=doc.add_table(rows=5,cols=4,style="Light Grid Accent 1")# 表头headers=["序号","洞察标题","重要程度","分析维度"]fori,headerinenumerate(headers):cell=table.rows[0].cells[i]cell.text=header# 表头加粗forparagraphincell.paragraphs:forruninparagraph.runs:run.bold=True# 填充数据foridx,insightinenumerate(insights,1):row=table.rows[idx]row.cells[0].text=str(idx)row.cells[1].text=insight["title"]row.cells[2].text=insight["importance"]row.cells[3].text=insight["dimension"]2.5 插入图片
doc.add_picture("chart.png",width=Inches(5.5))last_paragraph=doc.paragraphs[-1]last_paragraph.alignment=WD_ALIGN_PARAGRAPH.CENTER三、matplotlib 图表生成
3.1 中文支持
matplotlib 默认不支持中文,需要配置:
importmatplotlib.pyplotaspltimportmatplotlib# 设置中文字体(Windows 用 SimHei 或 Microsoft YaHei)matplotlib.rcParams["font.sans-serif"]=["Microsoft YaHei","SimHei"]matplotlib.rcParams["axes.unicode_minus"]=False# 解决负号显示问题3.2 柱状图:分类分布
defgenerate_category_chart(insights,output_path):"""生成分类分布柱状图"""categories={}forinsightininsights:dim=insight.get("dimension","其他")categories[dim]=categories.get(dim,0)+1fig,ax=plt.subplots(figsize=(8,4))colors=["#4f46e5","#7c3aed","#10b981","#f59e0b"]bars=ax.bar(categories.keys(),categories.values(),color=colors)ax.set_title("洞察维度分布",fontsize=14,fontweight="bold")ax.set_ylabel("数量",fontsize=12)# 在柱子上标数值forbarinbars:height=bar.get_height()ax.annotate(f"{int(height)}",xy=(bar.get_x()+bar.get_width()/2,height),xytext=(0,3),textcoords="offset points",ha="center",va="bottom",fontweight="bold")plt.tight_layout()plt.savefig(output_path,dpi=150,bbox_inches="tight")plt.close()3.3 饼图:重要程度分布
defgenerate_importance_pie(insights,output_path):"""生成重要程度饼图"""importance_count={}forinsightininsights:imp=insight.get("importance","低")importance_count[imp]=importance_count.get(imp,0)+1labels=list(importance_count.keys())sizes=list(importance_count.values())explode=[0.05]*len(labels)fig,ax=plt.subplots(figsize=(6,6))colors_pie={"高":"#ef4444","中":"#f59e0b","低":"#10b981"}colors_list=[colors_pie.get(l,"#6b7280")forlinlabels]ax.pie(sizes,explode=explode,labels=labels,colors=colors_list,autopct="%1.1f%%",shadow=False,startangle=90,textprops={"fontsize":12})ax.set_title("重要程度分布",fontsize=14,fontweight="bold")plt.tight_layout()plt.savefig(output_path,dpi=150,bbox_inches="tight")plt.close()四、实战:组装完整周报
4.1 报告结构
4.2 完整代码概览
defgenerate_report(insight_json_path,output_path):"""生成完整周报"""# 1. 加载洞察数据withopen(insight_json_path,"r",encoding="utf-8")asf:data=json.load(f)# 2. 生成图表chart_dir=Path(output_path).parent/"charts"chart_dir.mkdir(exist_ok=True)generate_category_chart(data["insights"],chart_dir/"category.png")generate_importance_pie(data["insights"],chart_dir/"importance.png")# 3. 构建 Word 文档doc=Document()# ... 封面、概述、洞察表格、图表 ...# 4. 保存doc.save(output_path)4.3 运行
cdcode/lesson-18-docx-report uv run docx_report_generator.py输出:output/竞品监控周报_2026-08-15.docx,包含封面、概述、洞察表格、两张图表。
五、样式美化技巧
5.1 自定义样式
# 自定义标题样式style=doc.styles["Heading 1"]style.font.size=Pt(18)style.font.color.rgb=RGBColor(79,70,229)# 紫色style.font.bold=True# 自定义正文样式style=doc.styles["Normal"]style.font.size=Pt(11)style.font.name="Microsoft YaHei"style.paragraph_format.space_after=Pt(6)5.2 页眉页脚
fromdocx.enum.textimportWD_ALIGN_PARAGRAPH section=doc.sections[0]header=section.header header_para=header.paragraphs[0]header_para.text="AI Agent 竞品监控系统 · 机密"header_para.alignment=WD_ALIGN_PARAGRAPH.RIGHT footer=section.footer footer_para=footer.paragraphs[0]footer_para.text=f"第{page_number}页"六、总结
| 能力 | 工具 | 效果 |
|---|---|---|
| Word 文档生成 | python-docx | 标题、段落、表格、样式 |
| 图表生成 | matplotlib | 柱状图、饼图、中文支持 |
| 报告组装 | 流水线脚本 | 洞察 + 图表 → 完整 Word |
| 可定制性 | 代码控制 | 格式、颜色、布局可任意调整 |
至此,场景一「竞品监控」的技术闭环完成:爬取 → 清洗 → 增强 → 洞察 → 报告。下一课,我们将加入定时任务,让这套系统 7x24 小时自动运行。
本课代码:code/lesson-18-docx-report/docx_report_generator.py