【经验】n8n的部署与使用

n8n(发音为“n-eight-n”)是一款开源的、可扩展的工作流自动化工具,其名称灵感来源于“无限循环”(∞ 符号与 n8 的形似),强调自动化流程的灵活性和无限可能性。它通过可视化节点(Node) 连接不同应用程序和服务,构建复杂的自动化流程,支持从简单的数据同步到跨系统的企业级自动化场景。

Docker部署n8n

创建/usr/n8n/目录并开放权限,若想映射其它目录可自行调整。

1
2
3
sudo mkdir -p /usr/n8n
sudo chown -R 1000:1000 /usr/n8n
sudo chmod -R 755 /usr/n8n

拉取最新n8n版本(镜像源配置参考其他文章)

1
docker pull n8nio/n8n:latest

创建n8n应用容器

1
2
3
4
5
6
7
8
9
10
docker run -d \
--name n8n \
-p 5678:5678 \
-v /usr/n8n:/home/node/.n8n \
-e N8N_BASIC_AUTH_ACTIVE=true \
-e N8N_BASIC_AUTH_USER=admin \
-e N8N_BASIC_AUTH_PASSWORD=your_secure_password_here \
-e N8N_ENCRYPTION_KEY=your_encryption_key_here \
-e N8N_SECURE_COOKIE=false \
n8nio/n8n:1.121.1

-e N8N_SECURE_COOKIE=false \ 禁用安全证书

n8nio/n8n:1.121.1 如果是最新版本,不需要携带版本号

完成上述步骤后,docker ps查看是否成功运行,若未成功运行,使用docker logs n8n查看报错信息。

最后,访问http://your-server-ip:5678可进入

汉化

(强烈不建议使用汉化,可能会有各种奇奇怪怪的问题,如果要使用,一定做好版本匹配)

  1. 从项目的 Releases 页面 (https://github.com/other-blowsnow/n8n-i18n-chinese/releases) 下载与你的 n8n 版本相对应的 editor-ui.tar.gz 文件。
  2. 替换 n8n 安装目录中原有的 n8n-editor-ui/dist 目录。
  3. 设置环境变量 N8N_DEFAULT_LOCALE=zh-CN
  4. 重启 n8n 服务。

对于使用 Docker 的朋友,可以通过路径映射(volume mapping)的方式来实现:

1
2
3
4
5
6
7
8
docker run -it --rm \
--name n8n-chinese \
-p 5678:5678 \
-v /path/to/your/downloaded/dist:/usr/local/lib/node_modules/n8n/node_modules/n8n-editor-ui/dist \
-v ~/.n8n:/home/node/.n8n \
-e N8N_DEFAULT_LOCALE=zh-CN \
-e N8N_SECURE_COOKIE=false \
n8nio/n8n

注意: 请将命令中的 /path/to/your/downloaded/dist 替换为你解压后 dist 文件夹的实际路径。

使用

n8n允许你在工作流中直接插入代码节点(如Function节点),这本质上是FaaS模式的微缩版。

如下图是一个获取百度热榜信息的Demo,由4个节点组成。

  1. 触发 ← Webhook接收外部HTTP请求
  2. 获取 → HTTP Request抓取百度热榜页面
  3. 处理 → JavaScript代码解析和清洗数据
  4. 响应 → 返回格式化后的JSON数据

数据流:外部请求 → Webhook → HTTP请求 → JavaScript处理 → JSON响应 → 返回调用方。

由Webhook接受API Get请求,触发热榜爬取,最后以处理后的Json格式返回。

JavaScript处理代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// 完善版:正确提取百度热榜URL
const response = $input.first().json;

let htmlContent = '';

// 从不同可能的响应结构中提取HTML内容
if (typeof response === 'string') {
htmlContent = response;
} else if (response.body) {
htmlContent = response.body;
} else if (response.data) {
htmlContent = response.data;
} else {
htmlContent = JSON.stringify(response);
}

if (!htmlContent || htmlContent.length < 100) {
throw new Error('没有获取到有效的HTML内容');
}

console.log('开始解析热榜数据...');

try {
let hotList = [];

// 使用HTML解析提取URL
if (hotList.length === 0 || hotList.some(item => !item.url)) {
console.log('使用HTML解析补充URL信息');

// 匹配每个热榜条目的完整块
const itemBlockRegex = /<div class="category-wrap_iQLoo[^>]*>([\s\S]*?)<\/div>\s*<\/div>/g;

// 匹配标题和URL的模式
const titleUrlRegex = /<a[^>]*href="([^"]*)"[^>]*class="[^"]*title_dIF3B[^"]*"[^>]*>[\s\S]*?<div class="c-single-text-ellipsis">([^<]*)<\/div>/g;

// 匹配热度的模式
const hotScoreRegex = /<div class="hot-index_1Bl1a">([^<]*)<\/div>/g;

let itemBlockMatch;
const itemsFromHTML = [];

// 首先收集所有热度值
const hotScores = [];
let hotScoreMatch;
while ((hotScoreMatch = hotScoreRegex.exec(htmlContent)) !== null) {
hotScores.push(hotScoreMatch[1].trim());
}

// 然后收集所有标题和URL
let titleUrlMatch;
while ((titleUrlMatch = titleUrlRegex.exec(htmlContent)) !== null) {
itemsFromHTML.push({
url: titleUrlMatch[1],
title: titleUrlMatch[2].trim()
});
}

// 合并数据:将标题URL和热度值配对
const minLength = Math.min(itemsFromHTML.length, hotScores.length);
for (let i = 0; i < minLength; i++) {
// 检查是否已经在hotList中存在(避免重复)
const existingIndex = hotList.findIndex(item =>
item.title === itemsFromHTML[i].title ||
item.word === itemsFromHTML[i].title
);

if (existingIndex >= 0) {
// 如果已存在,补充URL信息
if (!hotList[existingIndex].url) {
hotList[existingIndex].url = itemsFromHTML[i].url;
}
} else {
// 如果不存在,添加新条目
hotList.push({
word: itemsFromHTML[i].title,
title: itemsFromHTML[i].title,
hotScore: hotScores[i],
url: itemsFromHTML[i].url
});
}
}
}

console.log(`最终提取到 ${hotList.length} 条热榜数据`);

// 处理数据格式,确保URL完整
const processedList = hotList.map((item, index) => {
let finalUrl = item.url || item.link || '';

// 确保URL是完整的百度搜索链接
if (finalUrl && !finalUrl.startsWith('http')) {
finalUrl = `https://www.baidu.com${finalUrl}`;
}

// 处理热度值,转换为数字
let hotScoreValue = 0;
if (item.hotScore) {
const scoreText = item.hotScore.toString();
if (scoreText.includes('万')) {
hotScoreValue = parseInt(scoreText.replace('万', '')) * 10000;
} else {
hotScoreValue = parseInt(scoreText) || 0;
}
}

return {
rank: index + 1,
title: item.word || item.title || '未知标题',
hotScore: hotScoreValue,
hotScoreDisplay: item.hotScore || '0',
url: finalUrl,
timestamp: new Date().toISOString()
};
}).filter(item =>
item.title &&
item.title !== '未知标题' &&
item.title.length > 2
);

// 按热度排序
processedList.sort((a, b) => b.hotScore - a.hotScore);

// 重新分配排名
const rankedData = processedList.map((item, index) => ({
...item,
rank: index + 1
}));

console.log('最终返回数据示例:', JSON.stringify(rankedData.slice(0, 3), null, 2));

return rankedData.slice(0, 20); // 限制返回前20条

} catch (error) {
console.error('解析过程中出错:', error);
throw new Error(`处理热榜数据失败: ${error.message}`);
}

总结

由此可见,n8n是一个十分高效灵活的自动化工具,其自身的架构和其节点的设计都体现了微服务和模块化的思想,合理运用可以极大提升工作效率。且如今n8n已经对AI进行了深度适配,真不错。