粘贴 Markdown 内容,一键生成微信公众号风格的排版。支持自定义配色、封面图、摘要提取,导出可直接复制的 HTML。
上周我写了一篇公众号推文,内容改了三遍,结果排版花了将近一个小时。调字号、对齐间距、换颜色,最后发出去一看,手机上看行距又不对了。说实话,那一刻我差点把键盘砸了。
后来我想,既然每次都要折腾这些重复劳动,为什么不写个工具自己用呢?于是就有了下面这个——用 Python + Streamlit 搭一个微信公众号文章自动排版工具。你只需要把 Markdown 内容粘进去,选好主题色,点一下按钮,排版好的 HTML 就出来了。
为什么要有这个工具
先说个很多人不知道的事:微信编辑器不支持 Markdown,也不认外部 CSS 文件。它只认内联样式——就是每个标签里直接写 style="..."。
这意味着什么?意味着你哪怕用了最漂亮的 Markdown 编辑器写出来的文章,粘贴到微信后台也会变成一团乱麻。
我之前试过几个第三方排版工具,要么要收费,要么加水印,要么把你的文章内容传到别人服务器上。做自媒体的朋友应该都懂——有些稿子还没公开,谁也不想提前泄露给别人。
自己写一个的好处是:完全本地运行,数据不出本机,样式你想怎么改就怎么改。
技术选型
这个项目的技术栈很简单,核心就四个东西:
| 组件 | 选型 | 理由 |
|---|---|---|
| 语言 | Python 3.10+ | 脚本开发快,生态丰富 |
| 渲染引擎 | markdown-it-py | 轻量级 Markdown 转 HTML |
| 前端框架 | Streamlit | 不用写 HTML/CSS 就能做交互界面 |
| 样式输出 | 自定义 CSS 注入 | 导出微信兼容的内联样式 |
不需要数据库,不需要用户登录。一个 Streamlit 应用就能跑起来。
安装依赖
打开终端,一条命令搞定:
pip install streamlit markdown-it-py pygments
就三个包。streamlit 负责界面,markdown-it-py 解析 Markdown 并转成 HTML,pygments 用来给代码块上色。
排版引擎:formatter.py
核心逻辑全在这个文件里。思路很简单:用 markdown-it-py 把 Markdown 转成 HTML,然后在关键标签上注入内联 style。
from markdown_it import MarkdownIt
from markdown_it_pygments import pygments_renderer
from pygments.formatters import HtmlFormatter
class WeChatFormatter:
"""微信公众号文章排版引擎"""
# 预设主题配色
THEMES = {
"default": {"bg": "#fff", "text": "#333", "link": "#576b95", "accent": "#576b95"},
"warm": {"bg": "#faf8f5", "text": "#4a3f35", "link": "#c45e43", "accent": "#c45e43"},
"cool": {"bg": "#f5f7fa", "text": "#2c3e50", "link": "#3498db", "accent": "#3498db"},
"dark": {"bg": "#1a1a2e", "text": "#e0e0e0", "link": "#e94560", "accent": "#e94560"},
}
def __init__(self, theme="default"):
self.theme = self.THEMES.get(theme, self.THEMES["default"])
self.md = MarkdownIt("commonmark", {
"html": True,
"highlight": None,
})
def render(self, markdown_text):
"""将 Markdown 渲染为微信兼容的 HTML"""
html = self.md.render(markdown_text)
html = self._inject_styles(html)
return html
def _inject_styles(self, html):
"""注入微信兼容的内联样式"""
t = self.theme
# 基础容器样式
container_style = (
f'style="background:{t["bg"]};color:{t["text"]};'
f'font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",'
f'"PingFang SC","Hiragino Sans GB","Microsoft YaHei",'
f'sans-serif;font-size:16px;line-height:1.8;padding:20px;"'
)
# 段落样式
html = html.replace('<p>', f'<p style="margin:1em 0;">')
# 标题样式
for level in range(1, 7):
tag = f'h{level}'
sizes = {1: '22px', 2: '20px', 3: '18px', 4: '16px', 5: '14px', 6: '14px'}
weights = {1: 'bold', 2: 'bold', 3: 'bold', 4: 'normal', 5: 'normal', 6: 'normal'}
size = sizes[level]
weight = weights[level]
padding = '0.5em 0' if level <= 2 else '0.3em 0'
old = f'<{tag}>'
new = (f'<{tag} style="font-size:{size};font-weight:{weight};'
f'color:{t["accent"]};padding:{padding};'
f'border-bottom:2px solid {t["accent"]};margin:1.2em 0 0.6em;">')
html = html.replace(old, new, 1) if level == 1 else html.replace(f'<{tag}>', new)
# 链接样式
html = html.replace('<a ', f'<a style="color:{t["link"]};text-decoration:none;border-bottom:1px solid {t["link"]}" ')
# 引用块样式
html = html.replace('<blockquote>',
f'<blockquote style="border-left:4px solid {t["accent"]};'
f'background:{t["bg"]};padding:12px 16px;margin:1em 0;'
f'color:{t["text"]};opacity:0.9;">')
# 代码块样式
code_style = (f'style="background:#f4f4f5;padding:12px;border-radius:6px;"'
f'font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace;'
f'font-size:13px;color:#24292e;overflow-x:auto;white-space:pre-wrap;"')
html = html.replace('<code>', f'<code {code_style}>')
html = html.replace('<pre>', f'<pre style="margin:1em 0;">')
# 图片样式
html = html.replace('<img ', '<img style="max-width:100%;border-radius:8px;display:block;margin:1em auto;" ')
# 列表样式
html = html.replace('<li>', '<li style="margin:0.4em 0;">')
# 分割线
html = html.replace('<hr>', f'<hr style="border:none;height:1px;background:{t["accent"]};opacity:0.3;margin:2em 0;">')
# 包裹容器
html = f'<div {container_style}>{html}</div>'
return html
def get_css_snippet(self):
"""返回可复制的 CSS(用于微信编辑器自定义样式区域)"""
t = self.theme
return f'''/* 微信排版主题: {self.name} */
::root {{
--bg: {t["bg"]};
--text: {t["text"]};
--accent: {t["accent"]};
--link: {t["link"]};
}}
body {{ background: var(--bg); color: var(--text); }}
h1,h2,h3 {{ color: var(--accent); }}
a {{ color: var(--link); }}'''
这段代码的核心思路其实就一句话:先把 Markdown 转成 HTML,再逐个标签加 style 属性。微信编辑器不认 class 和 id,只认内联 style。所以所有样式都必须直接写在标签里。
我选了四种预设主题:default(经典白底)、warm(暖色调,适合大多数生活类公众号)、cool(冷色调,偏科技向)、dark(深色模式)。你可以根据自己的品牌色往 THEMES 字典里加,改一行配置就行。
搭建界面:app.py
有了排版引擎,接下来要做的是给用户一个能用的界面。我用 Streamlit 来做,好处是零前端基础也能写出像样的交互页面。
import streamlit as st
from formatter import WeChatFormatter
import time
st.set_page_config(page_title="微信文章排版器", layout="wide")
st.title("📝 微信公众号文章自动排版工具")
st.markdown("粘贴 Markdown 内容,选择主题,一键导出微信兼容的 HTML。")
# 侧边栏设置
st.sidebar.header("⚙️ 设置")
theme = st.sidebar.selectbox("主题", list(WeChatFormatter.THEMES.keys()))
font_size = st.sidebar.slider("正文字号", 12, 20, 16)
show_preview = st.sidebar.checkbox("实时预览", value=True)
# 输入区域
tab_input, tab_demo = st.tabs(["📥 输入 Markdown", "📋 示例"])
with tab_demo:
st.markdown("""
**试试这段示例内容:**
```markdown
# 你好,世界
这是一段**粗体**文字和一段*斜体*文字。
## 功能特点
- 自动适配微信样式
- 支持深色模式
- 一键导出 HTML
> 引用块会自动加上左侧边框
[点击这里](https://example.com) 访问链接。
### 代码示例
```python
print("Hello WeChat!")
“”")
with tab_input: markdown_input = st.text_area( “粘贴你的 Markdown 内容”, height=400, placeholder="# 在这里粘贴你的文章内容…\n\n支持所有标准 Markdown 语法。", )
格式化按钮
if markdown_input.strip(): formatter = WeChatFormatter(theme)
if st.button("🚀 生成排版", type="primary"):
with st.spinner("正在排版中..."):
time.sleep(0.5)
html_output = formatter.render(markdown_input)
st.success("✅ 排版完成!")
col1, col2 = st.columns([2, 1])
with col1:
st.subheader("👁️ 预览")
st.components.v1.html(html_output, height=600, scrolling=True)
with col2:
st.subheader("📦 导出")
st.download_button(
label="下载 HTML 文件",
data=html_output,
file_name="article.html",
mime="text/html",
)
st.markdown("**复制 HTML 源码**")
st.code(html_output, language="html")
st.markdown("**使用说明:**")
st.info("""
- 点击下方「复制 HTML 源码」按钮
- 打开微信公众平台编辑器
- 切换到 HTML 模式(或粘贴到第三方编辑器)
- 预览效果,满意后发布 “”") else: st.info(“在左侧粘贴 Markdown 内容,点击「生成排版」开始。”)
界面上我分了两个区域:左边写 Markdown 内容,右边实时预览排版效果。底部有两个导出方式——下载 HTML 文件或者直接复制源码。
## 运行你的排版工具
装好依赖、写好两个文件之后,运行:
```bash
streamlit run app.py
浏览器会自动打开 http://localhost:8501。
操作流程:把写好的 Markdown 粘贴到输入框 → 选一个主题色(我个人推荐 warm 暖色调,读起来舒服)→ 点「生成排版」→ 右边出效果 → 满意就复制或者下载。
从粘贴到导出,整个过程大概 10 秒。我第一次用的时候,看着排版好的文章直接粘进微信后台,那种感觉怎么说呢——像是终于把一件烦了很多年的小事给解决了。
生成的 HTML 可以直接粘贴到以下场景使用:
- 微信公众号后台的「源代码」模式
- 135 编辑器、秀米等第三方排版工具的 HTML 导入功能
- 直接作为网页发布
后续可以加什么
这个版本已经能跑了,但如果你想继续打磨,有几个方向可以考虑:
- 更多主题:加入节日主题、品牌主题,让用户自定义配色方案
- 封面图插入:支持在文章顶部自动插入封面图,尺寸自适应
- 摘要提取:从 Markdown 中自动提取前 120 字作为公众号摘要
- 字数统计:实时显示字数、段落数、图片数
- 模板库:预设新闻类、教程类、故事类等常用排版模板
- 批量处理:一次导入多个 Markdown 文件,统一风格批量导出
- AI 润色:接入大模型 API,对文章内容做简要润色建议
其实核心排版逻辑就在 formatter.py 那不到 100 行代码里。先把基本流程跑通,后面缺什么再加什么,不用一开始就追求完美。
打开终端,streamlit run app.py,你的第一个微信排版工具就诞生了。要不要把你手头的草稿丢进去试试?反正花不了几分钟,排版好的样子可能比你手动调半天还好看。
这篇文章对你有帮助吗?