项目背景
写公众号文章,最耗时的不是写内容,而是排版。
调整字体大小、配色、间距、配图位置、引用样式……一篇2000字的文章,排版至少花30分钟。
如果用AI生成内容呢?内容快了,排版照样折磨人。
这个项目就是解决这件事:输入Markdown,自动输出排版精美的HTML,附带AI生成的配图,一键复制到公众号后台。
技术选型
- Python 3.11+:核心语言
- mistune 2.x:Markdown转HTML
- OpenAI API(或兼容接口):生成文章配图
- Pillow:图片合成与文字叠加
- requests:API调用
- Jinja2:HTML模板渲染
全部开源库,零依赖成本。
实现步骤
第一步:安装依赖
pip install mistune jinja2 pillow openai requests
第二步:定义排版模板
创建 template.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue",
"PingFang SC", "Microsoft YaHei", sans-serif;
max-width: 677px;
margin: 0 auto;
padding: 20px;
color: #333;
line-height: 1.8;
font-size: 15px;
}
h1 {
font-size: 22px;
color: #1a1a1a;
border-left: 4px solid #07c160;
padding-left: 12px;
margin: 30px 0 15px;
}
h2 {
font-size: 18px;
color: #333;
background: #f7f7f7;
padding: 8px 12px;
border-radius: 4px;
margin: 25px 0 12px;
}
h3 {
font-size: 16px;
color: #555;
margin: 20px 0 10px;
}
p { margin: 12px 0; }
strong { color: #07c160; }
blockquote {
border-left: 3px solid #07c160;
background: #f9f9f9;
padding: 10px 15px;
margin: 15px 0;
color: #666;
font-style: italic;
}
code {
background: #f0f0f0;
padding: 2px 6px;
border-radius: 3px;
font-size: 13px;
color: #e83e8c;
}
pre {
background: #282c34;
color: #abb2bf;
padding: 15px;
border-radius: 6px;
overflow-x: auto;
font-size: 13px;
line-height: 1.6;
}
pre code {
background: none;
color: inherit;
padding: 0;
}
ul, ol { padding-left: 20px; }
li { margin: 6px 0; }
img {
max-width: 100%;
border-radius: 8px;
margin: 15px 0;
}
.tag {
display: inline-block;
background: #e8f5e9;
color: #07c160;
padding: 3px 10px;
border-radius: 12px;
font-size: 12px;
margin-right: 6px;
}
hr {
border: none;
height: 1px;
background: linear-gradient(90deg, #07c160, transparent);
margin: 25px 0;
}
</style>
</head>
<body>
{{ content }}
<hr>
<p style="font-size:12px;color:#999;">
原文链接:{{ url }} | 生成于 {{ time }}
</p>
</body>
</html>
第三步:写核心转换脚本
创建 wechat_formatter.py:
#!/usr/bin/env python3
"""
微信公众号文章自动排版工具
输入 Markdown → 输出排版好的 HTML
"""
import mistune
import json
import sys
from pathlib import Path
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
import requests
def markdown_to_html(markdown_text: str) -> str:
"""Markdown 转 HTML,带自定义渲染器"""
renderer = mistune.HTMLRenderer(escape=False)
parser = mistune.create_inline_renderer(renderer)
block_parser = mistune.create_block_parser(
inline_parser=parser, skip_inline=True
)
html = block_parser(markdown_text)
return html
def generate_cover(title: str, output_path: str = "cover.png"):
"""生成文章封面图"""
width, height = 900, 383
img = Image.new("RGB", (width, height), color="#0d1117")
draw = ImageDraw.Draw(img)
# 装饰线条
draw.rectangle([0, 0, width, 4], fill="#07c160")
draw.rectangle([0, height-4, width, height], fill="#07c160")
# 大字标题
try:
font_large = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 48)
except:
font_large = ImageFont.load_default()
# 小字副标题
try:
font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 24)
except:
font_small = ImageFont.load_default()
# 计算文字位置
bbox = draw.textbbox((0, 0), title, font=font_large)
text_w = bbox[2] - bbox[0]
x = (width - text_w) // 2
y = (height - 120) // 2
draw.text((x, y), title, fill="white", font=font_large)
draw.text((x, y + 65), "AI Auto Formatter", fill="#07c160", font=font_small)
img.save(output_path)
print(f"封面图已保存: {output_path}")
def ai_generate_image(prompt: str, output_path: str = "ai_image.png"):
"""通过AI API生成配图"""
# 使用 OpenAI 兼容接口
api_key = "sk-your-key-here" # 替换为你的API Key
api_url = "https://api.openai.com/v1/images/generations" # 或兼容接口地址
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"model": "dall-e-3",
"prompt": prompt,
"size": "1024x1024",
"quality": "standard",
"n": 1
}
resp = requests.post(api_url, headers=headers, json=payload)
if resp.status_code == 200:
url = resp.json()["data"][0]["url"]
img_data = requests.get(url).content
with open(output_path, "wb") as f:
f.write(img_data)
print(f"AI配图已保存: {output_path}")
return output_path
else:
print(f"AI配图生成失败: {resp.status_code}")
return None
def wrap_with_template(html_content: str, article_url: str = "") -> str:
"""用 Jinja2 模板包裹 HTML 内容"""
template_path = Path("template.html")
if not template_path.exists():
return html_content
with open(template_path, "r", encoding="utf-8") as f:
template_content = f.read()
from jinja2 import Template
tmpl = Template(template_content)
return tmpl.render(
content=html_content,
url=article_url or "navbox.com.cn",
time=datetime.now().strftime("%Y-%m-%d %H:%M")
)
def format_wechat(md_source: str, url: str = "") -> str:
"""完整流程:Markdown → 排版HTML"""
# 1. Markdown 转 HTML
html = markdown_to_html(md_source)
# 2. 用模板包裹
final_html = wrap_with_template(html, url)
return final_html
if __name__ == "__main__":
if len(sys.argv) < 2:
print("用法: python wechat_formatter.py <input.md> [output.html]")
print(" python wechat_formatter.py --cover <title>")
sys.exit(1)
if sys.argv[1] == "--cover":
generate_cover(sys.argv[2] if len(sys.argv) > 2 else "文章标题")
sys.exit(0)
input_file = sys.argv[1]
output_file = sys.argv[2] if len(sys.argv) > 2 else "output.html"
with open(input_file, "r", encoding="utf-8") as f:
md_text = f.read()
result = format_wechat(md_text, "navbox.com.cn")
with open(output_file, "w", encoding="utf-8") as f:
f.write(result)
print(f"✅ 排版完成: {output_file}")
print("📋 打开 output.html 查看效果,复制内容粘贴到公众号后台")
第四步:示例输入
创建 demo.md:
# AI排版工具:告别公众号排版噩梦
你是不是也这样?写完文章,花30分钟调整格式。
## 为什么要自动化
手动排版效率太低了。同样的内容,换个主题就要重新配色。
> 好的工具,让重复劳动自动化。
## 核心功能
- Markdown 一键转 HTML
- 微信公众号默认样式
- AI 配图自动生成
- 支持代码高亮
## 使用示例
```bash
python wechat_formatter.py demo.md output.html
python wechat_formatter.py --cover "我的文章标题"
运行后打开 output.html,全选复制,粘贴到公众号编辑器。
这个工具是我用来处理所有公众号文章的。每天省下半小时,一个月就是十几个小时。
### 第五步:运行
```bash
# 排版文章
python wechat_formatter.py demo.md output.html
# 生成封面图
python wechat_formatter.py --cover "AI排版工具:告别公众号排版噩梦"
# 如果配置了API Key,还可以生成AI配图(在模板中扩展img标签支持AI图)
python -c "from wechat_formatter import ai_generate_image; ai_generate_image('tech illustration minimalist green')"
运行效果
输出 output.html 后,浏览器打开:
- 标题左侧绿色竖线装饰
- 二级标题灰色背景块
- 代码块深色背景
- 引用块绿色左边框
- 底部自动带上原文链接和时间
公众号后台打开编辑器 → 粘贴内容 → 自动保留所有样式。
封面图 cover.png 直接上传到公众号文章封面位置。
优化方向
- API接入优化:支持多模型(DALL-E、Midjourney、Stable Diffusion),增加失败重试
- 图片插入:扫描Markdown中的图片占位符,自动替换为AI生成的配图
- 模板市场:提供多种配色方案模板(商务蓝、科技黑、清新绿),用户按需切换
- 定时发布:对接微信公众号API,实现定时自动群发
- 批量模式:读取目录中所有Markdown文件,批量生成HTML
- 云部署:搭一个简单Flask页面,上传Markdown直接返回HTML,手机也能用
这个工具最实用的地方在于——写的时候只管写,排交给机器。
你平时写公众号,最头疼的排版问题是啥?