处理不同类型的数据#
在本章中,您将学习如何使用 n8n 核心节点 来处理不同类型的数据。
HTML 和 XML 数据#
您可能已经熟悉 HTML 和 XML。
HTML 与 XML HTML 是一种用于描述网页结构和语义的标记语言。XML 看起来与 HTML 相似,但标签名称不同,因为它们描述的是所包含数据的类型。
如果需要在 n8n 工作流中处理 HTML 或 XML 数据,请使用 HTML 节点 或 XML 节点。
使用 HTML 节点 可通过引用 CSS 选择器来提取网页的 HTML 内容。这在需要从网站收集结构化信息时非常有用(即网络爬虫 / web-scraping)。
HTML 练习#
让我们获取最新一篇 n8n 博客文章的标题:
- 使用 HTTP Request 节点 向 URL
https://blog.n8n.io/发起 GET 请求(该端点无需身份验证)。 - 连接一个 HTML 节点,并配置它以提取页面上第一篇博客文章的标题。
- 提示:如果您不熟悉 CSS 选择器或阅读 HTML,CSS 选择器
.post .item-title a应该会有所帮助!
- 提示:如果您不熟悉 CSS 选择器或阅读 HTML,CSS 选择器
显示解决方案
-
配置 HTTP Request 节点,参数如下:
- Authentication(认证) : None(无)
- Request Method(请求方法) : GET
- URL : https://blog.n8n.io/
结果应如下图所示:
HTTP Request 节点的结果HTTP Request 节点的结果
- 将一个 HTML 节点 连接到 HTTP Request 节点,并配置其参数:
- Operation(操作) : Extract HTML Content(提取 HTML 内容)
- Source Data(源数据) : JSON
- JSON Property(JSON 属性) : data
- Extraction Values(提取值) :
- Key(键) : title
- CSS Selector(CSS 选择器) :
.post .item-title a - Return Value(返回值) : HTML
你可以添加更多值以提取更多数据。 结果应如下所示: HTML Extract 节点的结果HTML Extract 节点的结果 使用 XML 节点 将 XML 转换为 JSON,或将 JSON 转换为 XML。当你需要在使用不同格式(XML 或 JSON)的 Web 服务之间获取和提交数据时,此操作非常有用。
XML 练习
在 第一章的最后一个练习 中,你使用了 HTTP Request 节点 向 PokéAPI 发起请求。在这个练习中,我们将再次使用相同的 API,但会将输出转换为 XML 格式:
- 添加一个 HTTP Request 节点,向
https://pokeapi.co/api/v2/pokemon发起相同的请求。 - 使用 XML 节点将 JSON 输出转换为 XML。
显示解决方案
- 要从 PokéAPI 获取宝可梦数据,请使用以下参数执行 HTTP Request 节点:
- 认证(Authentication):无
- 请求方法(Request Method):GET
- URL:https://pokeapi.co/api/v2/pokemon
- 连接一个 XML 节点,并设置以下参数:
- 模式(Mode):JSON to XML
- 属性名称(Property name):data
结果应如下所示: XML 节点(JSON to XML)表格视图XML 节点(JSON to XML)– 表格视图 若要反向转换数据,请选择模式 XML to JSON。
日期、时间和间隔数据
日期和时间数据类型包括 DATE、TIME、DATETIME、TIMESTAMP 和 YEAR。这些日期和时间可以以不同格式传递,例如:
DATE:2022年3月29日、29-03-2022、2022/03/29TIME:08:30:00、8:30、20:30DATETIME:2022/03/29 08:30:00TIMESTAMP:1616108400(Unix 时间戳)、1616108400000(Unix 毫秒时间戳)YEAR:2022、22
有几种方式可以处理日期和时间:
- 使用 Date & Time 节点 将日期时间数据转换为不同格式,或进行日期计算。
- 使用 Schedule Trigger 节点 安排工作流在特定时间、时间间隔或持续时间内运行。
有时,你可能需要暂停工作流的执行。当你知道某个服务不会立即处理数据,或者返回所有结果较慢时,这种情况就显得尤为必要。在这种情况下,你不希望 n8n 将不完整的数据传递给下一个节点。
如果遇到类似情况,请在你想要延迟的节点之后使用 Wait 节点。Wait 节点 会暂停工作流的执行,并在以下情况下恢复执行:
- 在指定时间。
- 经过指定的时间间隔后。
- 收到 webhook 调用时。
日期练习#
构建一个工作流,该工作流从之前使用的 Customer Datastore 节点获取输入日期,并在此基础上增加五天。然后,如果计算出的日期晚于 1959 年,则工作流在将该日期设置为值之前,先等待 1 分钟。此工作流应每 30 分钟触发一次。
开始步骤如下:
- 添加 Customer Datastore (n8n training) 节点,选择 Get All People 操作,并返回全部结果。
- 添加 Date & Time 节点,将 datastore 中的创建日期向上取整到月末(End of Month),并将结果输出到字段
new-date,同时保留所有输入字段。 - 添加 If 节点,检查这个新的取整日期是否晚于
1960-01-01 00:00:00。 - 将 Wait 节点 连接到该节点的 True 输出端,并设置为等待一分钟。
- 添加 Edit Fields (Set) 节点,设置一个名为
outputValue的新字段,其值为包含new-date的字符串,并保留所有输入字段。 - 在工作流开头添加 Schedule Trigger 节点,使其每 30 分钟触发一次。(你可以保留 Manual Trigger 节点 用于测试!)
显示解决方案
-
添加 Customer Datastore (n8n training) 节点,并选择 Get All People 操作。
- 选择 Return All 选项。
-
添加一个连接到 Customer Datastore 节点的 Date & Time 节点,并选择 Round a Date 操作。
- 将
created日期作为要舍入的 Date。 - 选择
Round Up作为 Mode,End of Month作为 To。 - 将 Output Field Name 设置为
new-date。 - 在 Options 中,选择 Add Option,并通过控制项启用 Include Input Fields。
- 将
-
添加一个连接到 Date & Time 节点 的 If 节点。
- 将
new-date字段作为条件的第一部分。 - 将比较方式设置为 Date & Time > is after(日期时间 > 在...之后)。
- 将
1960-01-01 00:00:00作为表达式的第二部分。(这将使 True 分支输出 3 条数据,False 分支输出 2 条数据)
- 将
-
将一个 Wait 节点 连接到 If 节点 的 True 输出端。
- 将 Resume 设置为
After Time interval(等待指定时间间隔后继续)。 - 将 Wait Amount 设置为
1.00。 - 将 Wait Unit 设置为
Minutes(分钟)。
- 将 Resume 设置为
-
将一个 Edit Fields (Set) 节点 连接到 Wait 节点。
- 使用 JSON 或 Manual Mapping Mode(手动映射模式)。
- 设置一个名为
outputValue的新字段,其值等于new-date字段的值。 - 选择 Include Other Input Fields 选项,并包含 All 字段。
-
在工作流的开头添加一个 Schedule Trigger 节点。
- 将 Trigger Interval 设置为使用
Minutes(分钟)。 - 将 Minutes Between Triggers 设置为 30。
- 为了测试你的调度,请确保激活该工作流。
- 确保将此节点连接到你最初创建的 Customer Datastore (n8n training) 节点!
- 将 Trigger Interval 设置为使用
工作流应如下所示: 转换日期的工作流转换日期的工作流 要查看每个节点的配置,你可以复制此工作流的 JSON 代码,直接粘贴到编辑器界面中,或保存为文件后导入到新工作流中。更多信息请参见 导出和导入工作流(Export and import workflows)。
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209| ``` { "name":"Course 2, Ch 2, Date exercise", "nodes":[ { "parameters":{}, "id":"6bf64d5c-4b00-43cf-8439-3cbf5e5f203b", "name":"When clicking "Execute workflow"", "type":"n8n-nodes-base.manualTrigger", "typeVersion":1, "position":[ 620, 280 ] }, { "parameters":{ "operation":"getAllPeople", "returnAll":true }, "id":"a08a8157-99ee-4d50-8fe4-b6d7e16e858e", "name":"Customer Datastore (n8n training)", "type":"n8n-nodes-base.n8nTrainingCustomerDatastore", "typeVersion":1, "position":[ 840, 360 ] }, { "parameters":{ "operation":"roundDate", "date":"={{ $json.created }}", "mode":"roundUp", "outputFieldName":"new-date", "options":{ "includeInputFields":true } }, "id":"f66a4356-2584-44b6-a4e9-1e3b5de53e71", "name":"Date & Time", "type":"n8n-nodes-base.dateTime", "typeVersion":2, "position":[ 1080, 360 ] }, { "parameters":{ "conditions":{ "options":{ "caseSensitive":true, "leftValue":"", "typeValidation":"strict" }, "conditions":[ { "id":"7c82823a-e603-4166-8866-493f643ba354", "leftValue":"={{ $json['new-date'] }}", "rightValue":"1960-01-01T00:00:00", "operator":{ "type":"dateTime", "operation":"after" } } ], "combinator":"and" }, "options":{} }, "id":"cea39877-6183-4ea0-9400-e80523636912", "name":"If", "type":"n8n-nodes-base.if", "typeVersion":2, "position":[ 1280, 360 ] }, { "parameters":{ "amount":1, "unit":"minutes" }, "id":"5aa860b7-c73c-4df0-ad63-215850166f13", "name":"Wait", "type":"n8n-nodes-base.wait", "typeVersion":1.1, "position":[ 1480, 260 ], "webhookId":"be78732e-787d-463e-9210-2c7e8239761e" }, { "parameters":{ "assignments":{ "assignments":[ { "id":"e058832a-2461-4c6d-b584-043ecc036427", "name":"outputValue", "value":"={{ $json['new-date'] }}", "type":"string" } ] }, "includeOtherFields":true, "options":{} }, "id":"be034e9e-3cf1-4264-9d15-b6760ce28f91", "name":"Edit Fields", "type":"n8n-nodes-base.set", "typeVersion":3.3, "position":[ 1700, 260 ] }, { "parameters":{ "rule":{ "interval":[ { "field":"minutes", "minutesInterval":30 } ] } }, "id":"6e8e4308-d0e0-4d0d-bc29-5131b57cf061", "name":"Schedule Trigger", "type":"n8n-nodes-base.scheduleTrigger", "typeVersion":1.1, "position":[ 620, 480 ] } ], "pinData":{}, "connections":{ "When clicking "Execute workflow"":{ "main":[ [ { "node":"Customer Datastore (n8n training)", "type":"main", "index":0 } ] ] }, "Customer Datastore (n8n training)":{ "main":[ [ { "node":"Date & Time", "type":"main", "index":0 } ] ] }, "Date & Time":{ "main":[ [ { "node":"If", "type":"main", "index":0 } ] ] }, "If":{ "main":[ [ { "node":"Wait", "type":"main", "index":0 } ] ] }, "Wait":{ "main":[ [ { "node":"Edit Fields", "type":"main", "index":0 } ] ] }, "Schedule Trigger":{ "main":[ [ { "node":"Customer Datastore (n8n training)", "type":"main", "index":0 } ] ] } } }
---|---
## 二进制数据#
到目前为止,你主要处理的是文本数据。但如果你想要处理非文本的数据(例如图像或 PDF 文件)该怎么办?这类文件以二进制数字系统表示,因此被称为**二进制数据(binary data)**。在这种形式下,二进制数据本身无法提供有用的信息,因此你需要将其转换为可读的形式。
在 n8n 中,你可以使用以下节点来处理二进制数据:
* HTTP Request:从 Web 资源和 API 请求或发送文件。
* Read/Write Files from Disk:从运行 n8n 的机器上读取或写入文件。
* Convert to File:将输入数据输出为文件格式。
* Extract From File:从二进制格式中提取数据并转换为 JSON。
> **仅在自托管的 n8n 上支持读写文件**
> 在 n8n Cloud 上不支持读写磁盘文件。你只能读写安装了 n8n 的机器上的文件。如果你在 Docker 中运行 n8n,命令将在 n8n 容器内执行,而不是 Docker 主机上。**Read/Write Files From Disk** 节点会根据 n8n 的安装路径查找文件。建议使用绝对路径以避免错误。
要读取或写入一个二进制文件,你需要在节点的 `File(s) Selector` 参数中填写文件路径(用于读取操作),或在 `File Path and Name` 参数中填写路径(用于写入操作)。
### 正确命名文件路径
文件路径的具体写法取决于你运行 n8n 的方式:
* npm 方式:`~/my_file.json`
* n8n Cloud / Docker 方式:`/tmp/my_file.json`
### 二进制练习 1#
让我们进行第一个二进制数据练习:将一个 PDF 文件转换为 JSON:
1. 使用 HTTP 请求获取该 PDF 文件:`https://media.kaspersky.com/pdf/Kaspersky_Lab_Whitepaper_Anti_blocker.pdf`。
2. 使用 **Extract From File 节点** 将文件从二进制格式转换为 JSON。显示解决方案
在 HTTP Request 节点 中,你应该能看到获取到的 PDF 文件,如下所示: HTTP Request node to get PDFHTTP Request 节点获取 PDF
当你使用 Extract From File 节点 将 PDF 从二进制转换为 JSON 格式时,结果应如下图所示: Extract From File nodeExtract From File 节点
要查看节点的配置,你可以复制下面的 JSON 工作流代码,并粘贴到你的编辑器界面(Editor UI)中:
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| ``` { "name":"Binary to JSON", "nodes":[ { "parameters":{}, "id":"78639a25-b69a-4b9c-84e0-69e045bed1a3", "name":"When clicking "Execute Workflow"", "type":"n8n-nodes-base.manualTrigger", "typeVersion":1, "position":[ 480, 520 ] }, { "parameters":{ "url":"https://media.kaspersky.com/pdf/Kaspersky_Lab_Whitepaper_Anti_blocker.pdf", "options":{} }, "id":"a11310df-1287-4e9a-b993-baa6bd4265a6", "name":"HTTP Request", "type":"n8n-nodes-base.httpRequest", "typeVersion":4.1, "position":[ 700, 520 ] }, { "parameters":{ "operation":"pdf", "options":{} }, "id":"88697b6b-fb02-4c3d-a715-750d60413e9f", "name":"Extract From File", "type":"n8n-nodes-base.extractFromFile", "typeVersion":1, "position":[ 920, 520 ] } ], "pinData":{}, "connections":{ "When clicking "Execute Workflow"":{ "main":[ [ { "node":"HTTP Request", "type":"main", "index":0 } ] ] }, "HTTP Request":{ "main":[ [ { "node":"Extract From File", "type":"main", "index":0 } ] ] } } }
---|---
### 二进制练习 2#
在第二个二进制练习中,我们来将一些 JSON 数据转换为二进制格式:
1. 向 Poetry DB API 发起一个 HTTP 请求:`https://poetrydb.org/random/1`。
2. 使用 **Convert to File 节点** 将返回的数据从 JSON 格式转换为二进制。
3. 使用 **Read/Write Files From Disk 节点** 将生成的二进制文件写入运行 n8n 的机器本地磁盘。
4. 为了验证操作是否成功,再次使用 **Read/Write Files From Disk 节点** 读取刚刚生成的二进制文件。
显示解决方案
本练习的工作流程如下所示:
[将 JSON 转换为二进制数据的工作流程](https://docs.n8n.io/_images/courses/level-two/chapter-two/exercise_binarydata.png)_将 JSON 转换为二进制数据的工作流程_
要查看节点的配置,你可以复制下面的 JSON 工作流代码,并将其粘贴到你的编辑器界面(Editor UI)中: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
| ```
{
"name":"JSON to file and Read-Write",
"nodes":[
{
"parameters":{},
"id":"78639a25-b69a-4b9c-84e0-69e045bed1a3",
"name":"When clicking \"Execute Workflow\"",
"type":"n8n-nodes-base.manualTrigger",
"typeVersion":1,
"position":[
480,
520
]
},
{
"parameters":{
"url":"https://poetrydb.org/random/1",
"options":{}
},
"id":"a11310df-1287-4e9a-b993-baa6bd4265a6",
"name":"HTTP Request",
"type":"n8n-nodes-base.httpRequest",
"typeVersion":4.1,
"position":[
680,
520
]
},
{
"parameters":{
"operation":"toJson",
"options":{}
},
"id":"06be18f6-f193-48e2-a8d9-35f4779d8324",
"name":"Convert to File",
"type":"n8n-nodes-base.convertToFile",
"typeVersion":1,
"position":[
880,
520
]
},
{
"parameters":{
"operation":"write",
"fileName":"/tmp/poetrydb.json",
"options":{}
},
"id":"f2048e5d-fa8f-4708-b15a-d07de359f2e5",
"name":"Read/Write Files from Disk",
"type":"n8n-nodes-base.readWriteFile",
"typeVersion":1,
"position":[
1080,
520
]
},
{
"parameters":{
"fileSelector":"={{ $json.fileName }}",
"options":{}
},
"id":"d630906c-09d4-49f4-ba14-416c0f4de1c8",
"name":"Read/Write Files from Disk1",
"type":"n8n-nodes-base.readWriteFile",
"typeVersion":1,
"position":[
1280,
520
]
}
],
"pinData":{},
"connections":{
"When clicking \"Execute Workflow\"":{
"main":[
[
{
"node":"HTTP Request",
"type":"main",
"index":0
}
]
]
},
"HTTP Request":{
"main":[
[
{
"node":"Convert to File",
"type":"main",
"index":0
}
]
]
},
"Convert to File":{
"main":[
[
{
"node":"Read/Write Files from Disk",
"type":"main",
"index":0
}
]
]
},
"Read/Write Files from Disk":{
"main":[
[
{
"node":"Read/Write Files from Disk1",
"type":"main",
"index":0
}
]
]
}
}
}
---|---