Skip to content

处理不同数据类型#

在本章中,您将学习如何使用 n8n 核心节点 处理不同类型的数据。

HTML 和 XML 数据#

您可能对 HTML 和 XML 都很熟悉。

HTML 与 XML 的区别

HTML 是一种标记语言,用于描述网页的结构和语义。XML 看起来与 HTML 相似,但标签名称不同,因为它们描述的是所包含数据的类型。

如果需要在 n8n 工作流中处理 HTML 或 XML 数据,可以使用 HTML 节点XML 节点

使用 HTML 节点 通过引用 CSS 选择器来提取网页的 HTML 内容。这在您想从网站收集结构化信息(网络爬取)时非常有用。

HTML 练习#

让我们获取最新的 n8n 博客文章标题:

  1. 使用 HTTP Request 节点 向 URL https://blog.n8n.io/ 发送 GET 请求(此端点无需认证)。
  2. 连接一个 HTML 节点 并配置它以提取页面上第一篇博客文章的标题。
    • 提示:如果您不熟悉 CSS 选择器或阅读 HTML,可以使用 CSS 选择器 .post .item-title a 来定位!
显示解决方案
  1. 配置 HTTP Request 节点,参数如下:
    • 认证方式:无
    • 请求方法:GET
    • URL:https://blog.n8n.io/ 结果应如下图所示:

HTTP Request 节点的结果
HTTP Request 节点的结果

  1. HTML 节点 连接到 HTTP Request 节点 并配置前者的参数:
    • 操作:提取 HTML 内容
    • 源数据:JSON
    • JSON 属性:data
    • 提取值
      • :title
      • CSS 选择器.post .item-title a
      • 返回值:HTML

您可以添加更多值来提取更多数据。

结果应如下图所示:

HTML 提取节点的结果
HTML 提取节点的结果

使用 XML 节点 在 XML 和 JSON 之间相互转换。当您需要与使用不同格式(XML 或 JSON)的 Web 服务交互并在它们之间获取和提交数据时,此操作非常有用。

XML 练习#

第一章的最终练习中,您使用了 HTTP Request 节点 向 PokéAPI 发起请求。本练习中,我们将再次使用该 API,但会将输出转换为 XML 格式:

  1. 添加一个 HTTP Request 节点,向 PokéAPI 发起相同请求,地址为 https://pokeapi.co/api/v2/pokemon
  2. 使用 XML 节点将 JSON 输出转换为 XML。
显示解决方案
  1. 要从 PokéAPI 获取宝可梦数据,使用 HTTP Request 节点 执行以下参数配置:
    • 认证方式:无
    • 请求方法:GET
    • URL:https://pokeapi.co/api/v2/pokemon
  2. 连接一个 XML 节点 并配置以下参数:
    • 模式:JSON 转 XML
    • 属性名:data

结果应如下图所示:

XML节点表格视图(JSON转XML)
XML 节点(JSON 转 XML)– 表格视图

如需进行反向数据转换,请选择 XML 转 JSON 模式。

日期、时间和间隔数据#

日期和时间数据类型包括 DATETIMEDATETIMETIMESTAMPYEAR。日期和时间可以以不同格式传递,例如:

  • DATE: 2022年3月29日, 29-03-2022, 2022/03/29
  • TIME: 08:30:00, 8:30, 20:30
  • DATETIME: 2022/03/29 08:30:00
  • TIMESTAMP: 1616108400 (Unix时间戳), 1616108400000 (Unix毫秒时间戳)
  • YEAR: 2022, 22

处理日期和时间有几种方法:

有时您可能需要暂停工作流执行。当您知道某个服务不会立即处理数据或返回所有结果较慢时,这很有必要。在这些情况下,您不希望n8n将不完整的数据传递给下一个节点。

如果遇到这种情况,请在需要延迟的节点后使用等待节点等待节点会暂停工作流执行,并在以下情况下恢复执行:

  • 在特定时间
  • 经过指定时间间隔后
  • 收到webhook调用时

日期练习#

构建一个工作流,将之前使用的 Customer Datastore 节点中的输入日期增加五天。然后,如果计算后的日期晚于 1959 年,工作流会等待 1 分钟,再将计算后的日期设置为一个值。该工作流应每 30 分钟触发一次。

开始步骤:

  1. 添加 Customer Datastore (n8n training) 节点,选择 Get All People 操作。返回所有记录。
  2. 添加 Date & Time 节点,将数据存储中的创建日期向上舍入到月末。输出到 new-date 字段。包含所有输入字段。
  3. 添加 If 节点 检查新的舍入日期是否晚于 1960-01-01 00:00:00
  4. 在该节点的 True 输出分支添加 Wait 节点,设置为等待一分钟。
  5. 添加 Edit Fields (Set) 节点,设置一个名为 outputValue 的新字段,其值为包含 new-date 的字符串。包含所有输入字段。
  6. 在工作流开头添加 Schedule Trigger 节点,设置为每 30 分钟触发一次。(可以保留手动触发节点用于测试!)
显示解决方案
  1. 添加 Customer Datastore (n8n training) 节点,选择 Get All People 操作。
    • 选择 Return All 选项。
  2. 添加连接到 Customer Datastore 节点的 Date & Time 节点。选择 Round a Date 操作。
    • created 日期作为要舍入的 Date
    • 选择 Round Up 作为 ModeEnd of Month 作为 To
    • 设置 Output Field Namenew-date
    • Options 中,选择 Add Option 并使用控件 Include Input Fields
  3. 添加连接到 Date & Time 节点If 节点
    • 将 new-date 字段添加为条件的第一部分。
    • 设置比较为 Date &Time > is after
    • 添加 1960-01-01 00:00:00 作为表达式的第二部分。(这应该在 True 分支产生 3 个项目,False 分支产生 2 个项目)
  4. If 节点 的 True 输出分支添加 Wait 节点
    • 设置 ResumeAfter Time interval
    • 设置 Wait Amount1.00
    • 设置 Wait UnitMinutes
  5. Wait 节点 后添加 Edit Fields (Set) 节点
    • 使用 JSON 或 Manual Mapping Mode
    • 设置一个名为 outputValue 的新字段,其值为 new-date 字段的值。
    • 选择 Include Other Input Fields 选项并包含 All 字段。
  6. 在工作流开头添加 Schedule Trigger 节点
    • 设置 Trigger IntervalMinutes
    • 设置 Minutes Between Triggers 为 30。
    • 要测试调度,请确保激活工作流。
    • 确保将此节点连接到最初使用的 Customer Datastore (n8n training) 节点

工作流应如下所示:

日期转换工作流
日期转换工作流

要检查每个节点的配置,您可以复制此工作流的 JSON 代码,将其粘贴到编辑器 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
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": "课程 2, 章节 2, 日期练习",
"nodes": [
	{
	"parameters": {},
	"id": "6bf64d5c-4b00-43cf-8439-3cbf5e5f203b",
	"name": "当点击\"执行工作流\"时",
	"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": {
	"当点击\"执行工作流\"时": {
	"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 文件)该怎么办?这类文件以二进制数字系统表示,因此被视为二进制数据。在这种形式下,二进制数据无法提供有用信息,您需要将其转换为可读格式。

在 n8n 中,您可以使用以下节点处理二进制数据:

文件读写功能仅限自托管版 n8n

n8n 云版本不支持磁盘文件读写操作。读写操作将在安装 n8n 的机器上执行。如果您在 Docker 中运行 n8n,命令将在 n8n 容器内执行而非 Docker 宿主机。Read/Write Files From Disk 节点会相对于 n8n 安装路径查找文件。n8n 建议使用绝对文件路径以避免错误。

要读写二进制文件,您需要在节点的 File(s) Selector 参数(读取操作)或 File Path and Name 参数(写入操作)中填写文件路径(位置)。

正确命名路径

文件路径的表示方式因 n8n 运行方式而异:

  • npm 安装:~/my_file.json
  • n8n 云/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请求获取PDF
通过HTTP请求获取PDF

当你使用 Extract From File 节点 将 PDF 从二进制转换为 JSON 时,结果应该如下所示:

Extract From File节点
Extract From File节点

要检查节点的配置,你可以复制下面的 JSON 工作流代码并粘贴到你的编辑器界面中:

 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 https://poetrydb.org/random/1 发起 HTTP 请求
  2. 使用 Convert to File 节点 将返回的数据从 JSON 转换为二进制
  3. 使用 Read/Write Files From Disk 节点 将新的二进制文件数据写入运行 n8n 的机器
  4. 为了验证操作是否成功,使用 Read/Write Files From Disk 节点 读取生成的二进制文件
显示解决方案

这个练习的工作流如下所示:

将JSON转为二进制数据的工作流
将JSON转为二进制数据的工作流

要查看节点的配置,您可以复制下面的 JSON 工作流代码并粘贴到您的编辑器界面中:

  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
			}
			]
		]
		}
	}
}