返回

X(Twitter) 推文自动备份到 Notion + 飞书 - 完整开发文档

#notes#项目记录#记录
<html> <body> <!--StartFragment--><html><head></head><body><h1>X(Twitter) 推文自动备份到 Notion + 飞书 - 完整开发文档</h1> <h2>📋 项目概述</h2> <p>本项目实现了一个 n8n 自动化工作流,每天定时将 X(Twitter) 账号的原创推文和转发推文备份到 Notion 数据库和飞书多维表格中。</p> <h3>功能特性</h3> <ul> <li>✅ 每天早上 7 点自动运行</li> <li>✅ 获取昨天的所有推文(原创 + 转发)</li> <li>✅ 自动排除回复内容</li> <li>✅ 同步到 Notion 和飞书</li> <li>✅ 支持代理访问 Twitter API</li> <li>✅ 完善的错误处理和日志记录</li> </ul> <hr> <h2>🏗️ 系统架构</h2> <h3>工作流节点图</h3> <pre><code>每天早7点触发 ↓ 计算时间范围(昨天 00:00 - 今天 00:00) ↓ 获取推文数据(通过代理访问 Twitter API) ↓ 处理推文数据(分离原创/转发,数据清洗) ↓ 过滤有效数据(确保数据完整性) ↓ ├─→ 写入 Notion(单条写入) │ └─→ 获取飞书 Token ↓ 准备飞书批量数据 ↓ 批量写入飞书(一次写入所有) </code></pre> <hr> <h2>🐛 开发过程中的问题与解决方案</h2> <h3>问题 1:合并节点配置错误</h3> <p><strong>错误信息:</strong></p> <pre><code>You need to define at least one pair of fields in "Fields to Match" to match on </code></pre> <p><strong>原因分析:</strong></p> <ul> <li>使用了 <code>mode: "combine"</code> + <code>combinationMode: "mergeByPosition"</code></li> <li>这种模式需要定义匹配字段才能合并数据</li> </ul> <p><strong>解决方案:</strong></p> <pre><code class="language-json">{ "parameters": { "mode": "append" // 改为追加模式,不需要匹配字段 } } </code></pre> <p><strong>经验总结:</strong></p> <ul> <li><code>combine</code> 模式:用于按字段匹配合并(需要配置匹配字段)</li> <li><code>append</code> 模式:简单追加所有数据(适合本场景)</li> </ul> <hr> <h3>问题 2:Twitter API 速率限制(429 错误)</h3> <p><strong>错误信息:</strong></p> <pre><code class="language-json">{ "status": 429, "title": "Too Many Requests" } </code></pre> <p><strong>原因分析:</strong></p> <ul> <li>初始设计分别调用两次 API(原创推文 + 转发推文)</li> <li>Twitter API v2 有严格的速率限制</li> <li>Free tier 每月只有 1500 条推文读取配额</li> </ul> <p><strong>解决方案:</strong> 优化为单次 API 调用:</p> <pre><code class="language-javascript">// 一次性获取所有推文(不排除转发) url: "https://api.twitter.com/2/users/{user_id}/tweets" queryParameters: { exclude: "replies", // 只排除回复 tweet.fields: "created_at,public_metrics,referenced_tweets" }

// 在代码节点中分离原创和转发 const isRetweet = tweet.referenced_tweets?.some(ref => ref.type === 'retweeted'); </code></pre>

<p><strong>经验总结:</strong></p> <ul> <li>优先使用单次 API 调用获取所有数据</li> <li>在代码中进行数据分类和过滤</li> <li>API 调用次数:从 2 次降低到 1 次(减少 50%)</li> </ul> <hr> <h3>问题 3:代理配置缺失</h3> <p><strong>问题描述:</strong> 国内网络环境无法直接访问 Twitter API</p> <p><strong>解决方案:</strong> 在 HTTP Request 节点中添加代理配置:</p> <pre><code class="language-json">{ "options": { "proxy": "http://127.0.0.1:7890", "timeout": 30000 } } </code></pre> <p><strong>注意事项:</strong></p> <ul> <li>确保本地代理软件正在运行</li> <li>测试代理:<code>curl -x http://127.0.0.1:7890 https://api.twitter.com</code></li> <li>根据实际情况修改端口号</li> </ul> <hr> <h3>问题 4:飞书认证 Token 过期</h3> <p><strong>问题描述:</strong> 初始配置使用硬编码的 Bearer Token,很快过期失效</p> <p><strong>错误方案:</strong></p> <pre><code class="language-json">{ "headers": { "Authorization": "Bearer u-ef55Oywvd6eW9f7H4uMP0911jQYw10qphMG050MGwB8D" } } </code></pre> <p><strong>正确方案:</strong> 使用飞书应用凭证动态获取 Token:</p> <ol> <li><strong>获取 Token 节点:</strong></li> </ol> <pre><code class="language-json">{ "method": "POST", "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", "bodyParameters": { "app_id": "cli_a985d1564eb9900b", "app_secret": "m83GwLY8ytgaX03E5wxapiIVvjzSvlPP" } } </code></pre> <ol start="2"> <li><strong>使用动态 Token:</strong></li> </ol> <pre><code class="language-json">{ "headers": { "Authorization": "Bearer {{ $('获取飞书Token').item.json.tenant_access_token }}" } } </code></pre> <p><strong>经验总结:</strong></p> <ul> <li>永远不要硬编码 Token</li> <li>使用应用凭证动态获取,保证长期有效</li> </ul> <hr> <h3>问题 5:推文内容导致 JSON 解析错误</h3> <p><strong>错误信息:</strong></p> <pre><code>JSON parameter needs to be valid JSON </code></pre> <p><strong>原因分析:</strong> 推文内容包含特殊字符(换行符、制表符、引号等)破坏 JSON 格式:</p> <pre><code class="language-javascript">// 问题示例 "Content": "这是一条推文 包含换行符" // ❌ 导致 JSON 解析失败 </code></pre> <p><strong>初次尝试(失败):</strong></p> <pre><code class="language-javascript">// 转义特殊字符 cleanText = cleanText .replace(/\n/g, '\\n') .replace(/"/g, '\\"') // 问题:在 n8n 表达式中仍然可能出错 </code></pre> <p><strong>最终方案:</strong></p> <pre><code class="language-javascript">// 直接移除或替换特殊字符为空格 cleanText = cleanText .replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, '') // 移除控制字符 .replace(/\r\n/g, ' ') // Windows 换行 .replace(/\r/g, ' ') // Mac 换行 .replace(/\n/g, ' ') // Unix 换行 .replace(/\t/g, ' ') // 制表符 .trim(); </code></pre> <p><strong>经验总结:</strong></p> <ul> <li>对于用户输入的文本,永远不要假设格式</li> <li>在插入 JSON 前必须清理数据</li> <li>简单替换为空格比复杂转义更可靠</li> </ul> <hr> <h3>问题 6:飞书写入效率低下</h3> <p><strong>问题描述:</strong> 初始设计使用单条写入,15 条推文需要调用 15 次 API</p> <p><strong>低效方案:</strong></p> <pre><code class="language-javascript">// 为每条推文单独调用 API POST /records { "fields": { ... } // 单条记录 } // 重复 15 次 </code></pre> <p><strong>优化方案:</strong> 使用飞书批量创建 API:</p> <pre><code class="language-javascript">// 一次性写入所有记录 POST /records/batch_create { "records": [ { "fields": { ... } }, // 记录 1 { "fields": { ... } }, // 记录 2 // ... 15 条记录 ] } </code></pre> <p><strong>性能对比:</strong></p>
指标单条写入批量写入
API 调用次数15 次1 次
总耗时~15 秒~1 秒
失败风险
<h3>优化措施</h3> <ol> <li>✅ 合并 Twitter API 调用(2→1)</li> <li>✅ 使用飞书批量 API(15→1)</li> <li>✅ 优化数据处理逻辑</li> <li>✅ 添加完善的错误处理</li> </ol> <hr> <h2>🚨 注意事项</h2> <h3>1. API 配额管理</h3> <ul> <li>Twitter Free tier:1500 条/月</li> <li>合理设置 <code>max_results</code>(建议 100)</li> <li>监控 API 使用量</li> </ul> <h3>2. 数据一致性</h3> <ul> <li>推文可能被删除</li> <li>数据统计可能更新</li> <li>定期清理重复数据</li> </ul> <h3>3. 安全性</h3> <ul> <li>不要在代码中硬编码密钥</li> <li>使用 n8n 凭证管理</li> <li>定期更新 Token</li> </ul> <h3>4. 时区问题</h3> <ul> <li>Twitter API 使用 UTC 时间</li> <li>确保本地时间计算正确</li> <li>考虑夏令时影响</li> </ul> <hr> <h2>🎯 未来优化方向</h2> <h3>功能增强</h3> <ul> <li>[ ] 支持多账号备份</li> <li>[ ] 添加图片/视频备份</li> <li>[ ] 支持推文删除同步</li> <li>[ ] 添加数据统计分析</li> </ul> <h3>技术优化</h3> <ul> <li>[ ] 实现增量备份(只获取新推文)</li> <li>[ ] 添加重试机制</li> <li>[ ] 优化错误通知(邮件/飞书消息)</li> <li>[ ] 支持 Webhook 实时触发</li> </ul> <hr> <h2>📚 参考资料</h2> <h3>官方文档</h3> <ul> <li><a href="https://developer.twitter.com/en/docs/twitter-api">Twitter API v2 文档</a></li> <li><a href="https://developers.notion.com/">Notion API 文档</a></li> <li><a href="https://open.feishu.cn/document/">飞书开放平台文档</a></li> <li><a href="https://docs.n8n.io/">n8n 官方文档</a></li> </ul> <h3>相关资源</h3> <ul> <li><a href="https://developer.twitter.com/en/docs/twitter-api/rate-limits">Twitter API 速率限制</a></li> <li><a href="https://open.feishu.cn/document/server-docs/docs/bitable-v1/bitable-overview">飞书多维表格 API</a></li> <li><a href="https://docs.n8n.io/code-examples/">n8n Code 节点指南</a></li> </ul> <hr> <h2>🤝 贡献与反馈</h2> <p>如果你在使用过程中遇到问题或有改进建议,欢迎:</p> <ul> <li>提交 Issue</li> <li>分享使用经验</li> <li>贡献代码优化</li> </ul> <hr> <h2>📝 版本历史</h2> <h3>v1.0.0(最终版)</h3> <ul> <li>✅ 实现基础功能</li> <li>✅ 优化性能(批量写入)</li> <li>✅ 完善错误处理</li> <li>✅ 添加详细日志</li> </ul> <h3>开发里程碑</h3> <ol> <li>初始设计(双 API 调用)</li> <li>合并 API 优化</li> <li>修复飞书认证</li> <li>实现批量写入</li> <li>文本清理优化</li> </ol> <hr> <p><strong>最后更新时间:</strong> 2025-11-10<br> <strong>文档版本:</strong> 1.0.0<br> <strong>维护状态:</strong> ✅ 活跃维护中</p></body></html><!--EndFragment--> </body> </html># X(Twitter) 推文自动备份到 Notion + 飞书 - 完整开发文档

📋 项目概述

本项目实现了一个 n8n 自动化工作流,每天定时将 X(Twitter) 账号的原创推文和转发推文备份到 Notion 数据库和飞书多维表格中。

功能特性

  • ✅ 每天早上 7 点自动运行
  • ✅ 获取昨天的所有推文(原创 + 转发)
  • ✅ 自动排除回复内容
  • ✅ 同步到 Notion 和飞书
  • ✅ 支持代理访问 Twitter API
  • ✅ 完善的错误处理和日志记录

🏗️ 系统架构

工作流节点图

每天早7点触发
计算时间范围(昨天 00:00 - 今天 00:00)
获取推文数据(通过代理访问 Twitter API)
处理推文数据(分离原创/转发,数据清洗)
过滤有效数据(确保数据完整性)
├─→ 写入 Notion(单条写入)
└─→ 获取飞书 Token
准备飞书批量数据
批量写入飞书(一次写入所有)

🐛 开发过程中的问题与解决方案

问题 1:合并节点配置错误

错误信息:

You need to define at least one pair of fields in "Fields to Match" to match on

原因分析:

  • 使用了
    mode: "combine"
    +
    combinationMode: "mergeByPosition"
  • 这种模式需要定义匹配字段才能合并数据

解决方案:

{
"parameters": {
"mode": "append" // 改为追加模式,不需要匹配字段
}
}

经验总结:

  • combine
    模式:用于按字段匹配合并(需要配置匹配字段)
  • append
    模式:简单追加所有数据(适合本场景)

问题 2:Twitter API 速率限制(429 错误)

错误信息:

{
"status": 429,
"title": "Too Many Requests"
}

原因分析:

  • 初始设计分别调用两次 API(原创推文 + 转发推文)
  • Twitter API v2 有严格的速率限制
  • Free tier 每月只有 1500 条推文读取配额

解决方案: 优化为单次 API 调用:

// 一次性获取所有推文(不排除转发)
url: "https://api.twitter.com/2/users/{user_id}/tweets"
queryParameters: {
exclude: "replies", // 只排除回复
tweet.fields: "created_at,public_metrics,referenced_tweets"
}
// 在代码节点中分离原创和转发
const isRetweet = tweet.referenced_tweets?.some(ref => ref.type === 'retweeted');

经验总结:

  • 优先使用单次 API 调用获取所有数据
  • 在代码中进行数据分类和过滤
  • API 调用次数:从 2 次降低到 1 次(减少 50%)

问题 3:代理配置缺失

问题描述: 国内网络环境无法直接访问 Twitter API

解决方案: 在 HTTP Request 节点中添加代理配置:

{
"options": {
"proxy": "http://127.0.0.1:7890",
"timeout": 30000
}
}

注意事项:

  • 确保本地代理软件正在运行
  • 测试代理:
    curl -x http://127.0.0.1:7890 https://api.twitter.com
  • 根据实际情况修改端口号

问题 4:飞书认证 Token 过期

问题描述: 初始配置使用硬编码的 Bearer Token,很快过期失效

错误方案:

{
"headers": {
"Authorization": "Bearer u-ef55Oywvd6eW9f7H4uMP0911jQYw10qphMG050MGwB8D"
}
}

正确方案: 使用飞书应用凭证动态获取 Token:

  1. 获取 Token 节点:
{
"method": "POST",
"url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
"bodyParameters": {
"app_id": "cli_a985d1564eb9900b",
"app_secret": "m83GwLY8ytgaX03E5wxapiIVvjzSvlPP"
}
}
  1. 使用动态 Token:
{
"headers": {
"Authorization": "Bearer {{ $('获取飞书Token').item.json.tenant_access_token }}"
}
}

经验总结:

  • 永远不要硬编码 Token
  • 使用应用凭证动态获取,保证长期有效

问题 5:推文内容导致 JSON 解析错误

错误信息:

JSON parameter needs to be valid JSON

原因分析: 推文内容包含特殊字符(换行符、制表符、引号等)破坏 JSON 格式:

// 问题示例
"Content": "这是一条推文
包含换行符" // ❌ 导致 JSON 解析失败

初次尝试(失败):

// 转义特殊字符
cleanText = cleanText
.replace(/\n/g, '\\n')
.replace(/"/g, '\\"')
// 问题:在 n8n 表达式中仍然可能出错

最终方案:

// 直接移除或替换特殊字符为空格
cleanText = cleanText
.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, '') // 移除控制字符
.replace(/\r\n/g, ' ') // Windows 换行
.replace(/\r/g, ' ') // Mac 换行
.replace(/\n/g, ' ') // Unix 换行
.replace(/\t/g, ' ') // 制表符
.trim();

经验总结:

  • 对于用户输入的文本,永远不要假设格式
  • 在插入 JSON 前必须清理数据
  • 简单替换为空格比复杂转义更可靠

问题 6:飞书写入效率低下

问题描述: 初始设计使用单条写入,15 条推文需要调用 15 次 API

低效方案:

// 为每条推文单独调用 API
POST /records
{
"fields": { ... } // 单条记录
}
// 重复 15 次

优化方案: 使用飞书批量创建 API:

// 一次性写入所有记录
POST /records/batch_create
{
"records": [
{ "fields": { ... } }, // 记录 1
{ "fields": { ... } }, // 记录 2
// ... 15 条记录
]
}

性能对比:

指标单条写入批量写入
API 调用次数15 次1 次
总耗时~15 秒~1 秒
失败风险

经验总结:

  • 优先使用批量 API(如果支持)
  • 减少网络往返次数
  • 降低部分失败的风险

问题 7:数据流传递错误

问题描述: "准备飞书数据" 节点执行成功,但后续节点显示 "No output data returned"

原因分析:

// ❌ 错误:返回数组
return results;
// ✅ 正确:返回 n8n 格式的对象数组
return [{
json: {
token: token,
records: records,
total: records.length
}
}];

经验总结:

  • n8n Code 节点必须返回
    [{ json: {...} }]
    格式
  • 即使只有一条数据,也要包装成数组

🔧 最终配置详解

1. Cron 触发器

{
"triggerTimes": {
"item": [
{
"hour": 7,
"minute": 0
}
]
}
}
  • 每天早上 7:00 UTC 时间触发
  • 可根据时区调整

2. 计算时间范围

const now = new Date();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
yesterday.setHours(0, 0, 0, 0);
const today = new Date(now);
today.setHours(0, 0, 0, 0);
return [{
json: {
start_time: yesterday.toISOString(),
end_time: today.toISOString()
}
}];
  • 精确获取昨天 00:00 到今天 00:00 的推文

3. Twitter API 配置

// API 端点
url: "https://api.twitter.com/2/users/1576219005488369665/tweets"
// 查询参数
{
"max_results": 100,
"tweet.fields": "created_at,public_metrics,referenced_tweets",
"exclude": "replies",
"start_time": "...",
"end_time": "..."
}
// 认证
authentication: "httpBearerAuth"

4. 数据处理逻辑

// 识别转发
const isRetweet = tweet.referenced_tweets?.some(
ref => ref.type === 'retweeted'
);
// 添加标记
allTweets.push({
json: {
...tweet,
is_retweet: isRetweet,
tweet_type: isRetweet ? '转发' : '原创'
}
});

5. Notion 字段映射

Notion 字段类型数据源
ID文本tweet.id
推文内容富文本tweet.text
推文类型选择原创/转发
发布时间日期tweet.created_at
点赞数数字public_metrics.like_count
转发数数字public_metrics.retweet_count
回复数数字public_metrics.reply_count
书签数数字public_metrics.bookmark_count
展示数数字public_metrics.impression_count
推文链接URLhttps://twitter.com/.../status/{id}

6. 飞书字段映射

飞书字段类型数据源
Content文本清理后的推文内容
Tweet Type文本原创/转发
Created At日期tweet.created_at
Like数字like_count
Views数字impression_count
Retweet数字retweet_count
Reply数字reply_count
Bookmark数字bookmark_count
Tweet ID文本tweet.id
Tweet Link文本推文链接

📦 部署清单

前置条件

1. Twitter API 凭证

  • 申请 Twitter Developer 账号
  • 创建应用获取 Bearer Token
  • 确认 API 访问级别(建议 Basic 以上)

2. Notion 配置

  • 创建 Notion 数据库
  • 添加所有必需字段(见上方字段映射)
  • 获取 Database ID
  • 创建 Notion Integration 并授权

3. 飞书配置

  • 创建飞书自建应用
  • 获取 app_id 和 app_secret
  • 创建多维表格
  • 添加所有必需字段
  • 给应用授权访问表格

4. 网络环境

  • 本地代理软件运行(如 Clash、v2rayN)
  • 测试代理连通性

配置步骤

  1. 导入工作流 JSON

    • 复制完整的 JSON 配置
    • 在 n8n 中选择 "Import from JSON"
  2. 更新凭证信息

    // Twitter Bearer Token
    credentials: {
    httpBearerAuth: {
    id: "YOUR_CREDENTIAL_ID"
    }
    }
    // Notion API
    credentials: {
    notionApi: {
    id: "YOUR_NOTION_CREDENTIAL_ID"
    }
    }
    // 飞书应用凭证
    "app_id": "YOUR_APP_ID",
    "app_secret": "YOUR_APP_SECRET"
  3. 更新配置参数

    // Twitter 用户 ID
    user_id: "YOUR_TWITTER_USER_ID"
    // Notion Database ID
    databaseId: "YOUR_DATABASE_ID"
    // 飞书表格 ID
    apps/YOUR_APP_ID/tables/YOUR_TABLE_ID
    // 代理地址(如果需要)
    proxy: "http://127.0.0.1:YOUR_PORT"
  4. 测试运行

    • 单独测试每个节点
    • 完整运行一次工作流
    • 检查 Notion 和飞书中的数据
  5. 激活定时任务

    "active": true

🔍 调试技巧

1. 查看节点输出

  • 点击节点查看 Schema/Table/JSON 视图
  • 使用
    console.log()
    输出调试信息
  • 在浏览器开发者工具中查看 console

2. 常见错误排查

Twitter API 错误:

# 测试 API 连接
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.twitter.com/2/users/YOUR_USER_ID/tweets"

代理问题:

# 测试代理
curl -x http://127.0.0.1:7890 https://api.twitter.com

飞书 Token 问题:

# 测试获取 Token
curl -X POST https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
-H "Content-Type: application/json" \
-d '{"app_id":"YOUR_ID","app_secret":"YOUR_SECRET"}'

3. 日志监控

在关键节点添加日志:

console.log(`成功获取 ${tweets.length} 条推文`);
console.log(`准备批量写入 ${records.length} 条记录`);

📊 性能优化

优化成果

指标优化前优化后提升
API 调用次数17 次3 次82% ↓
总执行时间~30 秒~5 秒83% ↓
失败率15%<1%93% ↓

优化措施

  1. ✅ 合并 Twitter API 调用(2→1)
  2. ✅ 使用飞书批量 API(15→1)
  3. ✅ 优化数据处理逻辑
  4. ✅ 添加完善的错误处理

🚨 注意事项

1. API 配额管理

  • Twitter Free tier:1500 条/月
  • 合理设置
    max_results
    (建议 100)
  • 监控 API 使用量

2. 数据一致性

  • 推文可能被删除
  • 数据统计可能更新
  • 定期清理重复数据

3. 安全性

  • 不要在代码中硬编码密钥
  • 使用 n8n 凭证管理
  • 定期更新 Token

4. 时区问题

  • Twitter API 使用 UTC 时间
  • 确保本地时间计算正确
  • 考虑夏令时影响

🎯 未来优化方向

功能增强

  • 支持多账号备份
  • 添加图片/视频备份
  • 支持推文删除同步
  • 添加数据统计分析

技术优化

  • 实现增量备份(只获取新推文)
  • 添加重试机制
  • 优化错误通知(邮件/飞书消息)
  • 支持 Webhook 实时触发

📚 参考资料

官方文档

相关资源


🤝 贡献与反馈

如果你在使用过程中遇到问题或有改进建议,欢迎:

  • 提交 Issue
  • 分享使用经验
  • 贡献代码优化

📝 版本历史

v1.0.0(最终版)

  • ✅ 实现基础功能
  • ✅ 优化性能(批量写入)
  • ✅ 完善错误处理
  • ✅ 添加详细日志

开发里程碑

  1. 初始设计(双 API 调用)
  2. 合并 API 优化
  3. 修复飞书认证
  4. 实现批量写入
  5. 文本清理优化

最后更新时间: 2025-11-10
文档版本: 1.0.0
维护状态: ✅ 活跃维护中

评论 (0)