🚀

公众号排版太折磨?我用 Python 写了个自动排版工具,10秒搞定

粘贴 Markdown 内容,一键生成微信公众号风格的排版。支持自定义配色、封面图、摘要提取,导出可直接复制的 HTML。

👁️ - 次阅读
16px
📥 Markdown 输入 0 字
👁️ 预览 等待输入...

粘贴 Markdown 内容,点击「生成排版」开始预览

上周我写了一篇公众号推文,内容改了三遍,结果排版花了将近一个小时。调字号、对齐间距、换颜色,最后发出去一看,手机上看行距又不对了。说实话,那一刻我差点把键盘砸了。

后来我想,既然每次都要折腾这些重复劳动,为什么不写个工具自己用呢?于是就有了下面这个——用 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("""
  1. 点击下方「复制 HTML 源码」按钮
  2. 打开微信公众平台编辑器
  3. 切换到 HTML 模式(或粘贴到第三方编辑器)
  4. 预览效果,满意后发布 “”") else: st.info(“在左侧粘贴 Markdown 内容,点击「生成排版」开始。”)

界面上我分了两个区域:左边写 Markdown 内容,右边实时预览排版效果。底部有两个导出方式——下载 HTML 文件或者直接复制源码。

## 运行你的排版工具

装好依赖、写好两个文件之后,运行:

```bash
streamlit run app.py

浏览器会自动打开 http://localhost:8501

操作流程:把写好的 Markdown 粘贴到输入框 → 选一个主题色(我个人推荐 warm 暖色调,读起来舒服)→ 点「生成排版」→ 右边出效果 → 满意就复制或者下载。

从粘贴到导出,整个过程大概 10 秒。我第一次用的时候,看着排版好的文章直接粘进微信后台,那种感觉怎么说呢——像是终于把一件烦了很多年的小事给解决了。

生成的 HTML 可以直接粘贴到以下场景使用:

  • 微信公众号后台的「源代码」模式
  • 135 编辑器、秀米等第三方排版工具的 HTML 导入功能
  • 直接作为网页发布

后续可以加什么

这个版本已经能跑了,但如果你想继续打磨,有几个方向可以考虑:

  1. 更多主题:加入节日主题、品牌主题,让用户自定义配色方案
  2. 封面图插入:支持在文章顶部自动插入封面图,尺寸自适应
  3. 摘要提取:从 Markdown 中自动提取前 120 字作为公众号摘要
  4. 字数统计:实时显示字数、段落数、图片数
  5. 模板库:预设新闻类、教程类、故事类等常用排版模板
  6. 批量处理:一次导入多个 Markdown 文件,统一风格批量导出
  7. AI 润色:接入大模型 API,对文章内容做简要润色建议

其实核心排版逻辑就在 formatter.py 那不到 100 行代码里。先把基本流程跑通,后面缺什么再加什么,不用一开始就追求完美。

打开终端,streamlit run app.py,你的第一个微信排版工具就诞生了。要不要把你手头的草稿丢进去试试?反正花不了几分钟,排版好的样子可能比你手动调半天还好看。

这篇文章对你有帮助吗?