본문 바로가기
dev

n8n 웹 크롤링 자동화

by wlrn566 2026. 3. 24.

사이드 프로젝트를 할때나 어떤 생각에 의한 개발 프로젝트를 시작할 때, 항상 힘들었던 것이 레퍼런스 데이터들이다.

개발을 할 때 힘들진 않지만? 성가셨던 작업이 더미 데이터를 수집하는 것이었다.

항상 이러한 데이터를 수집하기 위해 수작업으로 제품 리스트를 나타내는 페이지 등을 참조하면서 수작업으로 진행했다.

시간도 오래 걸리기도 하고,  데이터 일관성이 떨어지기에 이런 작업들을 자동화로 처리하면 어떨까?

 

진행할 프로세스는 아래와 같다.

트리거 -> 웹 HTML 추출 -> 필요한 데이터 추출 -> 데이터 정제 -> 엑셀로 다운

 


n8n

간단하게 말하자면, 워크플로우 자동화 도구 이다.

노드(Node)라고 부르는 블록들을 선으로 연결하기만 하면 복잡한 작업 흐름이 뚝딱 만들어진다.

  • 노드로 그리는 로직: 어떠한 트리거(이벤트 또는 스케줄)를 통해, 데이터를 긁어온 다음(HTTP Request), DB에 저장해(Database) 같은 과정을 코딩 없이 시각적으로 설계할 수 있다.
  • 자유로운 확장성: 기본 노드로 부족하면 직접 JavaScript 코드를 작성해서 넣을 수 있다. 즉, 직접 코드를 짜서 진행할 수도 있다.
  • 도커 사용: Docker로 로컬 서버에 올려서 쓸 수 있어서 데이터 보안이나 비용 면에서 아주 자유롭다. 이를 Self-Hosting 이라고 한다.

ComfyUI 라고 n8n과 비슷하게 노드를 연결해서 사용하는 프로그램도 있다.

하지만 ComfyUI와 n8n은 목적이 완전 다르다

 

ComfyUI vs n8n ?

comfyUI는 이미지 또는 비디오를 생성하는 (Stable Diffusion) 위주로 사용된다. 즉, GPU를 사용한 생성형 인공지능 AI 로직을 프롬프트 + 노드연결을 사용해서 만들어내는 작업을 위한 것이다.

n8n은 업무용으로 사용되는 것이 더 크다. 특정 시간에 어떠한 업무를 시작하는 것, 여러 서비스들을 연결해서 작업하는 것. 이러한 비즈니스 로직을 짜는데 많이 사용된다.

 

이 둘을 함께 사용하기도 하는데, n8n의 트리거를 이용해서 comfyUI의 이미지 생성을 작업하고, 이를 n8n에 연결된 여러 서비스에 배포하는 식으로 많이 사용하기도 한다!

 


 

n8n은 도커로 실행하면 정말 간단하다.

왜 도커를 이용해서 직접 호스팅을 해야하는 이유는 다음과 같다.

  • n8n 클라우드를 사용하면 이메일 계정당 14일의 무료 기간이 있다. -> 유료임
  • n8n을 Self-Hosting(로컬로 직접 실행)을 하면 무료다. -> 완전 무료

그래서 도커에서 n8n을 지원하기에, 도커를 이용해서 셀프 호스팅을 하는 것이 제일 간단하다.

 

도커로  n8n 실행

간단하게 아래 docker-compose 코드를 사용하면 n8n을 사용할 수 있다.

version: "3.8"

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - GENERIC_TIMEZONE=Asia/Seoul
      - TZ=Asia/Seoul
      - N8N_DEFAULT_LOCALE=ko
      - N8N_RUNNERS_DISABLED=false
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false
      - EXECUTIONS_DATA_SAVE_ON_ERROR=all
      - N8N_ALLOWED_FILESYSTEMS=/files
    volumes:
      - n8n_data:/home/node/.n8n
      - ./n8n:/files  # 로컬 파일 공유 폴더 (엑셀 출력 등에 활용)

volumes:
  n8n_data:

 

n8n을 사용할 때는 몇가지 중요한 환경 설정이 있다. 이는 도커 컨테이너를 재실행 하거나, 로컬 볼륨을 이용해서 동기화 시키는데 중요하다.

 

GENERIC_TIMEZONE=Asia/Seoul : n8n 내부 시간대 설정. 스케줄 트리거가 한국 시간 기준으로 실행되게 함

TZ=Asia/Seoul : 컨테이너 OS 자체의 시간대 설정. 로그 시간 등이 한국 시간으로 표시되게 함

N8N_DEFAULT_LOCALE=ko : n8n UI 언어 한국어

N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false : n8n이 설정 파일 권한을 강제로 체크 비활성화 user: root로 실행할 때 권한 경고 무시용

EXECUTIONS_DATA_SAVE_ON_ERROR=all : 실행 오류 발생 시 로그 저장

N8N_ALLOWED_FILESYSTEMS=/files : n8n이 파일 읽기/쓰기를 허용하는 경로를 지정해요. /files에 쓰기작업을 허용


1. 접속

지정한 포트를 이용해 접속이 가능하다.

http://localhost:5678/

 


2. 트리거 설정

  • 이제 작업의 첫번째 노드인 트리거를 설정한다.
  • 스케줄을 이용하거나 여러 트리거가 있지만, 테스트를 위해 manually를 연결해 준다.


3. HTTP 추출

  • Core > HTTP Request
  • Method는 GET
  • 인증이 필요하다면 Authentication을 추가한다.
  • Header에 User-Agent, Cookie등 필요한 값들을 추가할 수 있다.

크롤링할 URL을 입력


4. HTTP 내용에서 데이터 추출

  • Data transformation > HTML > Extract HTML Content
  • Key : 해당 결과 데이터의 필드명
  • Css Selector : 요소 선택자. class명을 적어주면 좋다. ex) h2.ttl
  • Return Array : 요소가 여러개라면 무조건 체크해주기 (왠만하면 체크)
  • 해당 페이지의 개발자 도구 > 콘솔 document.querySelector('h2.ttl').innerText로 값을 먼저 확인하는 것도 좋다.
  • 한 요소에서 2개 이상의 값을 추출해야하는 경우 Add Value를 이용해 추가한다면, 순서가 보장되지 않을 수도 있다. 이 경우, 부모 요소를 추출한 다음, 이후 노드에서 처리하면 짝을 이룰 수 있다.

div > list_item 이라는 class를 가진 태그를 추출


5. JavaScript 코드 적용

  • 가장 중요한 작업이자 최대 장점
  • 이전 노드의 결과값을 이용해 직접 코드를 작성해서 데이터를 만질 수 있다.
  • 여기서는 추출된 HTML 코드에서 이미지, 브랜드, 제품명, 제품코드를 다시 추출하는 작업이다.
  • 이전 노드에서 HTML 자체로 데이터를 추출했기에 해당 노드에서 직접 코드를 작성해서 정제한다.
  • Extract HTML Content에서 Text를 사용해서 값이 이미 나왔다면, 코드를 굳이 쓸 필요는 없다!
    하지만, 한 요소에서 2가지 이상을 추출하려고 한다면, 순서가 보장되지 않기에 코드 작업이 필수가 될 것이다.
const results = [];
const items = $input.all();

for (const item of items) {
  const htmlArray = item.json.data;
  
  for (const html of htmlArray) {
    const imgMatch = html.match(/src="(https:\/\/m2img\.lxzin\.com[^"]+)"/);
    
    const brandMatches = [...html.matchAll(/class="brand"[^>]*>\s*([^\s<][^<]*?)\s*<\/small>/g)];
    const nameMatch = html.match(/class="seo-h6 ttl"[^>]*>([^<]+)</);
    const codeMatch = html.match(/class="code text_line1_cut"[^>]*>\s*([^\s<]+)\s*</);
    
    // 이미지
    const img = imgMatch ? imgMatch[1] : '';
    // 브랜드1
    const brand1 = brandMatches[0] ? brandMatches[0][1].trim() : '';
    // 브랜드2
    const brand2 = brandMatches[1] ? brandMatches[1][1].trim() : '';
    // 제품명
    const name = nameMatch ? nameMatch[1].trim() : '';
    // 제품코드
    const code = codeMatch ? codeMatch[1].trim() : '';
    
    if (name && code) {
      results.push({ 
        json: { img, brand1, brand2, name, code } 
      });
    }
  }
}

return results;


6. Google Sheet를 이용해 해당 데이터를 엑셀로 내보낸다.

  • 처음에는 직접 엑셀파일로 만들어서 로컬 볼륨에 저장하는 노드를 만들었다.
  • 하지만, 여러 AI 툴들이 구글 계정 + 구글 스프레드 시트를 지원하고 있기에 작업물을 하나의 플랫폼으로 통일하면 좋다는 생각에 n8n에서도 강력하게 지원하고 있는 구글 스프레드 시트를 이용하기로 했다.
  • 직접 엑셀 파일을 이용한 다운로드 방식은 제일 마지막에 추가한다.

6-1. Google Cloud Console 설정

  • 구글 시트 연동을 위해 구글 클라우드 콘솔 설정이 필요하다.

6-2. Google Sheets API 활성화

6-3.  Oauth 클라이언트 생성

  • 승인된 리디렉션 URI -> n8n의 SpreadSheet의 설정에서 Oauth Redirect URL을 넣어주면 된다.
  • 사전에 Create spreadsheet 라는 노드를 연결해줘야 한다.

6-4. 데이터 액세스 업데이트

  • 구글 스프레드 시트 관련 범위를 추가해준다.

6-5. 테스트 사용자 추가

  • 해당 앱을 테스트하기 위한 이메일 계정을 추가한다.
  • 이 이메일은 n8n에서 구글 로그인 인증 때와 동일한 이메일이어야 한다.

6-6. 클라이언트 ID, 비밀번호 확인

  • 이제 Oauth 클라이언트 ID와 Secrets 비밀번호를 확인해야 한다.
  • 해당 정보는 JSON 파일을 다운로드 해서 파일 내부 내용에 기재되어 있다.
  • JSON 파일의 client_id, client_secret 키의 값이다.

6-7. Create spreadsheet 노드 구글 계정 연동

  • 노드를 연결하고 노드 설정을 한다.
  • Client ID, Client Secret은 JSON파일에서 확인할 수 있다.
  • 구글 Sign In 이메일 인증을 진행한다.

 



6-8. Create spreadsheet 노드 설정

  • Resource : Sheet Within Document
  • Operation : Append or Update Row (알맞은 것 선택하면 됨)
  • Document : By ID
    • 해당 파일 URL의 ID값 : d/ ~ /edit 사이의 문자열이다.
    • 해당 파일의 시트이름
      Sheet : By Name

 


최종 노드 구성

데이터 추출 결과


  • 트리거를 스케줄로 변경하면 특정 시각마다 해당 사이트를 크롤링해서 구글 계정 스프레드시트로 확인할 수 있다.
  • JS렌더링으로 데이터가 표시되는 사이트인 경우 HTTP Request의 결과에 원하는 데이터가 없을 수도 있음 정적 사이트에만 데이터를 바로 뽑을 수 있다.

이를 위한 해결 방법으로는 2가지 정도가 있을 것이다.

  1. 브라우저 렌더링 시 데이터를 호출하는 API를 직접 확인한다.
    개발자 도구 > 네트워크 탭 > 페이지가 렌더링 될 때 호출되는 여러 API를 확인해서 찾으면 된다.
  2. Puppeteer를 설치해서 사용한다.
    기존 크롤링과 동일하게 Puppeteer를 사용하면 JS 렌더링 이후의 데이터를 추출할 수 있다.

로컬 엑셀 파일로 만드는 방법

Convert to XLSX + Write files from disk

  • 자바스크립트로 정리한 데이터를 엑셀파일로 만든다.
  • {{ $now.format(’yyyy-MM-dd’) }} 변수를 이용하면 현재 일자로 저장할 수 있다.
  • 이 방법은 도커 내에서 로컬PC의 디렉토리 권한 이슈가 있기에 구글 연동이 더 간단하다.