读取本地 Markdown 文件,自动转为富文本并发布到公众号后台。配合 crontab 实现定时推送,打工人也能准时下班。
凌晨两点还在改公众号排版?明天要发的稿子临时出了 bug?
这种痛苦每个做自媒体的都经历过。
今天做一个微信公众号定时发布助手。你只管写 Markdown,脚本负责排版、上传封面、设置定时推送。写完保存,到点自动发出去。
项目背景
微信公众号后台的编辑器不好用。Markdown 转富文本是个刚需。
更麻烦的是发布时间。你想在早上八点半发,但那时候你可能在睡觉。
手动操作可以,但容易忘。用脚本把流程自动化,设定好时间就能准时推送。
这个工具适合:
- 个人公众号运营者,想批量管理多篇草稿
- 团队内容编辑,统一排版风格
- 需要固定时间推送的自媒体账号
技术选型
| 组件 | 选择 | 理由 |
|---|---|---|
| API 调用 | requests | 简单直接,够用 |
| Markdown 渲染 | markdown + html5lib | 转富文本基础 |
| 素材上传 | 微信素材接口 | 封面图自动上传 |
| 定时调度 | APScheduler / crontab | 灵活可控 |
| 配置管理 | .env 文件 | 安全存储凭证 |
注意:微信开放平台需要先在 mp.weixin.qq.com 注册应用,获取 appid 和 secret。个人订阅号也能调用素材管理和草稿箱接口。
实现步骤
第一步:获取微信 access_token
# wechat_token.py
import requests
import json
import os
from dotenv import load_dotenv
load_dotenv()
APP_ID = os.getenv("WECHAT_APP_ID")
APP_SECRET = os.getenv("WECHAT_APP_SECRET")
def get_access_token():
"""获取微信 access_token,有效期2小时"""
url = f"https://api.weixin.qq.com/cgi-bin/token"
params = {
"grant_type": "client_credential",
"appid": APP_ID,
"secret": APP_SECRET
}
resp = requests.get(url, params=params)
data = resp.json()
if "access_token" in data:
print(f"✅ Token 获取成功,有效期 {data['expires_in']} 秒")
return data["access_token"]
else:
raise Exception(f"Token 获取失败: {data}")
第二步:上传封面图片
# wechat_media.py
import requests
from wechat_token import get_access_token
def upload_cover(image_path):
"""上传封面图到微信服务器,返回 media_id"""
token = get_access_token()
url = f"https://api.weixin.qq.com/cgi-bin/material/add_material"
params = {
"access_token": token,
"type": "image"
}
with open(image_path, "rb") as f:
files = {"media": (os.path.basename(image_path), f, "image/jpeg")}
resp = requests.post(url, params=params, files=files)
result = resp.json()
if "media_id" in result:
print(f"✅ 封面图上传成功,media_id: {result['media_id']}")
return result["media_id"]
else:
raise Exception(f"封面上传失败: {result}")
第三步:Markdown 转富文本
# wechat_formatter.py
import markdown
import re
import os
def md_to_wechat_html(md_content):
"""将 Markdown 转为微信公众号可用的富文本 HTML"""
# 扩展语法支持
extensions = ["tables", "fenced_code", "codehilite", "toc"]
# 转换 Markdown 为 HTML
html_body = markdown.markdown(md_content, extensions=extensions)
# 微信不支持某些标签,做替换
# 代码块添加样式
html_body = re.sub(
r'<pre><code class="language-(\w+)">(.*?)</code></pre>',
r'<div style="background:#f5f5f5;padding:12px;border-radius:6px;font-family:monospace;">\2</div>',
html_body,
flags=re.DOTALL | re.IGNORECASE
)
# 段落添加间距
html_body = re.sub(r'</p>\s*<p>', '</p><p>', html_body)
# 标题加粗着色
html_body = re.sub(
r'<h(\d)>(.*?)</h\1>',
lambda m: f'<strong style="font-size:{18-int(m.group(1))*2}px;color:#333;">{m.group(2)}</strong>',
html_body
)
return html_body
def render_article(title, subtitle, content_md, cover_media_id):
"""组装完整的文章数据"""
new_article_html = md_to_wechat_html(content_md)
article_data = {
"title": title,
"author": "作者名",
"digest": subtitle,
"content": new_article_html,
"thumb_media_id": cover_media_id,
"need_open_comment": 1,
"only_fans_can_comment": 0
}
return article_data
第四步:创建草稿并定时发布
# wechat_draft.py
import requests
import json
from datetime import datetime, timedelta
from wechat_token import get_access_token
from wechat_formatter import render_article
def create_draft(article_data):
"""创建公众号草稿"""
token = get_access_token()
url = f"https://api.weixin.qq.com/cgi-bin/draft/batchsave"
params = {"access_token": token}
payload = {"articles": [article_data]}
resp = requests.post(url, params=params, json=payload)
result = resp.json()
if "media_id" in result:
print(f"✅ 草稿创建成功,media_id: {result['media_id']}")
return result["media_id"]
else:
raise Exception(f"草稿创建失败: {result}")
def schedule_publish(media_id, publish_time_str=None):
"""
定时发布草稿
publish_time_str: ISO 格式时间字符串,如 "2026-07-06T08:30:00+08:00"
如果不传,默认立即发布
"""
token = get_access_token()
if publish_time_str:
# 定时发布
url = f"https://api.weixin.qq.com/cgi-bin/freepublish/submit"
payload = {
"media_id": media_id,
"freepublish_status": 2, # 2=定时发布
"publish_time": int(datetime.fromisoformat(publish_time_str).timestamp())
}
else:
# 立即发布
url = f"https://api.weixin.qq.com/cgi-bin/freepublish/submit"
payload = {
"media_id": media_id,
"freepublish_status": 0 # 0=立即发布
}
params = {"access_token": token}
resp = requests.post(url, params=params, json=payload)
result = resp.json()
if result.get("errcode") == 0:
print("✅ 发布任务提交成功!")
else:
print(f"⚠️ 发布结果: {result}")
return result
# ========== 主入口 ==========
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="微信公众号定时发布助手")
parser.add_argument("--title", required=True, help="文章标题")
parser.add_argument("--subtitle", default="", help="摘要")
parser.add_argument("--md-file", required=True, help="Markdown 文件路径")
parser.add_argument("--cover", required=True, help="封面图片路径")
parser.add_argument("--schedule", default=None, help="定时发布时间 ISO 格式")
args = parser.parse_args()
# 读取 Markdown 内容
with open(args.md_file, "r", encoding="utf-8") as f:
content = f.read()
# 上传封面
cover_media_id = upload_cover(args.cover)
# 渲染文章
article = render_article(args.title, args.subtitle, content, cover_media_id)
# 创建草稿
draft_media_id = create_draft(article)
# 发布
schedule_publish(draft_media_id, args.schedule)
第五步:准备 Markdown 文章
创建一个示例文章 my_article.md:
# Python 自动化发布教程
这是一篇测试文章。
## 为什么需要自动化?
手动发布太慢了。每次都要打开后台,复制粘贴,调整排版。
## 代码示例
```python
print("Hello, WeChat!")
小贴士:记得先获取 access_token 再调用接口。
感谢阅读,欢迎收藏转发。
### 第六步:运行
```bash
# 安装依赖
pip install requests markdown python-dotenv pygments
# 创建 .env 文件
echo "WECHAT_APP_ID=your_app_id" > .env
echo "WECHAT_APP_SECRET=your_app_secret" >> .env
# 立即发布
python wechat_draft.py \
--title "我的第一篇自动化推文" \
--subtitle "用 Python 自动发布公众号文章" \
--md-file my_article.md \
--cover cover.jpg
# 定时发布(明天早上八点)
python wechat_draft.py \
--title "定时推送测试" \
--md-file my_article.md \
--cover cover.jpg \
--schedule "2026-07-06T08:00:00+08:00"
运行效果
跑完脚本后,你会看到类似这样的输出:
✅ Token 获取成功,有效期 7200 秒
✅ 封面图上传成功,media_id: xxxxxxxxxxx
✅ 草稿创建成功,media_id: yyyyyyyyyyy
✅ 发布任务提交成功!
登录微信公众号后台,在"草稿箱"里能看到刚刚创建的草稿。如果是定时发布,到了指定时间会自动推送给订阅用户。
优化方向
- 批量发布:读取目录下所有
.md文件,一次性创建多篇草稿 - 模板系统:用 Jinja2 做文章模板,统一标题样式、页头页脚
- 预览功能:调用预览接口,发到指定微信号先看看效果
- 自动获取 token:把 token 存到 Redis,避免频繁请求被限流
- CI/CD 集成:配合 GitHub Actions,push 代码后自动触发发布
- 多账号支持:配置文件里写多个 appid/secret,一键切换
有了这个工具,晚上写好文章,设定好时间,安心睡觉。第二天醒来,推文已经发出去了。
要不要试试把你手头的文章丢进来跑一圈?
这篇文章对你有帮助吗?