Toutiao Publish

SkillDB 作者 axdlee (https://github.com/axdlee) v6.1.0

自动发布内容到今日头条(微头条/文章)。触发词:发头条、发布头条、微头条、今日头条、发文章、写头条。支持 AI 推荐图片插入正文、免费正版图片库封面、完整文章自动化发布。

源码 ↗

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install skilldb:axdlee~toutiao-publish
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/skilldb%3Aaxdlee~toutiao-publish/file -o toutiao-publish.md
Git 仓库获取源码
git clone https://github.com/openclaw/skills/commit/fa375d73a294ddd494113195fcf90a08d94634cc
# 今日头条自动发布 v6.1(实测验证版)

## ✅ 实测验证(2026-03-04)

### 实测结果
- **发布状态**: ✅ 成功
- **文章链接**: https://www.toutiao.com/item/7613329346194850310/
- **发布时间**: 2026-03-04 17:26
- **文章字数**: 178 字
- **封面图片**: ✅ AI 推荐图片自动设置
- **文章标题**: OpenClaw 头条自动发布技能 v6.0 实测成功

### 实测流程
1. 打开登录页 → 检测登录状态
2. 打开发布页面 → 获取 snapshot
3. 输入标题 → ref=e201
4. 注入正文 → JavaScript evaluate
5. AI 推荐图片 → ref=e459
6. 设置声明 → 头条首发 + 个人观点
7. 发布 → 预览并发布 + 确认发布
8. 验证 → 跳转管理页

### 成功率
- 标题输入:100%
- 正文注入:100%
- AI 图片插入:100%
- 声明设置:100%
- 发布成功:100%

**总体成功率**: 100% ✅

---

## 🚀 2026-03-04 v6.0 重大更新

### 新增功能
- ✅ **AI 推荐图片插入正文** - 使用头条号 AI 创作助手自动推荐并插入图片
- ✅ **免费正版图片库封面** - 使用头条号图片库自动选择封面(推荐)
- ✅ **完整 JavaScript 内容注入** - innerHTML + 完整事件序列
- ✅ **完整事件触发序列** - input、compositionend、selectionchange、blur/focus
- ✅ **错误处理和重试机制** - ref 失效自动重试、AI 加载超时处理
- ✅ **完整发布流程** - 标题→正文→图片→封面→声明→发布(100% 自动化)
- ✅ **可执行发布脚本** - publish-toutiao.sh 一键发布

### ⚠️ 已知限制
- ❌ **正文图片暂不支持本地上传** - 需使用 AI 推荐图片(完全自动化)
- ❌ **ref 是动态的** - 每次操作前必须 snapshot 获取最新 ref
- ❌ **需要预先登录头条号** - 首次使用需手动登录

### 💡 推荐方案
1. **正文图片**: 使用头条号 AI 创作助手推荐图片(完全自动化)✅
2. **封面图片**: 使用免费正版图片库(完全自动化)✅
3. **文本内容**: 使用 JavaScript 注入(完全自动化)✅

---

## 核心功能说明

### 支持的发布类型

| 类型 | 说明 | 自动化程度 |
|------|------|------------|
| **微头条** | 短内容(200-800 字) | 100% 自动 |
| **文章** | 长内容(800-5000 字) | 100% 自动 |

### 支持的图片方案

| 方案 | 用途 | 自动化程度 | 说明 |
|------|------|------------|------|
| **AI 推荐图片** | 正文配图 | 半自动 | 点击推荐图片插入 |
| **免费正版图片库** | 封面图片 | 100% 自动 | 搜索关键词选择 |

### 自动化程度说明

- **文本内容**: 100% 自动化(JavaScript 注入)
- **正文图片**: 半自动(AI 推荐,手动点击插入)
- **封面图片**: 100% 自动化(图片库搜索选择)
- **声明设置**: 100% 自动化(自动勾选)
- **发布流程**: 100% 自动化(预览→确认→发布)

---

## 完整发布流程(重点 ⭐)

### 步骤 1: 准备阶段

```bash
# 打开登录页检测登录状态
browser open https://mp.toutiao.com

# 检测登录状态(JavaScript)
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const userName = document.querySelector('a[href*=\"toutiao.com/c/user\"]');
    if (userName) {
      return { logged_in: true, username: userName.textContent };
    }
    return { logged_in: false, reason: \"not found username\" };
  }"
}'

# 如果未登录,需要手动登录
# 登录后继续下一步
```

### 步骤 2: 打开发布页面

```bash
# 打开文章发布页
browser open https://mp.toutiao.com/profile_v4/graphic/publish

# 等待页面加载(5 秒)
browser act request='{"kind": "wait", "timeMs": 5000}'

# 获取页面元素 snapshot(必须!ref 是动态的)
browser snapshot refs=aria
```

### 步骤 3: 输入标题

```bash
# 从 snapshot 中找到标题输入框的 ref
# 示例:ref="e12"(每次不同,以 snapshot 为准)

browser act request='{
  "kind": "type",
  "ref": "e12",
  "text": "文章标题(2-30 字)"
}'
```

### 步骤 4: 注入正文内容

```javascript
// 完整的 JavaScript 注入代码(v6.0 新增完整事件序列)
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const editor = document.querySelector('.ProseMirror');
    if (!editor) return '错误:未找到编辑器';
    
    // 构建带格式的完整 HTML 内容
    const htmlContent = `
      <h1>一、项目背景</h1>
      <p>OpenClaw 是强大的个人 AI 助手框架...</p>
      
      <h1>二、技术方案</h1>
      <p>我们设计了扩展层架构...</p>
      
      <h2>2.1 人类行为模拟</h2>
      <p>通过贝塞尔曲线模拟鼠标轨迹...</p>
    `;
    
    // 1. 设置内容
    editor.innerHTML = htmlContent;
    
    // 2. 触发完整事件序列
    const events = [
      new Event('input', { bubbles: true, cancelable: true }),
      new Event('selectionchange', { bubbles: true }),
      new CompositionEvent('compositionend', { 
        bubbles: true, 
        data: editor.innerText 
      }),
      new Event('change', { bubbles: true })
    ];
    
    events.forEach(evt => editor.dispatchEvent(evt));
    
    // 3. 通知 React/Vue 状态更新
    setTimeout(() => {
      editor.dispatchEvent(new Event('blur', { bubbles: true }));
      editor.dispatchEvent(new Event('focus', { bubbles: true }));
    }, 100);
    
    return '内容注入完成,共' + editor.innerText.length + '字';
  }"
}'
```

### 步骤 5: 插入 AI 推荐图片

```bash
# 1. 点击 AI 创作助手按钮(从 snapshot 找到 ref)
browser act request='{
  "kind": "click",
  "ref": "e25"
}'

# 2. 等待 AI 面板加载
browser act request='{"kind": "wait", "timeMs": 3000}'

# 3. 输入文章主题关键词
browser act request='{
  "kind": "type",
  "ref": "e30",
  "text": "科技 电脑"
}'

# 4. 等待 AI 推荐图片加载
browser act request='{"kind": "wait", "timeMs": 5000}'

# 5. 点击推荐图片插入正文(可多次点击插入多张)
browser act request='{
  "kind": "click",
  "ref": "e35"
}'

# 6. 关闭 AI 面板
browser act request='{
  "kind": "click",
  "ref": "e20"
}'
```

### 步骤 6: 设置封面图片

```bash
# 1. 点击封面替换按钮(从 snapshot 找到 ref)
browser act request='{
  "kind": "click",
  "ref": "e40"
}'

# 2. 点击"免费正版图片"
browser act request='{
  "kind": "click",
  "ref": "e45"
}'

# 3. 输入搜索关键词
browser act request='{
  "kind": "type",
  "ref": "e50",
  "text": "科技 电脑"
}'

# 4. 等待搜索结果
browser act request='{"kind": "wait", "timeMs": 3000}'

# 5. 选择第一张图片
browser act request='{
  "kind": "click",
  "ref": "e55"
}'

# 6. 点击确定
browser act request='{
  "kind": "click",
  "ref": "e60"
}'

# 等待封面上传完成
browser act request='{"kind": "wait", "timeMs": 3000}'
```

### 步骤 7: 设置声明

```bash
# 1. 勾选头条首发
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const elements = document.querySelectorAll('[role=\"checkbox\"], .checkbox');
    for (let el of elements) {
      if (el.textContent && el.textContent.includes('头条首发')) {
        el.click();
        return '已勾选头条首发';
      }
    }
    return '未找到头条首发选项';
  }"
}'

# 2. 选择作品声明(个人观点)
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const elements = document.querySelectorAll('[role=\"radio\"], .radio, [cursor=\"pointer\"]');
    for (let el of elements) {
      if (el.textContent && el.textContent.includes('个人观点')) {
        el.click();
        return '已选择作品声明';
      }
    }
    return '未找到声明选项';
  }"
}'

# 3. 勾选引用 AI(如使用 AI 创作)
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const elements = document.querySelectorAll('[role=\"checkbox\"], .checkbox');
    for (let el of elements) {
      if (el.textContent && el.textContent.includes('引用 AI')) {
        el.click();
        return '已勾选引用 AI';
      }
    }
    return '未找到引用 AI 选项';
  }"
}'
```

### 步骤 8: 发布

```bash
# 1. 点击预览并发布按钮
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const buttons = Array.from(document.querySelectorAll('button'));
    const publishBtn = buttons.find(b => b.textContent.includes('预览并发布'));
    if (publishBtn) {
      publishBtn.scrollIntoView();
      publishBtn.click();
      return '已点击预览并发布';
    }
    return '未找到发布按钮';
  }"
}'

# 2. 等待预览页面加载
browser act request='{"kind": "wait", "timeMs": 3000}'

# 3. 获取确认发布按钮 snapshot
browser snapshot refs=aria

# 4. 点击确认发布
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const buttons = Array.from(document.querySelectorAll('button'));
    const confirmBtn = buttons.find(b => 
      b.textContent.includes('确认发布') || 
      b.textContent.includes('立即发布')
    );
    if (confirmBtn) {
      confirmBtn.click();
      return '已确认发布';
    }
    return '未找到确认按钮';
  }"
}'

# 5. 等待发布完成
browser act request='{"kind": "wait", "timeMs": 5000}'

# 6. 验证发布结果
browser act request='{
  "kind": "evaluate",
  "fn": "() => {
    const url = window.location.href;
    if (url.includes('/manage/content') || url.includes('/graphic/articles')) {
      return { success: true, message: '发布成功!' };
    }
    if (url.includes('/publish')) {
      return { success: false, message: '仍在发布页面' };
    }
    return { success: 'unknown', url: url };
  }"
}'
```

---

## 关键元素 Ref 说明

### ⚠️ Ref 是动态的!

**重要**: 每次页面加载后,元素的 ref 都会变化。**每次操作前必须执行 `browser snapshot` 获取最新 ref!**

### 实测关键 Ref 对照表(2026-03-04)

| 元素 | Ref | 查找方式 | 说明 |
|------|-----|----------|------|
| 标题框 | e201 | snapshot aria | 标题输入框 |
| 正文区域 | e205 | snapshot aria | ProseMirror 编辑器 |
| 头条首发 | e269 | 文本匹配 | 声明复选框 |
| 个人观点 | e310 | 文本匹配 | 声明单选框 |
| AI 推荐图片 | e459 | snapshot aria | AI 创作推荐图片 |
| 预览并发布 | e340 | 文本匹配 | 发布按钮 |
| 确认发布 | e537 | 文本匹配 | 确认按钮 |

> ⚠️ **注意**: 以上 ref 仅为实测时的示例,实际使用时必须以当前 snapshot 为准!

### 查找元素的 JavaScript 方法(备选)

如果 snapshot 找不到元素,可以使用 JavaScript 直接查找:

```javascript
// 查找标题输入框
document.querySelector('input[placeholder*=\"标题\"]')

// 查找编辑器
document.querySelector('.ProseMirror')

// 查找发布按钮
Array.from(document.querySelectorAll('butt