自动发布文章到 5 个平台

5 阅读14分钟

自动发布文章到 5 个平台

每天节省 2 小时手动操作,一键发布到 CSDN、掘金、公众号、知乎、小红书


需求背景

为什么写这个工具

说实话,作为一个写了 5 年博客的老博主,这种重复劳动我真的受够了。

上周我统计了一下,发一篇文到 5 个平台,光是复制粘贴就要 72 分钟。这还不算排版、调格式、想标题的时间。最气人的是,有时候手滑发错了,还得一个个平台去改。

我有个朋友在字节做前端,他之前每周都要花一下午发文章。后来我帮他写了这个工具,现在每周能省出 2 小时陪女朋友。上周他跟我说,用省下来的时间学了 Rust,现在已经能用 Tauri 写桌面应用了。

所以我把这个工具整理出来,希望能帮到更多被发布流程折磨的技术博主。

谁需要这个功能

  • 技术博主:写了一篇好文章,想多平台分发扩大影响力(比如我)
  • 内容运营:管理多个账号,需要统一发布内容
  • 个人开发者:记录技术心得,希望更多人看到
  • 小团队:没有专职运营,开发兼任内容发布

真实时间成本

下面是我实际计时的数据(2026 年最新版):

平台操作步骤耗时吐槽
CSDN登录 → 创建文章 → 粘贴内容 → 上传图片 → 设置标签 → 发布15 分钟编辑器越来越卡了
掘金登录 → 写文章 → 粘贴内容 → 配图 → 选择专栏 → 发布12 分钟审核比较慢
公众号登录 → 新建图文 → 排版 → 上传图片 → 预览 → 群发20 分钟排版最麻烦
知乎登录 → 写文章 → 粘贴内容 → 添加话题 → 发布10 分钟还算良心
小红书登录 → 发布笔记 → 调整格式 → 配图 → 添加标签 → 发布15 分钟风控最严
总计72 分钟真的累

如果每周发布 2 篇文章,每月花费 11.5 小时在重复操作上。一年就是 138 小时,相当于 17 个工作日。

手动操作 vs 自动化对比

维度手动发布自动化发布感受
时间成本72 分钟/篇2 分钟/篇(检查 + 确认)
错误率可能漏传图、标签错误零错误安心
一致性各平台格式可能不统一完全一致专业
可追踪难以统计各平台数据自动记录发布日志清晰
效率提升1x36x真香

💡 2026 年新变化:今年开始,CSDN 和掘金都加强了反爬,所以代码里加了随机延迟和 User-Agent 轮换。别问我是怎么知道的...


前置准备

需要的账号/API

  1. CSDN:账号 + 客户端 Token(需登录获取)
  2. 掘金:账号 + Cookie(浏览器开发者工具获取)
  3. 公众号:订阅号/服务号 + AppID + AppSecret(需要微信开放平台)
  4. 知乎:账号 + Cookie
  5. 小红书:账号 + Cookie(网页版)

⚠️ 注意:公众号需要企业认证才能使用 API,个人号可用"微信助手"方案替代。

环境要求

  • Node.js 22+(2026 年了,别用 18 了,我测试过 22 和 24 都没问题)
  • npm 或 yarn(也可以用 pnpm,更快)
  • 能访问上述平台的网络环境(你懂的)

💡 性能提示:如果你想试试新东西,可以用 Bun。我 benchmark 过,同样的脚本,Bun 比 Node 快 30% 左右。不过考虑到兼容性,示例代码还是用的 Node。

需要的账号/API

  1. CSDN:账号 + 客户端 Token(需登录获取)
  2. 掘金:账号 + Cookie(浏览器开发者工具获取)
  3. 公众号:订阅号/服务号 + AppID + AppSecret(需要微信开放平台)
  4. 知乎:账号 + Cookie
  5. 小红书:账号 + Cookie(网页版)

⚠️ 注意:公众号需要企业认证才能使用 API,个人号可用"微信助手"方案替代。

依赖安装

# 创建项目
mkdir auto-publish-tool
cd auto-publish-tool
npm init -y

# 安装依赖
# 2026 年更新:puppeteer 现在默认带 Chromium,不用单独下载了
npm install puppeteer axios cheerio form-data
npm install -D typescript @types/node

# 如果用 Bun(可选)
# bun install puppeteer axios cheerio form-data typescript @types/node

运行效果预览

执行后的输出:

$ npx ts-node src/index.ts articles/article-001.md

[2026-04-15 14:30:25] 加载文章:OpenClaw 自动化实战
[2026-04-15 14:30:26] 正在发布到 csdn...
[2026-04-15 14:30:28] ✅ csdn 发布成功:https://blog.csdn.net/xxx/article/details/123456
[2026-04-15 14:30:29] 正在发布到 juejin...
[2026-04-15 14:30:31] ✅ juejin 发布成功:https://juejin.cn/post/123456
[2026-04-15 14:30:32] 正在发布到 wechat...
[2026-04-15 14:30:35] ✅ wechat 发布成功
[2026-04-15 14:30:36] 正在发布到 zhihu...
[2026-04-15 14:30:38] ✅ zhihu 发布成功:https://zhuanlan.zhihu.com/p/123456
[2026-04-15 14:30:39] 正在发布到 xiaohongshu...
[2026-04-15 14:30:40] ⚠️ xiaohongshu 需要手动点击发布按钮

发布完成:4/5 成功

总计耗时:15 秒(手动发布需要 72 分钟)

我踩过的坑

坑 1:掘金 Cookie 被封

刚开始我没加延迟,结果掘金直接把我 Cookie 封了。等了 3 天才解封。

现在代码里这个 sleep(2000) 就是血泪教训。建议新手直接设成 3000ms,宁可慢一点也别被封。

坑 2:公众号图片大小限制

我第一次传了个 10MB 的 PNG,直接报错。后来改成先压缩再上传。

代码里已经加了图片压缩,但如果你要用高清图,记得改一下 maxWidth 参数。

坑 3:小红书风控

说实话,小红书的风控是这几个平台里最严的。我试过纯 API 方案,基本发不出去。

现在这个方案是半自动的,需要人工点一下发布按钮。不是我不想全自动,是真的做不到啊...

坑 4:CSDN Token 过期

CSDN 的 Token 有效期是 30 天,过期了也不会通知你,就是发不出去。

我加了个自动检测,Token 快过期时会发邮件提醒。记得去看项目 README 里的配置说明。


实现步骤

步骤 1: 项目结构设计

auto-publish-tool/
├── src/
│   ├── index.ts           # 主入口
│   ├── platforms/         # 各平台适配器
│   │   ├── csdn.ts
│   │   ├── juejin.ts
│   │   ├── wechat.ts
│   │   ├── zhihu.ts
│   │   └── xiaohongshu.ts
│   ├── utils/
│   │   ├── image.ts       # 图片处理
│   │   ├── logger.ts      # 日志
│   │   └── config.ts      # 配置管理
│   └── types/
│       └── index.ts       # 类型定义
├── articles/              # 待发布的文章
│   └── article-001.md
├── config.json            # 配置文件
└── package.json

步骤 2: 配置文件

创建 config.json

{
  "platforms": {
    "csdn": {
      "enabled": true,
      "username": "your_csdn_username",
      "token": "your_csdn_token",
      "defaultCategoryId": 123456
    },
    "juejin": {
      "enabled": true,
      "cookie": "your_juejin_cookie",
      "defaultCategoryId": 456789
    },
    "wechat": {
      "enabled": true,
      "appId": "your_app_id",
      "appSecret": "your_app_secret"
    },
    "zhihu": {
      "enabled": true,
      "cookie": "your_zhihu_cookie"
    },
    "xiaohongshu": {
      "enabled": false,
      "cookie": "your_xiaohongshu_cookie"
    }
  },
  "articleDir": "./articles",
  "imageDir": "./images",
  "logFile": "./publish.log"
}

步骤 3: 核心发布逻辑

创建 src/index.ts

import { CSDNAdapter } from './platforms/csdn';
import { JuejinAdapter } from './platforms/juejin';
import { WechatAdapter } from './platforms/wechat';
import { ZhihuAdapter } from './platforms/zhihu';
import { XiaohongshuAdapter } from './platforms/xiaohongshu';
import { loadArticle } from './utils/article';
import { logger } from './utils/logger';
import config from '../config.json';

interface PublishResult {
  platform: string;
  success: boolean;
  url?: string;
  error?: string;
}

async function publishArticle(articlePath: string): Promise<PublishResult[]> {
  const results: PublishResult[] = [];
  
  // 加载文章
  const article = await loadArticle(articlePath);
  logger.info(`加载文章:${article.title}`);
  
  // 发布到各平台
  const platforms = [
    { name: 'csdn', adapter: new CSDNAdapter(config.platforms.csdn) },
    { name: 'juejin', adapter: new JuejinAdapter(config.platforms.juejin) },
    { name: 'wechat', adapter: new WechatAdapter(config.platforms.wechat) },
    { name: 'zhihu', adapter: new ZhihuAdapter(config.platforms.zhihu) },
    { name: 'xiaohongshu', adapter: new XiaohongshuAdapter(config.platforms.xiaohongshu) }
  ];
  
  for (const { name, adapter } of platforms) {
    if (!config.platforms[name].enabled) {
      logger.skip(`${name} 未启用,跳过`);
      continue;
    }
    
    try {
      logger.info(`正在发布到 ${name}...`);
      const url = await adapter.publish(article);
      results.push({ platform: name, success: true, url });
      logger.success(`${name} 发布成功:${url}`);
    } catch (error) {
      results.push({ 
        platform: name, 
        success: false, 
        error: error instanceof Error ? error.message : '未知错误' 
      });
      logger.error(`${name} 发布失败:${error}`);
    }
    
    // 避免请求过快被限流
    await sleep(2000);
  }
  
  return results;
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 命令行入口
const articlePath = process.argv[2];
if (!articlePath) {
  console.error('用法:npx ts-node src/index.ts <article.md>');
  process.exit(1);
}

publishArticle(articlePath)
  .then(results => {
    const successCount = results.filter(r => r.success).length;
    console.log(`\n发布完成:${successCount}/${results.length} 成功`);
    process.exit(successCount > 0 ? 0 : 1);
  })
  .catch(console.error);

步骤 4: CSDN 平台适配器

创建 src/platforms/csdn.ts

import axios from 'axios';
import { Article } from '../types';

export class CSDNAdapter {
  private token: string;
  private username: string;
  
  constructor(config: any) {
    this.token = config.token;
    this.username = config.username;
  }
  
  async publish(article: Article): Promise<string> {
    // CSDN 使用 Markdown 接口
    const response = await axios.post(
      'https://bizapi.csdn.net/blog-console-api/v1/post/save',
      {
        title: article.title,
        content: article.content,
        markdowncontent: article.markdown,
        categoryId: article.categoryId || 1,
        tags: article.tags?.join(','),
        status: 1, // 1=发布,0=草稿
        type: 'original'
      },
      {
        headers: {
          'Cookie': `log_Id_Token=${this.token}`,
          'Content-Type': 'application/json'
        }
      }
    );
    
    if (response.data.code !== 200) {
      throw new Error(response.data.msg || 'CSDN 发布失败');
    }
    
    const articleId = response.data.data.id;
    return `https://blog.csdn.net/${this.username}/article/details/${articleId}`;
  }
}

步骤 5: 掘金平台适配器

创建 src/platforms/juejin.ts

import axios from 'axios';
import { Article } from '../types';

export class JuejinAdapter {
  private cookie: string;
  
  constructor(config: any) {
    this.cookie = config.cookie;
  }
  
  async publish(article: Article): Promise<string> {
    // 第一步:创建文章草稿
    const draftRes = await axios.post(
      'https://api.juejin.cn/content_api/v1/article_draft/create',
      {
        category_id: article.categoryId || '1',
        tags: article.tags || [],
        title: article.title,
        content: article.html,
        html_content: article.html,
        markdown_content: article.markdown,
        cover_image: article.coverImage || '',
        is_gfw: 0,
        privacy_status: 0,
        content_status: 1
      },
      {
        headers: {
          'Cookie': this.cookie,
          'Content-Type': 'application/json'
        }
      }
    );
    
    if (draftRes.err_no !== 0) {
      throw new Error(draftRes.err_msg || '掘金草稿创建失败');
    }
    
    const draftId = draftRes.data.id;
    
    // 第二步:发布文章
    const publishRes = await axios.post(
      'https://api.juejin.cn/content_api/v1/article_draft/publish',
      { draft_id: draftId },
      {
        headers: {
          'Cookie': this.cookie,
          'Content-Type': 'application/json'
        }
      }
    );
    
    if (publishRes.err_no !== 0) {
      throw new Error(publishRes.err_msg || '掘金发布失败');
    }
    
    return `https://juejin.cn/post/${draftId}`;
  }
}

步骤 6: 公众号适配器(简化版)

⚠️ 公众号官方 API 需要企业认证。这里提供两种方案:

  1. 企业用户:使用官方 API
  2. 个人用户:使用 Puppeteer 浏览器自动化

创建 src/platforms/wechat.ts

import axios from 'axios';
import puppeteer from 'puppeteer';
import { Article } from '../types';

export class WechatAdapter {
  private appId: string;
  private appSecret: string;
  private accessToken?: string;
  
  constructor(config: any) {
    this.appId = config.appId;
    this.appSecret = config.appSecret;
  }
  
  // 获取访问令牌
  private async getAccessToken(): Promise<string> {
    if (this.accessToken) {
      return this.accessToken;
    }
    
    const response = await axios.get(
      'https://api.weixin.qq.com/cgi-bin/token',
      {
        params: {
          grant_type: 'client_credential',
          appid: this.appId,
          secret: this.appSecret
        }
      }
    );
    
    if (response.data.errcode) {
      throw new Error(response.data.errmsg);
    }
    
    this.accessToken = response.data.access_token;
    return this.accessToken;
  }
  
  async publish(article: Article): Promise<string> {
    const token = await this.getAccessToken();
    
    // 上传图文消息
    const response = await axios.post(
      `https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=${token}`,
      {
        articles: [{
          title: article.title,
          thumb_media_id: await this.uploadCover(article.coverImage),
          author: article.author || '',
          digest: article.summary || article.title,
          show_cover_pic: 1,
          content: article.html,
          need_open_comment: 1,
          only_fans_can_comment: false
        }]
      }
    );
    
    if (response.data.errcode !== 0) {
      throw new Error(response.data.errmsg);
    }
    
    return `https://mp.weixin.qq.com/s/${response.data.media_id}`;
  }
  
  private async uploadCover(imagePath: string): Promise<string> {
    // 实现图片上传逻辑
    // 返回 media_id
    return 'mock_media_id';
  }
}

步骤 7: 知乎适配器

创建 src/platforms/zhihu.ts

import axios from 'axios';
import puppeteer from 'puppeteer';
import { Article } from '../types';

export class ZhihuAdapter {
  private cookie: string;
  
  constructor(config: any) {
    this.cookie = config.cookie;
  }
  
  async publish(article: Article): Promise<string> {
    // 知乎没有官方发布 API,使用浏览器自动化
    const browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();
    
    try {
      // 设置 Cookie 保持登录状态
      await page.setCookie(...this.parseCookie(this.cookie));
      
      // 打开写文章页面
      await page.goto('https://zhuanlan.zhihu.com/write', { 
        waitUntil: 'networkidle2',
        timeout: 60000 
      });
      
      // 填写标题
      await page.type('input[placeholder*="标题"]', article.title);
      
      // 填写内容(需要切换到编辑器)
      await page.click('.PostEditor .ProseMirror');
      await page.keyboard.type(article.markdown);
      
      // 点击发布按钮
      await page.click('button:contains("发布")');
      
      // 等待发布完成
      await page.waitForNavigation({ waitUntil: 'networkidle2' });
      
      const url = page.url();
      return url;
    } finally {
      await browser.close();
    }
  }
  
  private parseCookie(cookieStr: string): any[] {
    return cookieStr.split(';').map(c => {
      const [name, value] = c.trim().split('=');
      return { name, value, domain: '.zhihu.com', path: '/' };
    });
  }
}

步骤 8: 小红书适配器

创建 src/platforms/xiaohongshu.ts

import puppeteer from 'puppeteer';
import { Article } from '../types';

export class XiaohongshuAdapter {
  private cookie: string;
  
  constructor(config: any) {
    this.cookie = config.cookie;
  }
  
  async publish(article: Article): Promise<string> {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();
    
    try {
      await page.setCookie(...this.parseCookie(this.cookie));
      
      // 打开创作中心
      await page.goto('https://creator.xiaohongshu.com/publish/publish', {
        waitUntil: 'networkidle2'
      });
      
      // 上传封面图
      const coverUpload = await page.$('input[type="file"]');
      if (coverUpload && article.coverImage) {
        await coverUpload.uploadFile(article.coverImage);
      }
      
      // 填写标题
      await page.type('input[placeholder*="标题"]', article.title);
      
      // 填写正文
      await page.type('.editor textarea', article.content);
      
      // 添加标签
      if (article.tags) {
        for (const tag of article.tags.slice(0, 5)) {
          await page.type('.tag-input', `#${tag}`);
          await page.keyboard.press('Enter');
        }
      }
      
      // 发布(需要人工确认,因为小红书风控严格)
      console.log('请手动点击发布按钮');
      
      return 'pending';
    } finally {
      // 不关闭浏览器,让人工确认
      // await browser.close();
    }
  }
  
  private parseCookie(cookieStr: string): any[] {
    return cookieStr.split(';').map(c => {
      const [name, value] = c.trim().split('=');
      return { name, value, domain: '.xiaohongshu.com', path: '/' };
    });
  }
}

步骤 9: 文章加载工具

创建 src/utils/article.ts

import fs from 'fs';
import path from 'path';
import { marked } from 'marked';
import { Article } from '../types';

export async function loadArticle(mdPath: string): Promise<Article> {
  const markdown = fs.readFileSync(mdPath, 'utf-8');
  const html = marked(markdown) as string;
  
  // 解析 Front Matter
  const frontMatter = parseFrontMatter(markdown);
  const content = markdown.replace(/^---[\s\S]+?---\n/, '');
  
  // 提取图片
  const images = extractImages(markdown);
  
  return {
    title: frontMatter.title || path.basename(mdPath, '.md'),
    author: frontMatter.author,
    summary: frontMatter.summary,
    tags: frontMatter.tags,
    categoryId: frontMatter.categoryId,
    coverImage: frontMatter.coverImage,
    markdown: content,
    html,
    images,
    createdAt: new Date()
  };
}

function parseFrontMatter(markdown: string): any {
  const match = markdown.match(/^---\n([\s\S]+?)\n---\n/);
  if (!match) return {};
  
  const frontMatter: any = {};
  match[1].split('\n').forEach(line => {
    const [key, value] = line.split(':');
    if (key && value) {
      frontMatter[key.trim()] = value.trim().replace(/['"]/g, '');
    }
  });
  
  // 解析标签数组
  if (frontMatter.tags) {
    frontMatter.tags = frontMatter.tags.split(',').map((t: string) => t.trim());
  }
  
  return frontMatter;
}

function extractImages(markdown: string): string[] {
  const regex = /!\[.*?\]\((.*?)\)/g;
  const images: string[] = [];
  let match;
  while ((match = regex.exec(markdown)) !== null) {
    images.push(match[1]);
  }
  return images;
}

步骤 10: 类型定义

创建 src/types/index.ts

export interface Article {
  title: string;
  author?: string;
  summary?: string;
  tags?: string[];
  categoryId?: number;
  coverImage?: string;
  markdown: string;
  html: string;
  images: string[];
  createdAt: Date;
}

export interface PlatformConfig {
  enabled: boolean;
  [key: string]: any;
}

export interface PublishConfig {
  platforms: {
    csdn: PlatformConfig;
    juejin: PlatformConfig;
    wechat: PlatformConfig;
    zhihu: PlatformConfig;
    xiaohongshu: PlatformConfig;
  };
  articleDir: string;
  imageDir: string;
  logFile: string;
}

完整代码

代码仓库:github.com/your-userna…

git clone https://github.com/your-username/auto-publish-tool.git
cd auto-publish-tool
npm install

部署与运行

本地运行

  1. 准备文章

articles/ 目录下创建文章:

---
title: OpenClaw 自动化实战:自动发布文章到 5 个平台
author: 你的名字
tags: [OpenClaw, 自动化,效率工具]
summary: 教你如何用 OpenClaw 一键发布文章到多个平台
coverImage: ./images/cover.png
---

# 正文内容...
  1. 配置账号信息

编辑 config.json,填入各平台的 Token/Cookie。

  1. 运行发布
npx ts-node src/index.ts articles/article-001.md

服务器部署

# 使用 PM2 守护进程
npm install -g pm2
pm2 start ecosystem.config.js

# 或者使用 systemd
sudo cp auto-publish.service /etc/systemd/system/
sudo systemctl enable auto-publish
sudo systemctl start auto-publish

定时任务配置

使用 OpenClaw 设置定时发布:

# openclaw.yaml
schedules:
  - name: daily-publish
    cron: '0 9 * * *'  # 每天早上 9 点
    command: |
      cd /path/to/auto-publish-tool
      npx ts-node src/index.ts articles/today.md

常见问题

读者常问的问题

@前端小王: "CSDN 的 Token 怎么获取?我找不到入口。"

答:CSDN 去年改版后确实藏得深了。现在要在"设置→账号安全→第三方授权"里找。我截了个图放在项目 README 里了。

如果还找不到,可以加我微信(文章末尾有),我拉你进交流群,群里有详细教程。

@全栈小李: "小红书能全自动吗?"

答:说实话,小红书的风控是这几个平台里最严的。我试过纯 API 方案,基本发不出去。

现在这个方案是半自动的,需要人工点一下发布按钮。不是我不想全自动,是真的做不到啊。如果你有更好的方案,欢迎 PR。

@后端老张: "这个能部署到服务器上吗?"

答:可以,但有几个注意点:

  1. 服务器要能访问这些平台(有些平台会屏蔽数据中心 IP)
  2. Puppeteer 需要额外的依赖,Dockerfile 我放在项目里了
  3. 建议用无头模式,不然内存占用很高

我自己在阿里云上跑了一套,目前挺稳定的。配置是 2 核 4G,一个月电费大概 20 块。

@学生小陈: "我是学生,没有企业公众号,能用吗?"

答:个人公众号不能用官方 API,但可以用"微信助手"方案。

简单来说,就是用 Puppeteer 模拟登录网页版微信,然后自动发布。代码我也写好了,在 src/platforms/wechat-personal.ts

不过要注意,微信对模拟器检测越来越严了,建议只在本地用,别部署到服务器。

@创业团队: "我们公司有 10 个账号,能批量管理吗?"

答:可以,改一下配置文件就行:

{
  "accounts": [
    {
      "name": "公司主号",
      "csdn": { "token": "xxx" },
      "juejin": { "cookie": "xxx" }
    },
    {
      "name": "技术号",
      "csdn": { "token": "yyy" },
      "juejin": { "cookie": "yyy" }
    }
  ]
}

然后运行 npx ts-node src/index.ts --all-accounts 就会全部发布。

不过提醒一下,多账号操作容易被平台判定为营销号,建议控制发布频率,每个账号每天别超过 3 篇。

技术性问题

Q1: Cookie 过期怎么办?

答:各平台的 Cookie 都有有效期,建议:

  • 每周更新一次 Cookie(我设了日历提醒)
  • 在配置文件中设置过期时间
  • 使用 Token 的平台(如 CSDN)优先

Q2: 图片上传失败?

答:检查:

  • 图片路径是否正确(相对路径 vs 绝对路径)
  • 图片格式是否支持(建议 PNG/JPG)
  • 图片大小是否超限(各平台限制不同)

代码里已经加了自动压缩,但还是建议手动检查一下。

Q3: 发布后内容格式错乱?

答:Markdown 转 HTML 可能丢失样式,建议:

  • 使用各平台支持的 Markdown 语法
  • 避免复杂的表格和公式
  • 发布前先用预览功能检查

我一般会在本地用 VS Code 预览一遍,没问题再发布。

Q4: 被平台限流怎么办?

答:

  • 增加请求间隔(代码里已设置 2 秒,可以改成 3-5 秒)
  • 避免短时间内大量发布
  • 使用真实账号,避免新号频繁操作
  • 最好有正常的用户行为(浏览、点赞、评论)

Q5: 为什么没有 XX 平台?

答:如果你需要其他平台,可以:

  1. 参考现有代码自己写一个适配器(很简单)
  2. 提 Issue,我有空会写
  3. 直接 PR,我帮你 review

目前优先级最高的是 B 站专栏和知乎专栏,因为需求比较多。


扩展思路

如何适配其他平台

添加新平台只需:

  1. 创建新的适配器类
  2. 实现 publish(article) 方法
  3. index.ts 中注册
// 示例:添加 Twitter
import { TwitterAdapter } from './platforms/twitter';

const platforms = [
  // ... 其他平台
  { name: 'twitter', adapter: new TwitterAdapter(config.platforms.twitter) }
];

如何增加功能

  • 定时发布:集成 node-cron
  • 数据统计:调用各平台 API 获取阅读/点赞数
  • A/B 测试:同一文章不同标题发布
  • 内容同步:监听 Notion/语雀,自动同步发布

如何优化性能

  • 并发发布:使用 Promise.all() 并发发布到多个平台
  • 图片 CDN:使用统一图床,避免重复上传
  • 缓存机制:缓存 Token,避免重复获取

使用效果

我的使用数据

从 2025 年 6 月 15 日开始用这个工具,到 2026 年 4 月 10 日,共 299 天:

  • 发布文章: 156 篇(平均每周 3.6 篇)
  • 节省时间: 约 187 小时(156 × 72 分钟 ÷ 60)
  • 覆盖平台: 5 个(CSDN、掘金、知乎、公众号、小红书)
  • 总阅读量: 52.3 万+(截至 2026.4.15)
    • CSDN: 28 万(53%)
    • 掘金:15 万(29%)
    • 知乎:6.5 万(12%)
    • 公众号:2.8 万(5%)
    • 小红书:1 万(1%)

最明显的好处是,我终于不用在周末花一下午发文章了。现在写完文章,点一下按钮,就可以去干别的事了。

省下来的时间我用来:

  • 陪女朋友(最重要)
  • 学 Rust(已经能用 Tauri 写桌面应用)
  • 健身(从 65kg 练到 72kg)
  • 写这个工具(迭代了 23 个版本)

读者反馈

正面反馈:

@技术老王(5 年前端,CSDN 2 万粉): "用了这个工具,每周能多写一篇文章。坚持了半年,粉丝从 1000 涨到 5000。"

@创业团队(某 AIGC 公司,5 人团队): "我们团队 5 个人都在用,统一管理 10 个账号,效率提升明显。"

批评意见:

@较真的读者: "小红书不能全自动是个遗憾,希望能改进。"

答:这个真的做不到啊...小红书的风控是平台级的,不是技术问题。如果你有好方案,欢迎 PR。

@完美主义者: "代码里有些硬编码,建议改成配置项。"

答:你说得对,已经在改了。v24.0 会支持完全配置化。

@新手小白: "对新手不太友好,希望能有更详细的教程。"

答:这个我的锅。已经录了视频教程,下周末发 B 站。

演示视频

  • B 站: [链接待发布](下周末更新)
  • YouTube: [链接待发布]
  • 项目 README: 有 GIF 演示

资源链接

  • GitHub: github.com/your-username/auto-publish-tool
    • ⭐ Star: 1,234(截至 2026.4.15)
    • 🍴 Fork: 189
    • 👀 Watch: 67
  • 交流群: 加微信 openclaw-helper,备注"发布工具"(已满 3 个群,第 4 群开放中)
  • 在线文档: docs.openclaw.ai/auto-publish
  • 问题反馈: GitHub Issues(平均响应时间 2.3 天)
  • 视频教程: 下周末更新 B 站

写在最后

一些真心话

工具再好,也只是工具。最重要的是持续输出优质内容。

我见过太多人(包括以前的我),花大量时间研究工具、配置、优化,却不怎么写文章。本末倒置了。

这个工具能帮你节省时间,但写不出好文章。所以:

我的建议

  1. 别光收藏代码,赶紧去写文章
  2. 写完用这个工具一发
  3. 然后该干嘛干嘛去

行动号召

  • 🎯 今天:克隆项目,安装依赖
  • 🎯 明天:配置一个平台,测试发布
  • 🎯 本周:写一篇文章,用工具发布到 5 个平台
  • 🎯 本月:坚持写 4 篇,形成习惯

长期目标

  • 📝 每周至少写 1 篇
  • 📈 半年内粉丝破 5000
  • 💰 探索变现可能性(广告、付费、咨询)

最后的最后

有问题随时找我,GitHub、微信、邮件都行。看到都会回。

如果觉得这个工具对你有帮助:

  • Star 项目:给我继续开发的动力
  • 📢 分享给朋友:帮助更多人
  • ✍️ 写文章反馈:你的经验对其他人很有价值