#!/usr/bin/env python3 """ 生成 Word 文档,图片从发布目录的 images 文件夹读取 """ import os from docx import Document from docx.shared import Inches, Pt from docx.enum.text import WD_ALIGN_PARAGRAPH BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年" MD_FILE = os.path.join(BASE_DIR, "final-article.md") IMAGES_DIR = os.path.join(BASE_DIR, "images") # 已复制的图片 OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_最终版.docx") with open(MD_FILE, "r", encoding="utf-8") as f: lines = f.readlines() doc = Document() doc.styles['Normal'].font.name = '微软雅黑' doc.styles['Normal'].font.size = Pt(11) def add_heading(text, level=1): heading = doc.add_heading(text, level=level) heading.alignment = WD_ALIGN_PARAGRAPH.LEFT return heading for line in lines: line = line.rstrip('\n') if line.startswith('# '): add_heading(line[2:], level=1) continue if line.startswith('## '): add_heading(line[3:], level=2) continue if line.startswith('### '): add_heading(line[4:], level=3) continue if line.startswith('---'): doc.add_paragraph('_' * 60) continue # 图片 if line.startswith('!['): import re m = re.match(r'!\[(.*?)\]\((images/.*?)\)', line) if m: alt, fname = m.groups() img_path = os.path.join(IMAGES_DIR, os.path.basename(fname)) if os.path.exists(img_path): try: doc.add_picture(img_path, width=Inches(6)) last_para = doc.paragraphs[-1] last_para.alignment = WD_ALIGN_PARAGRAPH.CENTER except Exception as e: doc.add_paragraph(f"[图片错误: {fname}]") else: doc.add_paragraph(f"[缺失图片: {fname}]") continue # 空行 if not line.strip(): doc.add_paragraph() continue # 普通段落,处理粗体斜体 p = doc.add_paragraph() parts = [] tmp = line while '**' in tmp: parts.append(tmp[:tmp.find('**')]) tmp = tmp[tmp.find('**')+2:] if '**' in tmp: parts.append(('bold', tmp[:tmp.find('**')])) tmp = tmp[tmp.find('**')+2:] else: parts.append(('bold', tmp)) break if not parts: parts = [line] for part in parts: if isinstance(part, tuple): style, text = part run = p.add_run(text) run.bold = (style == 'bold') else: p.add_run(part) doc.save(OUTPUT_DOCX) print(f"✅ Word 已生成: {OUTPUT_DOCX}") print(f"📄 段落数: {len(doc.paragraphs)}")