본문 바로가기
  • AI 시대에 적응하는 현대인을 위한 지식 공간
  • AI를 위한 데이터를 과학으로 역어본다
AI 활용

n8n에서 동적 웹페이지를 크롤링하는 방법 : curl, Headless 브라우저 설치

by 피크나인 2025. 12. 20.

n8n에서 동적 웹페이지를 크롤링하는 방법: curl 및 헤드리스 브라우저 설치를 위한 가이드

핵심 키워드: n8n 크롤링, 동적 웹페이지 스크래핑, JavaScript 렌더링, 헤드리스 브라우저, Puppeteer, curl, 워크플로우 자동화



1. 왜 일반적인 방법 (HTTP Request node)으로는 안 될까요?

웹 크롤링을 처음 시도하는 분들이 가장 많이 겪는 좌절감 중 하나는 "분명히 브라우저에서는 보이는데, 코드로 가져오면 빈 페이지가 나온다"는 것입니다. 이런 현상이 발생하는 이유는 현대 웹사이트의 대부분이 동적 웹페이지로 만들어져 있기 때문입니다. 쿠팡, 네이버, 인스타그램 같은 서비스들은 처음에 빈 껍데기 HTML만 보내주고, 실제 콘텐츠는 JavaScript가 실행되면서 나중에 채워지는 방식으로 동작합니다. 이 글에서는 n8n을 사용하여 이러한 동적 웹페이지를 효과적으로 크롤링하는 다양한 방법을 소개하고, 상황에 맞는 최적의 선택을 할 수 있도록 안내해 드리겠습니다.


2. 정적 웹페이지 vs 동적 웹페이지: 무엇이 다른가요?

웹페이지 크롤링을 이해하려면 먼저 정적 웹페이지와 동적 웹페이지의 차이를 알아야 합니다. 정적 웹페이지는 서버에서 완성된 HTML 문서를 그대로 보내주는 방식입니다. 마치 이미 인쇄된 책을 받아보는 것과 같아서, 받은 그대로 내용을 읽을 수 있습니다. 반면 동적 웹페이지는 서버에서 기본 틀만 보내주고, 브라우저에서 JavaScript가 실행되면서 내용이 채워지는 방식입니다. 빈 액자를 받아서 직접 그림을 그려 넣어야 하는 것과 비슷합니다.

구분 정적 웹페이지 동적 웹페이지
콘텐츠 로딩 서버에서 완성된 HTML 전송 JavaScript 실행 후 콘텐츠 생성
크롤링 난이도 쉬움 어려움
대표 사이트 위키피디아, 정부 사이트 쿠팡, 네이버, SNS
필요한 도구 HTTP Request, curl 헤드리스 브라우저

 

대부분의 현대 웹사이트는 동적 웹페이지 방식을 사용합니다. 이는 사용자 경험을 향상시키고 서버 부하를 줄이기 위한 것이지만, 크롤링을 시도하는 개발자들에게는 추가적인 도전 과제가 됩니다. 특히 쇼핑몰의 상품 리뷰, SNS 피드, 실시간 데이터 등은 거의 대부분 JavaScript로 로딩되기 때문에 특별한 접근 방법이 필요합니다.


3. 방법 1  |  HTTP Request 노드 (가장 간단하지만 제한적)

n8n에서 웹 데이터를 가져오는 가장 기본적인 방법은 HTTP Request 노드를 사용하는 것입니다. 이 노드는 웹 브라우저가 서버에 요청을 보내는 것과 동일한 방식으로 동작합니다. 설정이 매우 간단하고 별도의 추가 구성이 필요 없다는 장점이 있습니다. n8n 워크플로우에서 노드를 추가하고 URL만 입력하면 바로 사용할 수 있습니다.

 

하지만 HTTP Request 노드는 JavaScript를 실행하지 못한다는 근본적인 한계가 있습니다. 서버에서 보내주는 초기 HTML만 받아올 수 있기 때문에, 동적으로 로딩되는 콘텐츠는 가져올 수 없습니다. 따라서 이 방법은 정적 웹페이지나 API 엔드포인트를 호출할 때만 효과적입니다. 만약 대상 웹사이트가 내부적으로 JSON API를 사용한다면, 브라우저 개발자 도구에서 해당 API 주소를 찾아 직접 호출하는 방식으로 우회할 수 있습니다.

HTTP Request 노드 설정 예시

아래는 쿠팡 리뷰 API를 호출하는 HTTP Request 노드 설정 예시입니다.

브라우저 개발자 도구에서 Network 탭을 확인하면 이러한 내부 API 엔드포인트를 찾을 수 있습니다.

설정 항목
Method GET
URL https://www.coupang.com/next-api/review


Query Parameters
(Add Parameter 클릭하여 추가):

productId: 8096844330
page: 1
size: 10
sortBy: ORDER_SCORE_ASC
ratingSummary: true

 

Headers (Add Header 클릭하여 추가):

accept: application/json, text/plain, */*
accept-language: ko-KR,ko;q=0.9,en;q=0.8
referer: https://www.coupang.com/vp/products/8096844330
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36

적합한 사용 사례

HTTP Request 노드는 공개 API를 호출하거나, RSS 피드를 가져오거나, 정적 HTML 페이지를 스크래핑할 때 적합합니다. 또한 웹사이트가 내부적으로 사용하는 JSON API 엔드포인트를 직접 호출할 때도 유용합니다. 브라우저 개발자 도구의 Network 탭에서 XHR/Fetch 요청을 확인하면 이러한 숨겨진 API를 찾을 수 있습니다.


4. 방법 2  |  Execute Command 노드 + curl (중급)

HTTP Request 노드보다 더 세밀한 제어가 필요할 때는 Execute Command 노드에서 curl 명령어를 사용할 수 있습니다. curl은 명령줄에서 HTTP 요청을 보내는 강력한 도구로, 복잡한 헤더 설정이나 쿠키 관리가 가능합니다. 브라우저 개발자 도구 > Network > Fetch/XHR 필터를 적용하면, 하단에 나타나는 적합한 API (이 예제에서는 'review?productID=...')를 선택하고, 마우스 우클릭후 나타나는 컨텍스트 메뉴에서 "Copy as cURL" 기능(MacOS에서는 해당 URL을 직접 실행할 수 있도록 curl()로 쌓여있음)을 사용하면 실제 브라우저가 보내는 것과 동일한 요청을 복사할 수 있습니다.

 

이 방법의 장점은 브라우저에서 성공한 요청을 그대로 재현할 수 있다는 것입니다. 특히 로그인이 필요한 사이트에서 세션 쿠키를 포함한 요청을 보낼 때 유용합니다. 하지만 curl도 HTTP Request 노드와 마찬가지로 JavaScript를 실행하지 못하기 때문에, 진정한 의미의 동적 페이지 크롤링은 불가능합니다. 다만 웹사이트가 내부적으로 사용하는 API를 직접 호출할 때는 매우 효과적입니다.

Docker 환경에서 curl 사용하기

n8n을 Docker로 실행하는 경우, 기본 이미지에 curl이 포함되어 있지 않습니다. 이 문제를 해결하는 방법은 세 가지가 있으며, 각각의 장단점이 있습니다. 상황에 맞는 방법을 선택하시기 바랍니다.

방법 2-1: 컨테이너 내부에 직접 설치 (가장 간단)

가장 빠르고 간단한 방법은 실행 중인 컨테이너에 root 권한으로 접속하여 curl을 설치하는 것입니다. 별도의 설정 파일 수정이 필요 없고, 명령어 한 줄로 바로 사용할 수 있습니다. 테스트 목적이나 빠른 확인이 필요할 때 적합합니다.

# 컨테이너 이름 확인
docker ps --format "table {{.Names}}\t{{.Image}}"

# curl 설치 (n8n 컨테이너에 직접)
docker exec -u root -it [컨테이너이름] /bin/sh -c "apk update && apk add --no-cache curl"

## curl 설치 실행결과 (n8n-worker 컨테이너)
## n8n Queue mode에서는 실제 동작되는 컨테이너는 'n8n-worker' 컨테이너임
$ docker exec -u root -it n8n-worker /bin/sh -c "apk update && apk add --no-cache curl"

fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/community/aarch64/APKINDEX.tar.gz
v3.22.2-308-gfeaeb3000e3 [https://dl-cdn.alpinelinux.org/alpine/v3.22/main]
v3.22.2-307-g4886c13aeed [https://dl-cdn.alpinelinux.org/alpine/v3.22/community]
OK: 26167 distinct packages available
fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/community/aarch64/APKINDEX.tar.gz
(1/1) Installing curl (8.14.1-r2)
Executing busybox-1.37.0-r20.trigger
OK: 59 MiB in 66 packages

# 설치 확인
docker exec [컨테이너이름] curl --version

$ docker exec n8n-worker curl --version
curl 8.14.1 (aarch64-alpine-linux-musl) libcurl/8.14.1 OpenSSL/3.5.4 zlib/1.3.1 \
brotli/1.1.0 zstd/1.5.7 c-ares/1.34.5 libidn2/2.3.7 libpsl/0.21.5 nghttp2/1.65.0
Release-Date: 2025-06-04
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt \
pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IDN IPv6 Largefile libz \
NTLM PSL SSL threadsafe TLS-SRP UnixSockets zstd

 

  • 장점: 즉시 사용 가능하며, 기존 설정을 전혀 변경할 필요가 없습니다.
  • 단점: 컨테이너가 재시작되거나 docker-compose down && up을 실행하면 curl이 사라집니다. n8n 업데이트 시에도 다시 설치해야 합니다.

자동 설치 스크립트

매번 수동으로 설치하기 번거로우시다면, 아래 스크립트를 저장해두고 필요할 때 실행하시면 됩니다. 이 스크립트는 n8n-queue-stack의 모든 n8n 관련 컨테이너를 자동으로 찾아서 curl을 설치합니다.

#!/bin/bash

# ============================================================
# n8n 컨테이너에 curl 설치 스크립트
# 용도: n8n-queue-stack 컨테이너에 curl을 설치합니다
# ============================================================

# 색상 정의
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# n8n-queue-stack 디렉토리
N8N_DIR="$HOME/docker/n8n-queue-stack"

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}  n8n 컨테이너 curl 설치 스크립트${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""

# 1. 디렉토리 확인
echo -e "${YELLOW}[1/5] n8n-queue-stack 디렉토리 확인 중...${NC}"
if [ ! -d "$N8N_DIR" ]; then
    echo -e "${RED}오류: $N8N_DIR 디렉토리가 존재하지 않습니다.${NC}"
    echo -e "${YELLOW}디렉토리 경로를 확인해 주세요.${NC}"
    exit 1
fi
echo -e "${GREEN}✓ 디렉토리 확인 완료: $N8N_DIR${NC}"
echo ""

# 2. 실행 중인 n8n 컨테이너 찾기
echo -e "${YELLOW}[2/5] 실행 중인 n8n 컨테이너 검색 중...${NC}"
cd "$N8N_DIR"

# docker-compose로 실행된 컨테이너 목록 확인
CONTAINERS=$(docker compose ps --format "table {{.Name}}\t{{.Status}}" 2>/dev/null || docker-compose ps --format "table {{.Name}}\t{{.Status}}" 2>/dev/null)

if [ -z "$CONTAINERS" ]; then
    echo -e "${RED}오류: 실행 중인 컨테이너가 없습니다.${NC}"
    echo -e "${YELLOW}먼저 docker compose up -d 를 실행해 주세요.${NC}"
    exit 1
fi

echo -e "${GREEN}실행 중인 컨테이너 목록:${NC}"
echo "$CONTAINERS"
echo ""

# n8n 관련 컨테이너 찾기 (n8n, worker, webhook 등)
N8N_CONTAINERS=$(docker compose ps --format "{{.Name}}" 2>/dev/null | grep -E "(n8n|worker|webhook)" || docker-compose ps --format "{{.Name}}" 2>/dev/null | grep -E "(n8n|worker|webhook)")

if [ -z "$N8N_CONTAINERS" ]; then
    echo -e "${RED}오류: n8n 관련 컨테이너를 찾을 수 없습니다.${NC}"
    exit 1
fi

echo -e "${GREEN}✓ n8n 컨테이너 발견:${NC}"
echo "$N8N_CONTAINERS"
echo ""

# 3. 각 n8n 컨테이너에 curl 설치
echo -e "${YELLOW}[3/5] curl 설치 시작...${NC}"
echo ""

INSTALL_COUNT=0
FAIL_COUNT=0

for CONTAINER in $N8N_CONTAINERS; do
    echo -e "${BLUE}--------------------------------------${NC}"
    echo -e "${BLUE}컨테이너: $CONTAINER${NC}"
    echo -e "${BLUE}--------------------------------------${NC}"
    
    # curl이 이미 설치되어 있는지 확인
    if docker exec "$CONTAINER" which curl > /dev/null 2>&1; then
        echo -e "${GREEN}✓ curl이 이미 설치되어 있습니다.${NC}"
        CURL_VERSION=$(docker exec "$CONTAINER" curl --version | head -n 1)
        echo -e "  버전: $CURL_VERSION"
        ((INSTALL_COUNT++))
    else
        echo -e "${YELLOW}curl 설치 중...${NC}"
        
        # root 권한으로 curl 설치
        if docker exec -u root "$CONTAINER" /bin/sh -c "apk update && apk add --no-cache curl" 2>&1; then
            echo -e "${GREEN}✓ curl 설치 완료${NC}"
            CURL_VERSION=$(docker exec "$CONTAINER" curl --version | head -n 1)
            echo -e "  버전: $CURL_VERSION"
            ((INSTALL_COUNT++))
        else
            echo -e "${RED}✗ curl 설치 실패${NC}"
            ((FAIL_COUNT++))
        fi
    fi
    echo ""
done

# 4. 설치 결과 확인
echo -e "${YELLOW}[4/5] 설치 결과 확인...${NC}"
echo ""

for CONTAINER in $N8N_CONTAINERS; do
    if docker exec "$CONTAINER" curl --version > /dev/null 2>&1; then
        echo -e "${GREEN}✓ $CONTAINER: curl 사용 가능${NC}"
    else
        echo -e "${RED}✗ $CONTAINER: curl 사용 불가${NC}"
    fi
done
echo ""

# 5. 완료 메시지
echo -e "${YELLOW}[5/5] 완료${NC}"
echo ""
echo -e "${BLUE}========================================${NC}"
echo -e "${GREEN}  설치 완료: $INSTALL_COUNT 개 컨테이너${NC}"
if [ $FAIL_COUNT -gt 0 ]; then
    echo -e "${RED}  설치 실패: $FAIL_COUNT 개 컨테이너${NC}"
fi
echo -e "${BLUE}========================================${NC}"
echo ""

# 주의사항 안내
echo -e "${YELLOW} 주의사항:${NC}"
echo -e "  - 컨테이너가 재시작되면 curl이 사라집니다."
echo -e "  - docker compose down/up 후에는 이 스크립트를 다시 실행하세요."
echo ""

 

스크립트 사용 방법:

./install-curl.sh 스크립트를 실행하면 n8n-xxx로 실행되는 모든 컨텐이너를 찾아 curl을 설치합니다. 물론 Docker를 재실행하면 설치되었던 모든 curl관련 기능은 사라집니다. 다시 curl을 사용하려면 ./install-curl.sh을 재실행해서 curl을 설치해야 합니다.

# 1. 스크립트 저장
nano ~/docker/n8n-queue-stack/install-curl.sh

# 2. 위 내용 붙여넣기 후 저장 (Ctrl+O, Enter, Ctrl+X)

# 3. 실행 권한 부여
chmod +x ~/docker/n8n-queue-stack/install-curl.sh

# 4. 실행
cd ~/docker/n8n-queue-stack
./install-curl.sh

 

 

방법 2-2: 커스텀 Docker 이미지 빌드 (영구적)

컨테이너를 재시작해도 curl이 유지되도록 하려면 커스텀 Docker 이미지를 만들어야 합니다. n8n 공식 이미지를 기반으로 curl을 추가 설치한 새로운 이미지를 빌드하는 방식입니다. 한 번 설정해두면 컨테이너 재시작, 재생성과 관계없이 항상 curl을 사용할 수 있습니다.

 

Dockerfile이란?

Dockerfile은 Docker 이미지를 만들기 위한 레시피 파일입니다. 요리 레시피에 재료와 조리 순서가 적혀 있듯이, Dockerfile에는 어떤 기본 이미지에서 시작하고, 어떤 프로그램을 설치하고, 어떤 설정을 적용할지가 순서대로 적혀 있습니다. Docker는 이 파일을 읽고 지시사항을 하나씩 실행하여 새로운 이미지를 만들어냅니다.

 

1단계: 작업 폴더 생성 및 Dockerfile 작성

# 작업 폴더 생성
mkdir ~/n8n-custom
cd ~/n8n-custom

# Dockerfile 생성
cat > Dockerfile << 'EOF'
# 1. 기본 재료: n8n 공식 이미지에서 시작
FROM n8nio/n8n:latest

# 2. 요리사 변경: 설치를 위해 잠시 관리자 권한 획득
USER root

# 3. 재료 추가: curl 설치 (apk는 Alpine Linux의 패키지 관리자)
RUN apk add --no-cache curl

# 4. 요리사 복귀: 보안을 위해 일반 사용자로 돌아감
USER node
EOF

 

각 줄의 의미를 설명드리면:

명령어 의미
FROM n8nio/n8n:latest n8n 공식 이미지를 기본으로 사용하겠다
USER root 관리자 권한으로 전환하겠다 (설치를 위해 필요)
RUN apk add --no-cache curl curl 프로그램을 설치하겠다
USER node 다시 일반 사용자로 돌아가겠다 (보안상 중요)

 

컨테이너와 동일한 곳에 Dockerfile을 생성하는 것을 추천합니다!!

컨테이너와 동일한 곳에 Dockerfile을 생성하는 것을 추천합니다.

docker-compose.yml이 있는 컨테이너와 동일한 디렉토에동일한 디렉토리에서 작업하는 것이 가장 관리하기 편하고 표준적인 방식입니다. 이유와 구체적인 설정 방법은 다음과 같습니다.

1. 왜 같은 디렉토리가 좋은가요?
상대 경로 사용 가능: docker-compose.yml에서 Dockerfile의 위치를 지정할 때 ./Dockerfile처럼 간단하게 참조할 수 있습니다.
- 프로젝트 통합 관리: n8n 관련 데이터(데이터베이스, 볼륨 설정 등)와 이미지 빌드 파일을 한곳에 모아두면 백업과 관리가 용이합니다.
- 빌드 컨텍스트(Build Context): Docker 빌드 시 현재 디렉토리의 파일들을 컨테이너로 복사하기 쉬워집니다.

2. 추천하는 디렉토리 구조
my-n8n-project/
├── docker-compose.yml
├── Dockerfile          <-- 여기에 생성
└── n8n_data/           (볼륨 데이터 등)​

3. docker-compose.yml 설정 방법
Dockerfile을 같은 디렉토리에 두었다면, docker-compose.yml 파일을 아래와 같이 수정하여 자동 빌드되도록 설정할 수 있습니다.
# docker-compose.yml

services:
  n8n:
    # image: docker.n8n.io/n8nio/n8n  <-- 기존 이미지 줄을 주석 처리하거나 삭제
    build: .                          # 현재 디렉토리(.)의 Dockerfile을 사용하여 빌드
    container_name: n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=localhost
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:​

4. 실행 방법
파일 준비가 완료되었다면 터미널에서 다음 명령어를 입력하세요.
docker-compose up -d --build

# '--build' 옵션은 Dockerfile의 변경 사항을 감지하여 이미지를 새로 만들도록 강제합니다.

5. 주의사항 (.dockerignore)
만약 같은 디렉토리에 용량이 큰 로그 파일이나 백업 데이터 폴더가 있다면, 빌드 속도가 느려질 수 있습니다. 이 경우 동일 위치에 .dockerignore 파일을 만들고 제외할 폴더명을 적어주면 빌드 속도가 빨라집니다. (예: n8n_data/ 추가)
결론적으로, 같은 디렉토리에서 작업하는 것이 Docker Compose의 기능을 100% 활용하는 방법입니다. Docker Compose Build 참조를 통해 더 자세한 옵션을 확인할 수 있습니다.

6. n8n 버전 업데이트 방식
Dockerfile의 첫 줄(FROM) 설정에 따라 동작이 달라집니다.
FROM docker.n8n.io/n8nio/n8n:latest 로 설정한 경우 : docker-compose up -d --build 명령어를 실행할 때, 로컬에 이미 latest 이미지가 있다면 그것을 기반으로 빌드합니다.진짜 최신 버전으로 업데이트하고 싶다면, 빌드 전에 docker pull docker.n8n.io/n8nio/n8n:latest를 먼저 실행하여 베이스 이미지를 갱신해야 합니다.

7. curl 업데이트 방식
RUN apk add --no-cache curl 설정을 사용하면:이미지를 빌드할 때마다 Alpine 리눅스 저장소에서 그 시점의 최신 curl 버전을 가져와 설치합니다. --no-cache 옵션 덕분에 이전 빌드에 남은 찌꺼기 파일 없이 깔끔하게 설치됩니다.

 

2단계: 이미지 빌드

# 이미지 빌드 (n8n-with-curl이라는 이름으로)
docker build -t n8n-with-curl .

# 빌드 확인
docker images | grep n8n-with-curl

 

3단계: docker-compose.yml 수정

기존에 사용하시던 docker-compose.yml 파일에서 이미지 이름만 변경하면 됩니다.

# 변경 전
services:
  n8n:
    image: n8nio/n8n:latest
    # ... 나머지 설정

# 변경 후
services:
  n8n:
    image: n8n-with-curl
    # ... 나머지 설정 (그대로 유지)

 

4단계: 컨테이너 재시작

cd ~/n8n-queue-stack
docker compose down
docker compose up -d
  • 장점: 컨테이너가 재시작되거나 재생성되어도 curl이 항상 포함되어 있습니다.
  • 단점: n8n 공식 이미지가 업데이트되면 커스텀 이미지도 다시 빌드해야 합니다. FROM n8nio/n8n:latest라고 적어두었기 때문에 빌드할 때마다 최신 버전을 가져오지만, 이미 만들어진 커스텀 이미지는 자동으로 업데이트되지 않습니다.

n8n 업데이트 시 재빌드 방법

cd ~/n8n-custom

# 최신 n8n 이미지 가져오기
docker pull n8nio/n8n:latest

# 커스텀 이미지 다시 빌드
docker build -t n8n-with-curl .

# 컨테이너 재시작
cd ~/docker/n8n-queue-stack
docker compose down
docker compose up -d

 

방법 2-3: 세 가지 curl 설치 방법 비교

항목 컨테이너 내부 직접 설치 커스텀 이미지 빌드 curl-runner 컨테이너
설치 난이도 매우 쉬움 복잡함 보통
n8n 업데이트 영향 재설치 필요 재빌드 필요 영향 없음
컨테이너 재시작 시 사라짐 유지됨 유지됨
설정 복잡도 없음 Dockerfile 필요 docker-compose 수정 + Docker 소켓 마운트
보안 양호 양호 Docker 소켓 노출 위험
권장 상황 테스트, 임시 사용 프로덕션 환경 특수한 경우

 

권장: 처음에는 컨테이너 내부 직접 설치 방법으로 curl이 제대로 동작하는지 테스트하고, 정상 작동이 확인되면 커스텀 이미지 빌드 방법으로 영구적인 환경을 구축하는 것이 좋습니다.


5. 방법 3  |  헤드리스 브라우저 (동적 페이지의 정답)

동적 웹페이지를 제대로 크롤링하려면 실제 브라우저를 자동으로 제어하는 헤드리스 브라우저를 사용해야 합니다. 헤드리스 브라우저는 화면에 표시되지 않는 백그라운드 브라우저로, JavaScript를 완전히 실행하고 페이지가 완전히 로딩될 때까지 기다릴 수 있습니다. 마치 눈에 보이지 않는 로봇이 실제로 브라우저를 열고 웹사이트를 탐색하는 것과 같습니다.

 

가장 널리 사용되는 헤드리스 브라우저 도구는 Puppeteer와 Playwright입니다. Puppeteer는 Google에서 개발한 Node.js 라이브러리로 Chrome 브라우저를 제어하며, Playwright는 Microsoft에서 개발한 도구로 Chrome, Firefox, Safari를 모두 지원합니다. n8n에서 이러한 도구를 사용하려면 별도의 컨테이너를 설정하거나 커뮤니티 노드를 설치해야 합니다.

동적 웹페이지를 제대로 크롤링하려면 실제 브라우저를 자동으로 제어하는 헤드리스 브라우저를 사용해야 합니다

Browserless 컨테이너 연동하기

n8n과 함께 헤드리스 브라우저를 사용하는 가장 실용적인 방법은 Browserless 컨테이너를 별도로 실행하고 API로 연동하는 것입니다. Browserless는 Puppeteer를 API 서비스로 제공하는 도구로, n8n 이미지를 수정하지 않고도 브라우저 자동화 기능을 사용할 수 있습니다. docker-compose.yml 파일에 다음 서비스를 추가하면 됩니다.

services:
  # 기존 n8n 서비스 설정은 그대로 유지
  n8n:
    image: n8nio/n8n:latest
    # ... 기존 설정 ...

  # Browserless 서비스 추가
  browserless:
    image: browserless/chrome:latest
    container_name: browserless
    ports:
      - "3000:3000"
    environment:
      - MAX_CONCURRENT_SESSIONS=5
      - CONNECTION_TIMEOUT=60000
      - TIMEOUT=60000
    restart: unless-stopped
    networks:
      - n8n-network  # n8n과 동일한 네트워크 사용

networks:
  n8n-network:
    driver: bridge

n8n에서 Browserless 호출하기

Browserless가 실행되면 n8n의 HTTP Request 노드에서 API를 호출할 수 있습니다.

아래는 동적 페이지의 완전히 렌더링된 HTML을 가져오는 예시입니다. waitFor 옵션을 사용하면 JavaScript가 실행되고 콘텐츠가 로딩될 때까지 기다릴 수 있습니다.

 

HTTP Request 노드 설정:

설정 항목
Method POST
URL http://browserless:3000/content
Body Content Type JSON

 

Request Body:

{
  "url": "https://www.coupang.com/vp/products/8096844330",
  "waitFor": 3000,
  "gotoOptions": {
    "waitUntil": "networkidle0"
  }
}

 

이 요청을 Browserless의 /content 엔드포인트로 보내면 JavaScript가 완전히 실행된 후의 HTML을 받을 수 있습니다. 스크린샷이 필요하다면 /screenshot 엔드포인트를, PDF가 필요하다면 /pdf 엔드포인트를 사용하면 됩니다.

Browserless 주요 엔드포인트

엔드 포인트 용도 반환형식
/content 렌더링된 HTML 가져오기 HTML 텍스트
/screenshot 페이지 스크린샷 PNG 이미지
/pdf 페이지를 PDF로 변환 PDF 파일
/scrape 특정 요소 추출 JSON 데이터

6. 방법 4  |  외부 크롤링 서비스 API (가장 편리함)

직접 인프라를 구축하고 싶지 않다면 전문 크롤링 서비스를 이용하는 것도 좋은 선택입니다.

ScraperAPI, Bright Data, Oxylabs 같은 서비스들은 헤드리스 브라우저, 프록시 로테이션, CAPTCHA 해결 등의 기능을 클라우드에서 제공합니다. n8n에서는 단순히 HTTP Request 노드로 이들 서비스의 API를 호출하기만 하면 되므로, 복잡한 설정 없이 바로 동적 페이지 크롤링을 시작할 수 있습니다.

 

이러한 서비스들의 장점은 봇 탐지 우회, IP 차단 방지, 대규모 크롤링 등의 어려운 문제를 대신 처리해 준다는 것입니다. 특히 쿠팡, 아마존 같은 대형 이커머스 사이트들은 강력한 봇 탐지 시스템을 갖추고 있어서, 개인이 직접 크롤링하기 매우 어렵습니다. 전문 서비스를 이용하면 이러한 장벽을 쉽게 넘을 수 있습니다. 물론 비용이 발생하지만, 개발 시간과 인프라 유지보수 비용을 고려하면 오히려 경제적일 수 있습니다.

클라우드형 API를 활용하는 것은 정말로 편리함을 제공하지만 비용의 압박을 피할 수 없습니다 ❘ https://www.scraperapi.com
클라우드형 API를 활용하는 것은 정말로 편리함을 제공하지만 비용의 압박을 피할 수 없습니다 ❘ https://www.scraperapi.com

ScraperAPI 사용 예시

HTTP Request 노드 설정:

설정 항목
Method GET
URL https://api.scraperapi.com


Query Parameters:

api_key: YOUR_API_KEY
url: https://www.coupang.com/vp/products/8096844330
render: true

 

render=true 옵션을 설정하면 ScraperAPI가 헤드리스 브라우저로 페이지를 렌더링한 후 결과를 반환합니다. 이 한 줄의 옵션만으로 동적 페이지 크롤링이 가능해집니다.


7. 방법 비교  |  어떤 것을 선택해야 할까요?

각 방법의 특성을 한눈에 비교하면 다음과 같습니다. 상황에 따라 적합한 방법이 다르므로, 자신의 요구사항과 기술 수준을 고려하여 선택하시기 바랍니다.

방법 난이도 비용 동적페이지 봇탐지 우회 권장 상황
HTTP Request 무료 불가능 불가능 API 호출, 정적 페이지
curl 무료 불가능 가능 할 수 있음 복잡한 헤더/쿠키 필요
Browserless 무료 가능 가능 할 수 있음 동적 페이지, 자체 인프라
외부 서비스 유료 가능 가능 대규모 크롤링, 봇 탐지 우회

상황별 권장 방법

  • 테스트 및 소규모 프로젝트를 진행한다면 먼저 HTTP Request 노드로 시도해보고, 안 되면 브라우저 개발자 도구에서 내부 API를 찾아 curl로 호출해보는 것을 권장합니다. 이 방법으로 대부분의 간단한 크롤링 작업을 해결할 수 있습니다.
  • 정기적인 데이터 수집이 필요하다면 Browserless 컨테이너를 설정하는 것이 좋습니다. 초기 설정에 시간이 걸리지만, 한 번 구축해두면 다양한 동적 페이지를 안정적으로 크롤링할 수 있습니다.
  • 대규모 상업적 크롤링을 계획한다면 외부 서비스를 이용하는 것이 현명합니다. 인프라 관리 부담 없이 안정적인 크롤링이 가능하고, 법적 문제나 IP 차단 위험도 줄일 수 있습니다.

8. 크롤링 전에 확인해야 할 것들

robots.txt 확인하기

모든 웹사이트에는 robots.txt 파일이 있으며, 이 파일에는 크롤링이 허용되는 영역과 금지되는 영역이 명시되어 있습니다. 예를 들어 https://www.example.com/robots.txt를 확인하면 해당 사이트의 크롤링 정책을 알 수 있습니다. 이 정책을 무시하면 법적 문제가 발생할 수 있으므로 반드시 확인해야 합니다.

이용약관 검토하기

많은 웹사이트들은 이용약관에서 자동화된 데이터 수집을 금지하고 있습니다. 특히 상업적 목적의 크롤링은 더욱 엄격하게 제한됩니다. 크롤링을 시작하기 전에 대상 사이트의 이용약관을 반드시 검토하고, 필요하다면 사이트 운영자에게 허가를 요청하는 것이 좋습니다.

요청 간격 조절하기

짧은 시간에 너무 많은 요청을 보내면 서버에 부담을 주고, IP가 차단될 수 있습니다. n8n 워크플로우에서 Wait 노드를 사용하여 요청 사이에 적절한 간격(최소 1~2초)을 두는 것이 좋습니다. 이는 예의 바른 크롤링의 기본 원칙이며, 장기적으로 안정적인 데이터 수집을 가능하게 합니다.

공식 API 먼저 확인하기

크롤링을 시도하기 전에 해당 서비스가 공식 API를 제공하는지 확인해보세요. 많은 서비스들이 개발자용 API를 제공하며, 이를 통해 더 안정적이고 합법적으로 데이터에 접근할 수 있습니다. 예를 들어 쿠팡 파트너스, 네이버 개발자 센터 등에서 다양한 API를 제공하고 있습니다.


웹 크롤링은 강력한 도구이지만, 책임감 있게 사용해야 합니다. 대상 웹사이트의 서버에 부담을 주지 않도록 요청 빈도를 조절하고, 수집한 데이터의 저작권과 개인정보 보호 규정을 준수해야 합니다. 기술적으로 가능하다고 해서 모든 것이 허용되는 것은 아닙니다. 합법적이고 윤리적인 범위 내에서 크롤링을 활용하여 업무 효율을 높이고 가치 있는 인사이트를 얻으시기 바랍니다.