用 Python + Playwright 自动化发布掘金文章,我是怎么搞定的
说实话,每次写完技术文章还要手动登录掘金、填标题、选分类、贴标签、点发布——这一套下来至少5分钟,写多了真的烦。所以我就想,能不能用脚本把发布流程全自动化?
答案是可以的,而且没那么难。今天分享一下我用 Python + Playwright 搞定掘金自动发布的完整过程,包括踩过的坑。
核心思路
掘金的发布流程拆开来看就三步:创建草稿 → 更新内容 → 发布上线。背后都是 API 调用,但直接调 API 需要处理登录态,最省事的方式是用 Playwright 携带 cookie 去访问页面,然后直接调接口。
我的方案是:Playwright 启动 headless 浏览器 → 加载本地存的 cookie → 调掘金 API 完成发布。全程不需要打开浏览器,跑在服务器上也没问题。
Cookie 怎么管
这是第一个坑。掘金的 cookie 有效期各不相同——sessionid 这类核心 cookie 能活一年,但 passport_auth_status 只有30天,还有些跟踪类 cookie 五六天就过期了。
我的做法是把 cookie 存成 Netscape 格式的文本文件,每次发文前先用 Playwright 访问一次掘金首页,触发 cookie 自动续期,然后再导出保存。这样只要保持每3天左右发一次文的节奏,短周期 cookie 就不会过期。
from playwright.sync_api import sync_playwright
import http.cookiejar as cookielib
import os
COOKIE_FILE = os.path.expanduser("~/.hermes/juejin_cookies.txt")
def load_cookies(context):
# 从 Netscape 格式文件加载 cookie 到浏览器上下文
jar = cookielib.MozillaCookieJar(COOKIE_FILE)
jar.load(ignore_discard=True, ignore_expires=True)
for cookie in jar:
context.add_cookies([{
"name": cookie.name,
"value": cookie.value,
"domain": cookie.domain,
"path": cookie.path,
}])
def renew_cookies(context):
# 访问掘金首页续期 cookie
page = context.new_page()
page.goto("https://juejin.cn", wait_until="networkidle")
page.wait_for_timeout(2000)
page.close()
老实讲,最开始我直接拿 cookie 调 API,结果 passport_auth_status 过期了,API 返回 401。排查了半天才搞明白是短周期 cookie 的问题,不是 sessionid 挂了。
发布接口的坑
第二个大坑在 API 参数上。掘金发布接口看着简单,实际上有几个必须注意的点:
brief_content 不能超过100字,超了直接返回"参数错误",而且错误信息一点提示都没有。我第一次发文就卡在这,还以为是 token 过期了。
更新草稿时必须带 mark_content,不然内容会被清空。这个设计说实话挺反直觉的——你以为创建时填了内容就行,更新不带内容它就给你清了。
import requests
HEADERS = {
"Content-Type": "application/json",
"Origin": "https://juejin.cn",
"Referer": "https://juejin.cn/editor/draft",
}
def create_draft(cookies_dict, title, content, brief):
# 创建草稿
resp = requests.post(
"https://juejin.cn/content_api/v1/article_draft/create",
headers=HEADERS,
cookies=cookies_dict,
json={
"category_id": "6809637773935378440", # 人工智能
"tag_ids": ["7516396389476401162"], # Agent
"link_url": "",
"cover_image": "",
"title": title,
"brief_content": brief[:100], # 关键:截断到100字
"mark_content": content,
"editor_type": 1,
}
)
return resp.json()
def publish_draft(cookies_dict, draft_id):
# 发布草稿
resp = requests.post(
"https://juejin.cn/content_api/v1/article/publish",
headers=HEADERS,
cookies=cookies_dict,
json={
"draft_id": draft_id,
"sync_to_org": False,
"column_ids": [],
"theme_ids": [],
}
)
return resp.json()
完整发布流程
把上面的拼起来,完整流程是这样的:
- Playwright 启动 headless Chromium
- 加载本地 cookie 文件
- 访问掘金首页续期 cookie
- 从浏览器提取 cookie 字典
- 调 API 创建草稿
- 调 API 更新草稿(确保内容完整)
- 调 API 发布
- 重新导出 cookie 保存
整个过程跑下来大概10秒,比手动操作快了不知道多少倍。
踩坑总结
| 坑 | 表现 | 解决方案 |
|---|---|---|
| 短周期 cookie 过期 | API 返回 401 | 每次发文前访问首页续期 |
| brief_content 超长 | 返回"参数错误" | 截断到100字以内 |
| 更新不带 mark_content | 内容被清空 | 每次更新都带上完整内容 |
| cookie 格式问题 | Playwright 加载失败 | 用 Netscape 格式 + cookielib 解析 |
我现在已经把这套流程跑成了定时任务,每3天自动发一篇。写完文章扔进去就行,发布完全不用管。
当然这个方案还有改进空间——比如自动生成摘要、自动选择最合适的标签、甚至根据阅读数据优化发布时间。这些等后面有空再搞吧。
如果你也想搞自动发布,核心就一句话:先把 cookie 续期逻辑搞定,再调 API,别上来就莽。