从零开发一个掘金自动发布 Skill,并上架 Clawhub

从零开发一个掘金自动发布 Skill,并上架 Clawhub

本文记录了一次完整的 Skill 开发旅程:从一句「帮我创建一个可以自动发布文章到掘金的 skill」开始,到最终成功上架 Clawhub,全程真实还原每一个关键决策和踩坑过程。


背景:为什么要做这个 Skill?

我日常运营一个 AI 资讯账号,每天需要将 Markdown 格式的文章发布到多个平台,包括微信公众号、小红书、掘金等。其中微信公众号和小红书已经有现成的 Skill 可以用,但掘金没有

每次发布掘金都要:

  1. 打开浏览器,登录掘金
  2. 进入编辑器,粘贴 Markdown 内容
  3. 手动设置分类、标签、摘要、封面
  4. 点击发布

这套流程重复且机械,非常适合自动化。于是决定自己动手,开发一个 juejin-publisher Skill。


第一步:研究掘金 API

开发自动发布工具,首先要搞清楚掘金的发布接口。掘金没有公开的开发者 API 文档,但可以通过浏览器抓包来分析。

抓包分析

打开掘金编辑器,按 F12 进入开发者工具,切换到 Network 标签,然后正常发布一篇文章,观察请求:

发现关键的两个接口:

① 创建草稿

bash 复制代码
POST https://api.juejin.cn/content_api/v1/article_draft/create

请求体(JSON):

json 复制代码
{
  "category_id": "6809637773935378440",
  "tag_ids": ["6809640445233070098"],
  "title": "文章标题",
  "brief_content": "摘要,50-100字",
  "edit_type": 10,
  "mark_content": "# Markdown 正文...",
  "cover_image": "",
  "html_content": "deprecated",
  "link_url": "",
  "theme_ids": []
}

② 发布草稿

bash 复制代码
POST https://api.juejin.cn/content_api/v1/article/publish

请求体:

json 复制代码
{
  "draft_id": "7xxxxxxxxxxxxxx",
  "sync_to_org": false,
  "column_ids": [],
  "theme_ids": []
}

鉴权方式

掘金使用 Cookie 鉴权,只需在请求头中带上登录后的 Cookie 即可。Cookie 有效期约 30 天,其中最关键的字段是:

ini 复制代码
sessionid=69c4b5312172d146beea98ddfabf5bd6

注意事项

  • edit_type: 10 代表 Markdown 模式(富文本模式为 0
  • brief_content 必须在 50-100 字之间,否则接口报错
  • tag_ids 是数组,category_id 是字符串

第二步:设计 Skill 结构

参考已有的 wechat-mp-publisher Skill 的目录规范,设计如下结构:

bash 复制代码
skills/juejin-publisher/
├── SKILL.md              # Skill 主文档(含 frontmatter 元数据)
├── README.md             # 快速说明
├── _meta.json            # 本地元数据
├── example.md            # 文章格式示例
├── juejin.env.example    # 配置文件模板
├── scripts/
│   ├── publish.py        # 核心发布脚本
│   └── query_tags.py     # 标签 ID 查询工具
└── references/
    ├── category_ids.md   # 常用分类 ID 参考
    └── tag_ids.md        # 常用标签 ID 参考

设计原则:

  • 核心逻辑用 Python 标准库实现,零依赖安装
  • 支持 Markdown frontmatter,让文章自带元数据
  • 提供 配置文件模板,降低上手门槛
  • 附带 标签查询工具,解决 tag_id 难以记忆的问题

第三步:编写核心发布脚本

3.1 配置加载

juejin.env 文件读取 Cookie 和默认配置:

python 复制代码
def load_config():
    """从 juejin.env 加载配置"""
    config = {}
    with open(CONFIG_FILE, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if line.startswith("#") or "=" not in line:
                continue
            # 支持 export KEY="VALUE" 和 KEY="VALUE" 两种格式
            line = line.removeprefix("export").strip()
            key, _, val = line.partition("=")
            val = val.strip().strip('"').strip("'")
            config[key.strip()] = val
    return config

3.2 Markdown 解析

支持从文章头部的 YAML frontmatter 中读取标题、摘要、封面、分类、标签:

python 复制代码
def parse_markdown(filepath):
    """解析 Markdown 文件,提取 frontmatter 和正文"""
    with open(filepath, "r", encoding="utf-8") as f:
        content = f.read()

    meta = {}
    body = content

    # 提取 YAML frontmatter
    fm_match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
    if fm_match:
        fm_text = fm_match.group(1)
        body = content[fm_match.end():]
        for line in fm_text.splitlines():
            if ":" in line:
                k, _, v = line.partition(":")
                meta[k.strip()] = v.strip().strip('"').strip("'")

    # 从正文提取标题(取第一个 # 标题)
    if "title" not in meta:
        title_match = re.search(r"^#\s+(.+)$", body, re.MULTILINE)
        if title_match:
            meta["title"] = title_match.group(1).strip()

    return meta, body.strip()

3.3 自动生成摘要

掘金要求摘要 50-100 字,脚本自动处理:

python 复制代码
def generate_brief(meta, body, min_len=50, max_len=100):
    """生成符合掘金要求的摘要(50-100字)"""
    if "description" in meta:
        brief = meta["description"]
        if min_len <= len(brief) <= max_len:
            return brief
        if len(brief) > max_len:
            return brief[:max_len]

    # 从正文提取纯文本生成摘要
    plain = re.sub(r"```.*?```", "", body, flags=re.DOTALL)
    plain = re.sub(r"[#*`>\[\]!]", "", plain)
    plain = re.sub(r"\s+", " ", plain).strip()
    return plain[:max_len]

3.4 API 调用封装

使用 Python 内置的 urllib 实现 HTTP 请求,无需安装 requests

python 复制代码
def api_post(path, data, cookie):
    """发送 POST 请求到掘金 API"""
    url = f"https://api.juejin.cn{path}"
    payload = json.dumps(data).encode("utf-8")
    headers = {
        "Content-Type": "application/json; charset=utf-8",
        "Cookie": cookie,
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
        "Referer": "https://juejin.cn/",
        "Origin": "https://juejin.cn",
    }
    req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read().decode("utf-8"))

3.5 完整发布流程

python 复制代码
def main():
    # 1. 解析命令行参数
    args = parse_args()
    
    # 2. 加载 Cookie 配置
    config = load_config()
    cookie = config["JUEJIN_COOKIE"]
    
    # 3. 解析 Markdown 文件
    meta, body = parse_markdown(args.file)
    title = meta.get("title", "无标题")
    brief = generate_brief(meta, body)
    
    # 4. 创建草稿
    draft_id = create_draft(title, body, brief, category_id, tag_ids, cover_image, cookie)
    
    # 5. 发布(除非指定 --draft-only)
    if not args.draft_only:
        article_id = publish_draft(draft_id, cookie)
        print(f"🎉 文章已发布: https://juejin.cn/post/{article_id}")

使用示例

Markdown 文章格式(支持 frontmatter):

markdown 复制代码
---
title: 我的技术文章标题
description: 这里是文章摘要,建议 50-100 字,会显示在文章列表中
cover: https://example.com/cover.jpg
category_id: "6809637773935378440"
tag_ids: "6809640445233070098,6809640408797167623"
---

# 正文内容开始

这里是 Markdown 正文...

命令行调用:

bash 复制代码
# 基本发布
python3 scripts/publish.py article.md

# 指定分类和标签
python3 scripts/publish.py article.md \
  --category "6809637773935378440" \
  --tags "6809640445233070098"

# 仅创建草稿
python3 scripts/publish.py article.md --draft-only

第四步:编写 SKILL.md 规范文件

Skill 的核心是 SKILL.md,它既是使用文档,也是 AI 理解该 Skill 的"说明书"。文件头部需要包含 frontmatter 元数据:

yaml 复制代码
---
name: juejin-publisher
version: 1.0.0
license: MIT
description: 掘金文章自动发布技能。通过掘金官方 API(Cookie 鉴权),
  支持将 Markdown 文章一键发布到稀土掘金平台,支持设置分类、标签、摘要和封面图。
metadata:
  openclaw:
    emoji: "⛏️"
    category: publishing
  clawdbot:
    emoji: "⛏️"
    requires:
      bins: ["python3", "curl"]
    install: []
---

关键字段说明:

  • name:Skill 的唯一标识,发布到 Clawhub 后即为 slug
  • license必填,Clawhub 发布时服务端会校验此字段(踩坑记录见下方)
  • metadata.clawdbot.requires.bins:声明运行时依赖的系统命令

第五步:发布到 Clawhub

5.1 安装 clawhub CLI

bash 复制代码
npm install -g clawhub

安装完成后验证:

bash 复制代码
clawhub --version
# 0.7.0

5.2 登录

由于是在无 UI 的 Linux 服务器上操作,使用 Token 登录模式:

bash 复制代码
clawhub login --token clh_xxxxxxxxxxxxxxxxxx

Token 获取方式:登录 clawhub.ai → Settings → API Tokens → 创建新 Token。

5.3 发布 Skill

bash 复制代码
clawhub publish /data/workspace/skills/juejin-publisher --version 1.0.0

5.4 踩坑:acceptLicenseTerms 报错

第一次发布时遇到报错:

swift 复制代码
Error: acceptLicenseTerms is required

原因:Clawhub 服务端要求 payload 中包含 acceptLicenseTerms: true 字段,但 CLI(v0.7.0)的 publish.js 脚本并没有在 payload 中传递这个字段。

解决方案: 修改 CLI 源码,在 payload 中补充该字段:

bash 复制代码
# 定位 publish.js 文件
find /usr/local/node/lib/node_modules/clawhub/dist/cli/commands/ -name "publish.js"

# 使用 sed 在 payload 对象中插入字段
sed -i 's/form.set('\''payload'\'', JSON.stringify({/form.set('\''payload'\'', JSON.stringify({ acceptLicenseTerms: true,/' \
  /usr/local/node/lib/node_modules/clawhub/dist/cli/commands/publish.js

修改后重新发布,成功!

另一个解决方案 (更优雅):在 SKILL.md frontmatter 中添加 license: MIT 字段,部分版本的 CLI 会据此自动处理。

5.5 发布成功

yaml 复制代码
✅ Skill published successfully!
  Name:       juejin-publisher
  Version:    1.0.0
  Version ID: k97d5hg42cnk2yhzgjswhx8jc982n3nv
  Publisher:  @devilWwj

现在任何人都可以通过以下命令安装使用:

bash 复制代码
clawhub install juejin-publisher

完整目录结构

bash 复制代码
skills/juejin-publisher/
├── SKILL.md                    # Skill 主文档 + AI 使用说明
├── README.md                   # 快速说明
├── _meta.json                  # 本地元数据
├── example.md                  # 文章格式示例(含 frontmatter)
├── juejin.env.example          # 配置文件模板(需复制为 juejin.env)
├── scripts/
│   ├── publish.py              # 核心发布脚本(~200行,纯标准库)
│   └── query_tags.py           # 标签 ID 查询工具
└── references/
    ├── category_ids.md         # 常用分类 ID 速查表
    └── tag_ids.md              # 常用标签 ID 速查表

常用分类 ID 速查

分类名称 category_id
前端 6809637767543259144
后端 6809637769959178254
AI 6809637773935378440
工具 6809637771511070734
Android 6809635626879549454
iOS 6809635627209637895

总结与思考

这次 Skill 开发的整体流程:

复制代码
需求分析 → 抓包研究 API → 脚本实现 → Skill 规范封装 → 上架 Clawhub

几个关键经验:

  1. 掘金 API 不难逆向:浏览器抓包 + 观察请求体,基本上两个接口就能搞定发布全流程

  2. 摘要长度是坑brief_content 必须 50-100 字,太短或太长都会报错,自动生成摘要时要处理边界情况

  3. 零依赖设计更健壮 :用 Python 标准库的 urllib 代替 requests,避免在不同环境中出现依赖缺失的问题

  4. Clawhub 发布需要 license 字段SKILL.md frontmatter 中必须声明 license,否则服务端校验不通过

  5. Skill 的价值在于可复用:封装好的 Skill 不仅自己用,还能分享给社区,一次开发多人受益


相关链接

如果你也在做内容自动化,欢迎交流 👋

相关推荐
颜酱2 小时前
图的数据结构:从「多叉树」到存储与遍历
javascript·后端·算法
雨中飘荡的记忆3 小时前
零拷贝技术深度解析
后端
uzong3 小时前
十年老员工的项目管理实战心得:有道有术
后端
Victor3564 小时前
MongoDB(31)索引对查询性能有何影响?
后端
Victor3565 小时前
MongoDB(30)如何删除索引?
后端
lizhongxuan5 小时前
多 Agent 协同机制对比
后端
IT_陈寒5 小时前
SpringBoot项目启动慢?5个技巧让你的应用秒级响应!
前端·人工智能·后端
树上有只程序猿6 小时前
2026低代码选型指南,主流低代码开发平台排名出炉
前端·后端
高端章鱼哥6 小时前
为什么说用OpenClaw对打工人来说“不划算”
前端·后端