다양한 데이터 유형 처리하기
이 챕터에서는 n8n 코어 노드를 사용하여 다양한 유형의 데이터를 처리하는 방법을 배웁니다. HTML과 XML은 아마 익숙하실 것입니다. HTML은 웹 페이지의 구조와 의미를 설명하는 마크업 언어입니다. n8n 워크플로에서 HTML 또는 XML 데이터를 처리해야 한다면 HTML 노드 또는 XML 노드를 사용하세요.
이 챕터에서는 n8n 코어 노드를 사용하여 다양한 유형의 데이터를 처리하는 방법을 배웁니다.
HTML 및 XML 데이터#
HTML과 XML은 아마 익숙하실 것입니다.
HTML은 웹 페이지의 구조와 의미를 설명하는 마크업 언어입니다. XML은 HTML과 비슷해 보이지만, 태그 이름이 다르며 보유하는 데이터의 종류를 설명합니다.
n8n 워크플로에서 HTML 또는 XML 데이터를 처리해야 한다면 HTML 노드 또는 XML 노드를 사용하세요.
HTML 노드를 사용하면 CSS 선택자를 참조하여 웹 페이지의 HTML 콘텐츠를 추출할 수 있습니다. 이는 웹사이트에서 구조화된 정보를 수집하려는 경우(웹 스크래핑)에 유용합니다.
HTML 연습 문제#
최신 n8n 블로그 포스트의 제목을 가져와 봅시다:
- HTTP Request 노드를 사용하여 URL
https://blog.n8n.io/에 GET 요청을 보냅니다(이 엔드포인트는 인증이 필요하지 않습니다). - HTML 노드를 연결하고 페이지의 첫 번째 블로그 포스트 제목을 추출하도록 설정합니다.
- 힌트: CSS 선택자나 HTML 읽기에 익숙하지 않다면 CSS 선택자
.post .item-title a가 도움이 됩니다!
- 힌트: CSS 선택자나 HTML 읽기에 익숙하지 않다면 CSS 선택자
정답 보기
1. HTTP Request 노드를 다음 파라미터로 설정하세요:
- **Authentication**: None
- **Request Method**: GET
- **URL**: https://blog.n8n.io/
결과는 다음과 같이 보여야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_html_httprequestnode.png" alt="Result of HTTP Request node" style="width:100%"><figcaption align = "center"><i>HTTP Request 노드 결과</i></figcaption></figure>
2. **HTML 노드**를 **HTTP Request 노드**에 연결하고 파라미터를 설정하세요:
- **Operation**: Extract HTML Content
- **Source Data**: JSON
- **JSON Property**: data
- **Extraction Values**:
- **Key**: title
- **CSS Selector**: `.post .item-title a`
- **Return Value**: HTML
더 많은 데이터를 추출하려면 값을 추가할 수 있습니다.
결과는 다음과 같이 보여야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_html_htmlextractnode.png" alt="Result of HTML Extract node" style="width:100%"><figcaption align = "center"><i>HTML Extract 노드 결과</i></figcaption></figure>
XML 노드를 사용하면 XML을 JSON으로, JSON을 XML로 변환할 수 있습니다. 이 작업은 XML 또는 JSON을 사용하는 다양한 웹 서비스와 함께 작업하여 두 형식 간에 데이터를 가져오고 제출해야 할 때 유용합니다.
XML 연습 문제#
챕터 1의 마지막 연습 문제에서 HTTP Request 노드를 사용하여 PokéAPI에 요청했습니다. 이 연습에서는 동일한 API로 돌아가지만 출력을 XML로 변환합니다:
https://pokeapi.co/api/v2/pokemon의 PokéAPI에 동일한 요청을 보내는 HTTP Request 노드를 추가합니다.- XML 노드를 사용하여 JSON 출력을 XML로 변환합니다.
정답 보기
1. PokéAPI에서 포켓몬을 가져오려면 다음 파라미터로 **HTTP Request 노드**를 실행하세요:
- **Authentication**: None
- **Request Method**: GET
- **URL**: https://pokeapi.co/api/v2/pokemon
2. 다음 파라미터로 **XML 노드**를 연결하세요:
- **Mode**: JSON to XML
- **Property name**: data
결과는 다음과 같이 보여야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_html_xmlnode_table.png" alt="Table view of XML Node (JSON to XML)" style="width:100%"><figcaption align = "center"><i>XML 노드 (JSON to XML) - 테이블 뷰</i></figcaption></figure>
반대 방향으로 데이터를 변환하려면 **XML to JSON** 모드를 선택하세요.
날짜, 시간 및 간격 데이터#
날짜와 시간 데이터 유형에는 DATE, TIME, DATETIME, TIMESTAMP, YEAR가 포함됩니다. 날짜와 시간은 다양한 형식으로 전달될 수 있습니다. 예를 들면:
DATE: March 29 2022, 29-03-2022, 2022/03/29TIME: 08:30:00, 8:30, 20:30DATETIME: 2022/03/29 08:30:00TIMESTAMP: 1616108400 (Unix 타임스탬프), 1616108400000 (Unix ms 타임스탬프)YEAR: 2022, 22
날짜와 시간을 처리하는 몇 가지 방법이 있습니다:
- Date & Time 노드를 사용하여 날짜와 시간 데이터를 다른 형식으로 변환하고 날짜를 계산합니다.
- Schedule Trigger 노드를 사용하여 특정 시간, 간격 또는 기간에 워크플로를 실행하도록 예약합니다.
때로는 워크플로 실행을 일시 중지해야 할 수 있습니다. 서비스가 데이터를 즉시 처리하지 않거나 모든 결과를 반환하는 데 느릴 수 있다는 것을 알 경우에 필요합니다. 이 경우 n8n이 불완전한 데이터를 다음 노드로 전달하는 것을 원하지 않습니다.
이런 상황이 발생하면 지연하려는 노드 뒤에 Wait 노드를 사용하세요. Wait 노드는 워크플로 실행을 일시 중지하고 다음 경우에 실행을 재개합니다:
- 특정 시간에.
- 지정된 시간 간격 후에.
- 웹훅 호출 시.
날짜 연습 문제#
이전에 사용한 Customer Datastore 노드의 입력 날짜에 5일을 더하는 워크플로를 구축하세요. 그런 다음 계산된 날짜가 1959년 이후에 발생했다면 워크플로는 1분 기다린 후 계산된 날짜를 값으로 설정합니다. 워크플로는 30분마다 실행되어야 합니다.
시작하려면:
- Customer Datastore (n8n training) 노드를 추가하고 Get All People 액션을 선택합니다. Return All을 선택합니다.
- Date & Time 노드를 추가하여 데이터스토어의 생성 날짜를 월말로 올림(Round Up)합니다. 이를 new-date 필드로 출력합니다. 모든 입력 필드를 포함합니다.
- If 노드를 추가하여 새로 올림된 날짜가
1960-01-01 00:00:00이후인지 확인합니다. - 해당 노드의 True 출력에 Wait 노드를 추가하고 1분 기다리도록 설정합니다.
- Edit Fields (Set) 노드를 추가하여 new-date를 포함하는 String으로 outputValue라는 새 필드를 설정합니다. 모든 입력 필드를 포함합니다.
- 워크플로 시작 부분에 Schedule Trigger 노드를 추가하여 30분마다 트리거합니다. (테스트를 위해 Manual Trigger 노드를 유지할 수 있습니다!)
정답 보기
1. **Customer Datastore (n8n training) 노드**를 추가하고 **Get All People** 액션을 선택합니다.
- **Return All** 옵션을 선택합니다.
2. Customer Datastore 노드에 연결된 **Date & Time 노드**를 추가합니다. **Round a Date** 옵션을 선택합니다.
- `created` 날짜를 반올림할 **Date**로 추가합니다.
- **Mode**로 `Round Up`을 선택하고 **To**로 `End of Month`를 선택합니다.
- **Output Field Name**을 `new-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 노드**를 추가합니다.
- **Resume**을 `After Time interval`로 설정합니다.
- **Wait Amount**를 `1.00`으로 설정합니다.
- **Wait Unit**을 `Minutes`로 설정합니다.
5. **Wait 노드**에 **Edit Fields (Set) 노드**를 추가합니다.
- JSON 또는 Manual Mapping **Mode** 중 하나를 사용합니다.
- new-date 필드의 값이 되도록 `outputValue`라는 새 필드를 설정합니다.
- **Include Other Input Fields** 옵션을 선택하고 **All** 필드를 포함합니다.
6. 워크플로 시작 부분에 **Schedule Trigger 노드**를 추가합니다.
- **Trigger Interval**을 `Minutes`로 설정합니다.
- **Minutes Between Triggers**를 30으로 설정합니다.
- 예약을 테스트하려면 워크플로를 게시해야 합니다.
- 이 노드를 처음 시작한 **Customer Datastore (n8n training) 노드**에 연결해야 합니다!
워크플로는 다음과 같이 보여야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_datetime.png" alt="Workflow for transforming dates" style="width:100%"><figcaption align = "center"><i>날짜 변환을 위한 워크플로</i></figcaption></figure>
각 노드의 설정을 확인하려면 이 워크플로의 JSON 코드를 복사하여 Editor UI에 붙여넣거나 파일로 저장한 후 새 워크플로에 파일로 가져올 수 있습니다. 자세한 내용은 [워크플로 내보내기 및 가져오기](/workflows/export-import.md)를 참조하세요.
```json
{
"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 파일과 같이 텍스트가 아닌 데이터를 처리하고 싶다면 어떻게 할까요? 이러한 유형의 파일은 이진 수 체계로 표현되므로 바이너리 데이터로 간주됩니다. 이 형태에서 바이너리 데이터는 유용한 정보를 제공하지 않으므로 읽을 수 있는 형태로 변환해야 합니다.
n8n에서는 다음 노드들로 바이너리 데이터를 처리할 수 있습니다:
- HTTP Request: 웹 리소스 및 API에서/로 파일을 요청하고 전송합니다.
- Read/Write Files from Disk: n8n이 실행 중인 머신에서/로 파일을 읽고 씁니다.
- Convert to File: 입력 데이터를 가져와 파일로 출력합니다.
- Extract From File: 바이너리 형식에서 데이터를 가져와 JSON으로 변환합니다.
디스크에서 파일을 읽고 쓰는 것은 n8n Cloud에서는 사용할 수 없습니다. n8n이 설치된 머신에서 읽고 씁니다. Docker에서 n8n을 실행하는 경우, 명령은 Docker 호스트가 아닌 n8n 컨테이너에서 실행됩니다. Read/Write Files From Disk 노드는 n8n 설치 경로에 상대적인 위치에서 파일을 찾습니다. n8n은 오류를 방지하기 위해 절대 파일 경로를 사용할 것을 권장합니다.
바이너리 파일을 읽거나 쓰려면 노드의 File(s) Selector 파라미터(읽기 작업의 경우) 또는 노드의 File Path and Name 파라미터(쓰기 작업의 경우)에 파일의 경로(위치)를 입력해야 합니다.
파일 경로는 n8n을 실행하는 방식에 따라 약간 다르게 보입니다:
- npm:
~/my_file.json - n8n cloud / Docker:
/tmp/my_file.json
바이너리 연습 문제 1#
첫 번째 바이너리 연습으로 PDF 파일을 JSON으로 변환해 봅시다:
- 이 PDF 파일을 가져오기 위한 HTTP 요청을 보냅니다:
https://media.kaspersky.com/pdf/Kaspersky_Lab_Whitepaper_Anti_blocker.pdf. - Extract From File 노드를 사용하여 파일을 바이너리에서 JSON으로 변환합니다.
정답 보기
**HTTP Request 노드**에서 다음과 같이 PDF 파일을 볼 수 있어야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_binarydata_httprequest_file.png" alt="HTTP Request node to get PDF" style="width:100%"><figcaption align = "center"><i>PDF를 가져오는 HTTP Request 노드</i></figcaption></figure>
**Extract From File 노드**를 사용하여 PDF를 바이너리에서 JSON으로 변환하면 결과는 다음과 같이 보여야 합니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_binarydata_movedata_btoj.png" alt="Extract From File node" style="width:100%"><figcaption align = "center"><i>Extract From File 노드</i></figcaption></figure>
노드 설정을 확인하려면 아래 JSON 워크플로 코드를 복사하여 Editor UI에 붙여넣을 수 있습니다:
```json
{
"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 데이터를 바이너리로 변환해 봅시다:
- Poetry DB API
https://poetrydb.org/random/1에 HTTP 요청을 보냅니다. - Convert to File 노드를 사용하여 반환된 데이터를 JSON에서 바이너리로 변환합니다.
- Read/Write Files From Disk 노드를 사용하여 새 바이너리 파일 데이터를 n8n이 실행 중인 머신에 씁니다.
- 제대로 작동했는지 확인하려면 Read/Write Files From Disk 노드를 사용하여 생성된 바이너리 파일을 읽습니다.
정답 보기
이 연습의 워크플로는 다음과 같이 보입니다:
<figure><img src="/images/docs/n8n/_images/courses/level-two/chapter-two/exercise_binarydata.png" alt="Workflow for moving JSON to binary data" style="width:100%"><figcaption align = "center"><i>JSON에서 바이너리 데이터로 이동하는 워크플로</i></figcaption></figure>
노드 설정을 확인하려면 아래 JSON 워크플로 코드를 복사하여 Editor UI에 붙여넣을 수 있습니다:
```json
{
"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
}
]
]
}
}
}
```
