用 Python + Playwright 自动化发布掘金文章,我是怎么搞定的

4 阅读1分钟

用 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()

完整发布流程

把上面的拼起来,完整流程是这样的:

  1. Playwright 启动 headless Chromium
  2. 加载本地 cookie 文件
  3. 访问掘金首页续期 cookie
  4. 从浏览器提取 cookie 字典
  5. 调 API 创建草稿
  6. 调 API 更新草稿(确保内容完整)
  7. 调 API 发布
  8. 重新导出 cookie 保存

整个过程跑下来大概10秒,比手动操作快了不知道多少倍。

踩坑总结

表现解决方案
短周期 cookie 过期API 返回 401每次发文前访问首页续期
brief_content 超长返回"参数错误"截断到100字以内
更新不带 mark_content内容被清空每次更新都带上完整内容
cookie 格式问题Playwright 加载失败用 Netscape 格式 + cookielib 解析

我现在已经把这套流程跑成了定时任务,每3天自动发一篇。写完文章扔进去就行,发布完全不用管。

当然这个方案还有改进空间——比如自动生成摘要、自动选择最合适的标签、甚至根据阅读数据优化发布时间。这些等后面有空再搞吧。

如果你也想搞自动发布,核心就一句话:先把 cookie 续期逻辑搞定,再调 API,别上来就莽