크롤링과 HTML 추출 — 웹 데이터 수집 자동화

크롤링과 HTML 추출 — 웹 데이터 수집 자동화

API를 제공하지 않는 웹사이트에서도 데이터를 자동으로 수집할 수 있다. HTTP Request로 페이지를 가져오고, HTML Extract로 원하는 정보만 뽑아내면 된다.

크롤링 기본 구조

[Schedule/Manual] → [HTTP Request: 웹 페이지 가져오기] → [HTML Extract: 데이터 추출]
                                                          → [Edit Fields: 정제]
                                                          → [저장/알림]

Step 1: HTTP Request로 페이지 가져오기

Method: GET
URL: https://news.ycombinator.com/
Options → Response Format: Text (HTML 원본)

💡 주의: Response Format을 Text로 설정해야 HTML 원본이 그대로 넘어온다. JSON(기본값)으로 설정하면 파싱 에러가 발생한다.

User-Agent 설정

일부 사이트는 봇을 차단한다. User-Agent 헤더를 추가하자:

Headers:
  User-Agent: Mozilla/5.0 (compatible; n8n-bot/1.0)

Step 2: HTML Extract 노드

HTML에서 CSS 셀렉터를 사용해 원하는 데이터를 추출한다.

기본 설정

설정 설명
Source Data Binary (HTML 파일) 또는 JSON (텍스트 필드)
Extraction Values CSS 셀렉터 + 반환할 속성 목록

CSS 셀렉터 기초

셀렉터 의미 예시
h1 태그 이름 모든 h1 태그
.class-name 클래스 .article-title
#id-name ID #main-content
div > p 직접 자식 div 바로 아래 p
div p 모든 자손 div 안의 모든 p
a[href] 속성 있는 태그 href 속성이 있는 a
:nth-child(2) N번째 요소 두 번째 자식 요소

반환 속성

Return Value 설명
HTML 태그의 innerHTML
Text 태그의 텍스트만 (태그 제거)
Attribute: href 링크 URL
Attribute: src 이미지 URL
Attribute: class 클래스명

실전 예제: Hacker News 크롤링

Hacker News 첫 페이지의 제목과 링크를 수집하자.

HTML Extract 설정

Extraction Values:
  제목:
    CSS Selector: .titleline > a
    Return Value: Text

  링크:
    CSS Selector: .titleline > a
    Return Value: Attribute → href

  포인트:
    CSS Selector: .score
    Return Value: Text

결과

[
  { "제목": "Show HN: Something Cool", "링크": "https://...", "포인트": "142 points" },
  { "제목": "Why AI Needs More...", "링크": "https://...", "포인트": "89 points" }
]

여러 페이지 크롤링 (Pagination)

한 페이지만으로 부족할 때, 여러 페이지를 순회한다.

패턴: URL 패턴 기반

[Code: URL 목록 생성]
  → [Split Out: 각 URL]
  → [HTTP Request: 페이지 가져오기]
  → [HTML Extract: 데이터 추출]
  → [Aggregate: 결과 합치기]

Code 노드:

const pages = [];
for (let i = 1; i <= 5; i++) {
  pages.push({ json: { url: `https://example.com/list?page=${i}` } });
}
return pages;

패턴: "다음 페이지" 링크 추적

[HTTP Request] → [HTML Extract: 데이터 + 다음 URL]
  → [IF: 다음 페이지 있는가?]
     true → [Edit Fields: 다음 URL로] → [HTTP Request] (루프)
     false → [완료]

SerpAPI 노드 — 검색 결과 수집

직접 크롤링 대신 SerpAPI를 사용하면 Google, Bing, YouTube 등의 검색 결과를 구조화된 JSON으로 받을 수 있다.

API: Google Search
Query: "n8n workflow automation"
Location: South Korea
Language: ko

결과:

{
  "organic_results": [
    { "title": "...", "link": "...", "snippet": "..." },
    { "title": "...", "link": "...", "snippet": "..." }
  ]
}

실전: 경쟁사 가격 모니터링

[Schedule: 매일 오전 9시]
  → [HTTP Request: 경쟁사 상품 페이지]
  → [HTML Extract: 가격, 상품명]
  → [Code: 가격 파싱 (₩ 제거, 숫자 변환)]
  → [Google Sheets: 기록]
  → [IF: 가격 변동?]
     true → [Slack: "⚠️ 경쟁사 가격 변경!" 알림]

가격 파싱 Code 노드

const items = $input.all();
return items.map(item => {
  const priceText = item.json.가격 || '0';
  const price = parseInt(priceText.replace(/[^0-9]/g, ''), 10);

  return {
    json: {
      상품명: item.json.상품명?.trim(),
      가격: price,
      수집일: new Date().toISOString().split('T')[0],
      원본가격: priceText
    }
  };
});

윤리적 크롤링 주의사항

원칙 설명
robots.txt 확인 크롤링 허용 여부를 먼저 확인
Rate Limiting 요청 간 1~2초 이상 대기. 서버에 부하를 주지 말 것
이용약관 준수 사이트의 ToS에서 크롤링 금지 여부 확인
개인정보 보호 개인 식별 정보 수집 금지
캐싱 같은 페이지를 반복 요청하지 않도록 결과 캐싱
API 우선 API가 있으면 크롤링 대신 API 사용

⚠️ 경고: 무분별한 크롤링은 법적 문제를 야기할 수 있다. 항상 합법적이고 윤리적인 방법으로 데이터를 수집하자.


📝 정리

  • [x] 크롤링 기본: HTTP Request(Text 모드) → HTML Extract(CSS 셀렉터)
  • [x] CSS 셀렉터: 태그, 클래스(.), ID(#), 속성([href]) 조합으로 정밀 추출
  • [x] 반환 값: Text(텍스트만), HTML(태그 포함), Attribute(href, src 등)
  • [x] 페이지네이션: URL 패턴 또는 "다음 페이지" 링크 추적
  • [x] 윤리적 크롤링: robots.txt, Rate Limiting, 이용약관 준수 필수

다음 편 예고

21편: n8n × AI 입문 — LLM 노드로 텍스트 자동 생성

Part 4 시작! OpenAI, Claude, Gemini를 n8n에 연결하여 텍스트 요약, 번역, 감성 분석을 자동화한다. AI 워크플로우의 첫걸음.