Memo:用 n8n 搭建高尔夫新闻自动抓取 + AI 改写 + WordPress 草稿发布流水线
起因
我有一个高尔夫网站 golforfun.net,想让它每天自动产出一些新闻内容。VPS 上已经跑着 n8n,正好可以用它搭一条自动化流水线。
目标:
- 每天自动抓取高尔夫新闻
- 用 AI 改写成中文文章
- 自动配图
- 创建 WordPress 草稿(人工审核后再发布)
整体架构
text
Schedule Trigger(每天定时)
↓
RSS Read(抓取高尔夫新闻)
↓
Limit(限制数量)
↓
Code(清洗 RSS 内容)
↓
Code(组装请求体)
↓
HTTP Request(调 One API → Kimi K3 改写)
↓
Code(拆分标题正文 + 提取图片 URL)
↓
HTTP Request(下载图片)
↓
HTTP Request(上传到 WordPress 媒体库)
↓
WordPress(创建草稿,带特色图片)
节点配置
节点 1:Schedule Trigger
- Trigger Interval:
Days - Days Between Triggers:
1 - Trigger at Hour:
9
节点 2:RSS Read
- URL:
https://golf.com/feed/
Golf.com 的 RSS 里包含 enclosure.url 字段,就是文章的特色图片。这是后续配图的关键。
节点 3:Limit
- Max Items:
3
节点 4:Code(清洗 RSS 内容)
RSS 抓到的内容里经常有换行符、引号,直接插入 JSON 会破坏格式。这个节点负责清洗:
javascript
const items = $input.all();
return items.map(item => {
const title = (item.json.title || '').replace(/[\n\r\t]/g, ' ').trim();
const content = (item.json.contentSnippet || item.json.content || '')
.replace(/[\n\r\t]/g, ' ')
.replace(/"/g, '\\"')
.trim();
return {
json: {
cleanTitle: title,
cleanContent: content.slice(0, 2000)
}
};
});
节点 5:Code(组装请求体)
关键点:不要在 HTTP Request 节点里手写 JSON。用 Code 节点组装对象,让 n8n 自动序列化,避免转义问题。
javascript
const item = $input.first().json;
const prompt = `请根据以下新闻,用中文写一篇高尔夫资讯文章。
严格要求:
1. 必须忠实于原始新闻内容,只能使用原文提供的事实
2. 禁止添加原文没有的人物、赛事、时间、数据
3. 如果原文信息不足,就写短文,不要编造
4. 第一行输出标题(不要加引号、星号或 Markdown 标记)
5. 空一行后输出正文,200-400字
6. 只输出文章内容,不要任何解释
原始标题:${item.cleanTitle}
原始内容:${item.cleanContent}`;
return [{
json: {
body: {
model: "moonshotai/kimi-k3",
messages: [{ role: "user", content: prompt }],
max_tokens: 4096,
stream: false
}
}
}];
节点 6:HTTP Request(调 LLM)
- Method:
POST - URL:
http://172.17.0.1:3000/v1/chat/completions - Headers:
Authorization:Bearer sk-你的OneAPI令牌Content-Type:application/json
- Send Body: 开启
- Body Content Type:
JSON - Specify Body:
Using JSON - JSON:
{{ $json.body }} - Options → Timeout:
600000
节点 7:Code(拆分标题正文 + 提取图片 URL)
javascript
const input = $input.first().json;
const text = input.choices[0].message.content
.replace(/\\n/g, '\n')
.replace(/\*\*/g, '')
.replace(/^#+\s*/gm, '');
const lines = text.split('\n').map(l => l.trim()).filter(l => l);
const title = lines[0].replace(/^["'"'""'']|["'"'""'']$/g, '').trim();
const content = lines.slice(1).join('\n\n').trim();
const rssItem = $('RSS Read').item.json;
const imageUrl = rssItem.enclosure?.url || '';
return [{ json: { title, content, imageUrl } }];
节点 8:HTTP Request(下载图片)
- Method:
GET - URL:
{{ $json.imageUrl }} - Options → Response → Response Format:
File - Options → Response → Put Output in Field:
data
节点 9:HTTP Request(上传到 WordPress 媒体库)
- Method:
POST - URL:
https://golforfun.net/wp-json/wp/v2/media - Authentication:
Generic Credential Type→Basic Auth- User: WordPress 用户名
- Password: 应用密码
- Send Body: 开启
- Body Content Type:
n8n Binary File - Input Data Field Name:
data - Send Headers:
Content-Disposition:attachment; filename="featured.webp"Content-Type:image/webp
返回的 id 就是 Media ID。
节点 10:WordPress(创建草稿)
- Credential: WordPress 凭据
- Resource:
Post - Operation:
Create - Title:
{{ $('Code').item.json.title }} - Content:
{{ $('Code').item.json.content }} - Status:
draft - Additional Fields → Featured Media:
{{ $json.id }}
踩过的坑
坑 1:模型选择
最初用 mistralai/mistral-nemotron,中文创作质量差,还会编造人物和年份(把 Carlota Ciganda 写成 Linnéa Ström,把 2023 年写成 2022 年)。
换成 moonshotai/kimi-k3 后,中文流畅、事实准确、不编造。这是关键。
坑 2:JSON Body 控制字符错误
在 HTTP Request 节点里手写 JSON 时,如果 prompt 里有真实换行符,会报:
text
Bad control character in string literal in JSON
解决:用 Code 节点组装对象,HTTP Request 里只填 {{ $json.body }}。
坑 3:messages 被当成字符串
最初用 “Using Fields Below” 模式,messages 数组被 n8n 当成字符串发出,报:
text
json: cannot unmarshal string into Go struct field ... messages of type []model.Message
解决:改用 “Using JSON” 模式,配合 Code 节点组装。
坑 4:节点位置放错
「拆分标题正文」的 Code 节点必须放在 HTTP Request 之后,因为它依赖 LLM 的返回(choices[0].message.content)。如果放在 Limit 之后,会报:
text
Cannot read properties of undefined (reading '0')
坑 5:单独执行 Code 节点报错
n8n 里单独执行某个 Code 节点时,不会自动执行它前面的节点,所以上游数据是空的。
解决:点画布右上角的 Execute Workflow 跑整条链,或从上游节点开始执行。
坑 6:RSS 只有摘要
Golf.com 的 RSS 只提供一句话摘要,LLM 只能基于这一句话写文章,内容空洞。
当前状态:接受这个限制,生成短资讯。后续可以加全文抓取节点优化。
坑 7:WordPress 应用密码
自托管 WordPress 必须用 Application Password(基础认证),不能用 OAuth2。OAuth2 只适用于 WordPress.com 托管的站点。
在 WordPress 后台 → 用户 → 个人资料 → 应用密码,生成一个专用密码。
当前状态
| 环节 | 状态 |
|---|---|
| RSS 抓取 | ✅ Golf.com feed |
| 内容清洗 | ✅ |
| LLM 改写 | ✅ Kimi K3 |
| 图片提取 | ✅ RSS enclosure |
| 图片下载 + 上传 | ✅ |
| WordPress 草稿 | ✅ 带特色图片 |
待优化
- □ 全文抓取:RSS 只有摘要,加 HTTP Request 抓文章详情页
- □ 去重:检查标题是否已存在,避免重复
- □ 加分类和标签:在 WordPress 节点里自动设置
- □ 多源聚合:加多个 RSS 源,每天产出更多内容
- □ 自动发布:确认质量稳定后,把
draft改成publish - □ 错误通知:如果某天抓取或 LLM 失败,发 Telegram 通知
关键文件位置
| 项目 | 位置 |
|---|---|
| n8n | http://162.43.92.249:5678 |
| One API | http://172.17.0.1:3000 |
| WordPress | https://golforfun.net |
| Kimi K3 模型 | moonshotai/kimi-k3 |
一句话总结
n8n 定时触发 → RSS 抓新闻 → Code 清洗 → Kimi K3 改写 → 提取图片 → 上传媒体库 → WordPress 草稿。 每天自动产出 3 篇草稿,人工审核后发布。
