본문 바로가기

N8N - 웹 스크래핑 데이터 Google Sheet 저장

by Tech.Knockknows 2025. 11. 15.

이전 글에서 N8N + Playwright + FastAPI로 뉴스를 스크래핑하는 워크플로우를 만들었어요. 이번에는 여기서 한 단계 더 나아가, 스크래핑한 데이터를 Google Sheets(구글 스프레드시트)에 자동으로 저장하는 방법을 알아볼게요. 엑셀 파일로 다운로드하는 것보다 실시간으로 데이터가 쌓이고, 관리가 편하며 활용하기도 쉬워요.

 

전체 워크플로우 구조

이전 글에서는 웹에서 스크래핑한 데이터를 Convert to File 노드를 통해 xlsx 파일로 저장했었어요.

이번에는 Google Sheets 노드를 사용하고 구글 시트에 스크래핑 데이터를 저장할꺼에요.

N8N - 웹 스크래핑 구글 스프레드시트 저장 워크플로우
구분 기존 워크플로우 개선된 워크플로우
최종 단계 Convert to File (엑셀 다운로드) Google Sheets (자동 저장) ✨
데이터 확인 파일을 열어야 함 실시간 확인 가능
공유 수동으로 파일 전송 자동으로 공유됨
데이터 누적 매번 새 파일 생성 하나의 시트에 계속 추가

 

1단계: Google Sheets API 설정

N8N이 Google Sheets에 접근하려면 Google Cloud Console에서 API를 활성화하고 인증 정보를 만들어야 해요.

Google Cloud Console 프로젝트 생성

  1. Google Cloud Console 접속
  2. 상단의 프로젝트 선택 클릭 → 새 프로젝트 버튼 클릭
  3. 프로젝트 이름 입력 (예: n8n-news-scraper)
  4. 만들기 클릭

Google Sheets API 활성화

  1. 왼쪽 메뉴에서 API 및 서비스라이브러리 클릭
  2. 검색창에 Google Sheets API 입력
  3. Google Sheets API 클릭 → 사용 버튼 클릭

OAuth 동의 화면 구성

  1. 왼쪽 메뉴에서 API 및 서비스OAuth 동의 화면 클릭
  2. 중앙 Google 인증 플랫폼이 아직 구성되지 않음 -> 시작하기 클릭
  3. 앱 정보 입력:
    • 앱 이름: N8N News Scraper (자유롭게 입력)
    • 사용자 지원 이메일: 본인 이메일 선택
  4. 사용자 유형 선택:
    • 외부 선택 (개인 계정이라면)
    • 만들기 클릭
  5. 연락처 정보:
    • 사용하는 메일 입력
  6. 완료:
    • Google API 서비스: 사용자 데이터 정책 에 동의합니다.  체크
  7. 만들기 클릭
  8. 좌측 사이드 메뉴에서 데이터 액세스 선택:
    • 범위 추가 또는 삭제 클릭
    • Google Sheets API 선택
    • 업데이트 클릭
    • Save 선택
  9. 좌측 사이드 메뉴에서 대상 선택:
    • 테스트 사용자 아래 사용자 추가 클릭
    • Google Sheets를 사용할 본인의 Gmail 주소 입력
    • 저장 클릭

OAuth 2.0 클라이언트 ID 생성

  1. 왼쪽 메뉴에서 API 및 서비스사용자 인증 정보 클릭
  2. 상단의 + 사용자 인증 정보 만들기OAuth 클라이언트 ID 클릭
  3. 애플리케이션 유형 선택:
    • 웹 애플리케이션 선택
  4. 이름 입력: N8N OAuth Client (자유롭게)
  5. 승인된 리디렉션 URI에 N8N 주소 입력:
text 리디렉션 URI
https://<N8N 도메인>/rest/oauth2-credential/callback

💡 중요

N8N이 다른 주소(예: https://your-domain.com)에서 실행 중이라면 해당 주소를 입력해요.
예시: https://your-domain.com/rest/oauth2-credential/callback

  1. 만들기 클릭
  2. 생성된 클라이언트 ID클라이언트 보안 비밀번호를 복사해서 메모장에 저장하고 JSON도 다운로드 받아둬요.(분실 대비)

Google OAuth 발급

2단계: N8N에서 Google Sheets 인증

이제 N8N에서 Google 계정을 연동할 거예요.

  1. N8N 웹 인터페이스 접속
  2. 우측 상단의 설정(톱니바퀴) 아이콘 클릭 → Credentials 메뉴 클릭
  3. 우측 상단의 + Add Credential 버튼 클릭
  4. 검색창에 Google 입력 → Google Sheets OAuth2 API 선택
  5. 정보 입력:
항목 설명
Credential Name Google Sheets account 알아보기 쉬운 이름이면 돼요.
Client ID (1단계에서 복사한 클라이언트 ID) Google Cloud Console에서 발급받은 값
Client Secret (1단계에서 복사한 클라이언트 보안 비밀번호) Google Cloud Console에서 발급받은 값
  1. Sign in with Google 버튼 클릭
  2. Google 계정 선택 후 권한 허용
    • "이 앱은 Google에서 확인하지 않았습니다" 경고가 나올 수 있어요
    • 계속 → 모든 Google Sheets 스프레드시트 확인, 수정, 생성, 삭제 선택
    • 계속 버튼 클릭
  3. N8N으로 자동 리디렉션되면 자격증명 등록 완료
✅ 이제 N8N이 Google Sheets에 접근할 수 있어요.

 

https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlesheets/

 

Google Sheets | n8n Docs

<!-- Copyright (c) 2016-2024 Martin Donath Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without lim

docs.n8n.io

 

3단계: Google Sheet 준비

데이터를 저장할 Google Sheet를 미리 만들어 둘 거예요.

새 스프레드시트 생성

 
  1. Google Sheets 접속
  2. 상단의 + 빈 스프레드시트 클릭
  3. 제일 상단 제목없는 스프레드시트 -> 이름 변경: 웹 스크래핑 데이터-N8N (자유롭게)

헤더(컬럼명) 설정

 

첫 번째 행에 다음 컬럼명을 입력해요:

A B C D E F
제목 URL 본문 발행일 스크랩 일시 응답 시간(ms)

💡 왜 헤더를 먼저 만들까요?

N8N의 Google Sheets 노드는 헤더가 있는 시트에 데이터를 추가할 때 컬럼을 자동으로 매칭해줘요.

스프레드 시트 생성 및 헤더 설정

Sheet ID 복사

 

스프레드시트 URL에서 Sheet ID를 복사해요:

https://docs.google.com/spreadsheets/d/[이 부분이 Sheet ID]/edit

예시:
https://docs.google.com/spreadsheets/d/1a2b3c4d5e6f7g8h9i0j/edit
                                      ↑
                            이 부분을 복사해요!

Sheet ID를 메모장에 저장해요. (N8N에서 사용)

 

4단계: N8N 워크플로우 수정

이전 글에서 만든 워크플로우를 수정해서 Google Sheets 노드를 추가할 거예요.

Google Sheets 노드 추가

  1. N8N에서 이전에 만든 워크플로우 열기
  2. Convert to File 노드 삭제 (또는 연결 끊기)
  3. 삭제된 노드 자리에  Google Sheets  - Append row in sheet 추가
  4. 노드 설정:
기본 설정
항목 설명
Credential to connect with Google Sheets account 2단계에서 만든 Credential 선택
Resource Sheet Within Document Sheet(시트) 리소스를 사용해요.
Operation Append Row 기존 데이터 아래에 새 행을 추가해요.
Document By ID Seeht ID로 스프레드시트를 지정해요
By ID (3단계에서 복사한 SheetID를 입력해요) 예: 1a2b3c4d5e6f...
Sheet From list 문서 내 시트 목록을 나열해요.
From list 시트1(Sheet1) 값을 추가할 시트를 선택해요.
Mapping Column Mode Map Automatically N8N이 자동으로 데이터를 컬럼에 매핑해줘요.

 

데이터 매핑

Google Sheets는 3단계에서 만든 헤더(제목, URL, 본문 등)와 정확히 일치하는 이름의 데이터를 찾아요.

현재 WebpageContentExtractor 노드의 출력 데이터와 Google Sheets 헤더가 일치하지 않을 수 있어요. 그래서 중간에 Code 노드를 하나 더 추가해서 데이터를 정리할 거예요.

새 Code 노드 추가

 
  1. WebpageContentExtractor뒤에  Code 노드 추가
  2. 노드 이름 설정 : Google Sheet 헤더 포맷 정규화
  3. 다음 코드 입력:
javascript N8N Code Node - 데이터 정리
// 이전 노드(WebpageContentExtractor)에서 들어온 데이터를 가져와요.
const items = [];

for (const item of $input.all()) {
  // 원본 데이터
  const url = $('HTTP Request').first().json.url;
  const originalPubDate = $input.first().json.publishedTime;
  
  // WebpageContentExtractor 결과
  const extractedText = $input.first().json.textContent;
  const extractedTitle = $input.first().json.title;
  
  // HTTP Request 응답 데이터
  const responseTime = $('HTTP Request').first().json.response_time_ms;
  
  // 현재 시각
  const scrapedAt = $('HTTP Request').first().json.scraped_at;
  
  // [중요!] Google Sheets의 헤더명과 정확히 일치하도록 키 이름을 설정해요.
  items.push({
    json: {
      "제목": extractedTitle,
      "URL": url,
      "본문": extractedText,
      "발행일": originalPubDate,
      "스크랩 일시": scrapedAt,
      "응답 시간(ms)": responseTime
    }
  });
}

return items;

🔍 핵심

json 객체의 키 이름("제목", "URL" 등)이 Google Sheets의 헤더명과 정확히 일치해야 해요!

 

5단계: 실행 및 테스트

워크플로우 실행

 
  1. 워크플로우 저장 (상단의 Save 버튼)
  2. 우측 상단의 Execute Workflow 버튼 클릭

실행 과정 확인

 

N8N 화면에서 각 노드를 클릭하면 실행 결과를 볼 수 있어요:

  1. RSS Read: RSS 피드에서 가져온 기사 목록
  2. Code (URL 추출): 추출된 URL과 요청 데이터
  3. Loop Over Items: 현재 처리 중인 아이템 번호
  4. HTTP Request: FastAPI 응답 (HTML, 제목 등)
  5. WebpageContentExtractor: 추출된 본문
  6. Code (데이터 정리): Google Sheets 형식으로 정리된 데이터
  7. Google Sheets: 성공 여부

Google Sheets 확인

 
  1. Google Sheets 스프레드시트 열기
  2. 새로운 행들이 추가되었는지 확인

웹 스크래핑 데이터가 추가된 구글 Sheets

이제 15분마다 자동으로 새 기사가 스프레드시트에 추가돼요

워크플로우 활성화

 
  1. 워크플로우 상단의 Inactive 토글을 Active로 변경
  2. 이제 Schedule Trigger에 설정한 시간마다 자동으로 실행돼요

 

트러블슈팅 (Q&A)

"Insufficient Permission" 오류

 

증상: Google Sheets 노드가 "Insufficient Permission" 또는 "권한이 없습니다" 오류를 반환해요.
원인: Google Cloud Console의 OAuth 동의 화면에서 Spreadsheets API 범위(Scope)를 추가하지 않았어요.
해결:

  1. Google Cloud Console → OAuth 동의 화면 이동
  2. 앱 수정 클릭
  3. 범위 단계에서 https://www.googleapis.com/auth/spreadsheets 범위가 있는지 확인
  4. 없다면 범위 추가 또는 삭제 → 검색 후 추가
  5. N8N의 Credential을 삭제하고 2단계부터 다시 인증

"Unable to parse range" 오류

 

 

증상: Google Sheets 노드가 "Unable to parse range" 오류를 반환해요.
원인: Sheet 이름이 잘못되었어요. (예: Sheet1이 아닌 다른 이름)
해결:

  1. Google Sheets 스프레드시트 열기
  2. 하단의 시트 탭 이름 확인 (예: Sheet1, 시트1 등)
  3. N8N의 Google Sheets 노드 설정에서 Sheet 필드에 정확한 이름 입력

데이터가 엉뚱한 컬럼에 들어가요

 

증상: 제목이 URL 컬럼에 들어가는 등 데이터가 뒤섞여요.
원인: Code(데이터 정리) 노드의 키 이름과 Google Sheets 헤더명이 일치하지 않아요.
해결:

  1. Google Sheets의 헤더명을 정확히 확인 (띄어쓰기, 대소문자 주의!)
  2. Code 노드의 키 이름을 정확히 일치시켜요:
javascript 올바른 예시
// 잘못된 예
"title": extractedTitle,  // ❌ 헤더가 "제목"이라면 작동 안 함

// 올바른 예
"제목": extractedTitle,    // ✅

 

 

중복 데이터가 계속 쌓여요

 

증상: 같은 기사가 매번 스프레드시트에 추가돼요.
원인: RSS 피드는 최근 N개의 기사를 항상 포함하기 때문에, 이미 처리한 기사도 다시 가져올 수 있어요. 워크플로우가 실행될 때마다 중복 체크가 필요해요.


해결 1: Google Sheets로만 확인 (데이터가 적을 경우)

워크플로우 시작 시 Google Sheet의 기존 URL을 모두 읽어온 후, N8N의 Filter 노드를 사용해 비교해요. 데이터가 수백~수천 건 수준이라면 가장 구현하기 쉬워요.

워크플로우 (해결 1):

Schedule Trigger 
  → RSS Read
  → Google Sheets (Get Existing URLs) ← ✨ 1. 기존 URL 읽기
    → Code (URL 추출) 
      → Loop Over Items
        → HTTP Request (Playwright)
          → WebpageContentExtractor
            → Filter (Check if URL exists) ← ✨ 2. 중복 필터링
              → Code (데이터 정리)
                → Google Sheets (Append)

1. 'Google Sheets (Get Existing URLs)' 노드 추가

  • RSS Read 노드와 Code (URL 추출) 노드 사이에 Google Sheets 노드를 추가합니다.
  • Credential: (기존에 만든 Credential 선택)
  • Operation: Get (읽기)
  • Document ID: (데이터가 저장된 Sheet ID 입력)
  • Sheet: Sheet1 (시트 이름)
  • Data Mode: Define Columns
  • Columns: URL (Google Sheet의 'URL' 컬럼명과 일치해야 함)
    • 또는 Data ModeUse Range로 하고 RangeB2:B (B컬럼이 URL이고 1행이 헤더일 경우)를 입력해도돼요.

2. 'Filter' 노드 추가

  • WebpageContentExtractor 노드와 Code (데이터 정리) 노드 사이에 Filter 노드를 추가해요.
  • ConditionsAdd Condition 클릭
  • Value 1: {{ $json.scrapeRequest.url }} (또는 HTTP Request 노드에서 URL을 나타내는 변수)
  • Operation: Not In
  • Value 2: Expression (우측 'f(x)' 버튼 클릭)
    • Expression 입력창에: {{ $('Google Sheets (Get Existing URLs)').all('json').map(item => item.URL) }}
    • (Google Sheets (Get Existing URLs)는 1번에서 추가한 노드의 이름, item.URL은 해당 노드에서 가져온 컬럼명과 일치해야 해요.)

3. 노드 연결

  • Filter 노드의 true (조건 통과, 즉 중복 아님) 출력(점)을 Code (데이터 정리) 노드로 연결해요.
  • false (중복) 출력은 아무데도 연결하지 않아요.

해결 2: 별도 DB 사용 (권장, 데이터가 많을 경우)

문제점: '해결 1' 방식은 시트에 데이터가 수만 건 쌓이면, 매번 모든 URL을 읽어오는 과정에서 속도가 느려지고 Google Sheets API 할당량을 초과할 수 있어요..

개선: N8N에 내장된 SQLite 또는 외부 DB(Postgres, MySQL 등)에 중복 확인용 URL만 따로 저장하고 대조해요. 이 방식이 훨씬 빠르고 안정적이에요.

워크플로우 (해결 2):

Schedule Trigger 
  → RSS Read
    → Code (URL 추출) 
      → Loop Over Items
        → SQLite (Check URL)     ← ✨ 1. DB에서 URL 존재 확인 (SELECT)
          → Filter (If count=0)  ← ✨ 2. DB에 없으면(0) 통과
            → HTTP Request (Playwright)
              → WebpageContentExtractor
                → Code (데이터 정리)
                  → Google Sheets (Append)
                    → SQLite (Insert URL) ← ✨ 3. 시트 저장 성공 시, DB에 URL 추가 (INSERT)

1. 'SQLite (Check URL)' 노드 추가 (루프 내부)

  • Loop Over Items 노드 바로 다음에 SQLite 노드를 추가해요.
  • Operation: Execute Query
  • Query: SELECT count(*) as count FROM processed_urls WHERE url = '{{ $json.url }}'
  • (processed_urls 테이블은 미리 CREATE TABLE processed_urls (url TEXT PRIMARY KEY, added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP) 같은 쿼리를 실행해 생성해둬야 해요.)

2. 'Filter' 노드 추가

  • SQLite (Check URL) 노드 다음에 Filter (또는 If) 노드를 추가해요.
  • Value 1: {{ $('SQLite (Check URL)').item.json.count }}
  • Operation: Equals
  • Value 2: 0

3. 'SQLite (Insert URL)' 노드 추가

  • Filtertrue 경로를 따라 Google Sheets (Append) 노드까지 연결해요.
  • Google Sheets (Append) 노드 다음에 SQLite 노드를 하나 더 추가해요.
  • Operation: Execute Query
  • Query: INSERT INTO processed_urls (url) VALUES ('{{ $json.url }}')
  • 결과: 이 방식은 Google Sheet의 크기와 상관없이 항상 빠른 속도로 중복을 체크할 수 있어요.

 

 

"API Rate Limit Exceeded" 오류

 

증상: Google Sheets 노드가 "Rate limit exceeded" 오류를 반환해요.
원인: Google Sheets API는 분당 요청 수 제한이 있어요. (기본: 분당 60회)
해결:

  1. RSS Read 노드의 Limit을 줄여서 한 번에 처리하는 기사 수를 줄여요.
  2. Schedule Trigger 실행 간격을 늘려요. (15분 → 30분)
  3. Google Cloud Console에서 API 할당량을 확인하고 필요 시 증액 요청

OAuth 인증이 만료되었어요

 

증상: 워크플로우가 "Token has been expired or revoked" 오류를 반환해요.
원인: Google OAuth 토큰은 일정 시간 후 만료돼요. (앱이 "테스트" 모드일 경우 7일)
해결:

  1. Google Cloud Console → OAuth 동의 화면 이동
  2. 게시 상태테스트프로덕션으로 변경
    • 앱 게시 버튼 클릭
    • (개인 사용이므로 Google 검토는 필요 없어요)
  3. N8N Credential에서 Sign in with Google 버튼을 다시 클릭해서 재인증

 

정리

이번 글에서 아래와 같은 내용을 진행했어요.

  •  Google Cloud Console에서 Sheets API 활성화 및 OAuth 설정
  • N8N에서 Google 계정 인증
  • 스크래핑 데이터를 Google Sheets에 자동 저장
  • 15분마다 자동으로 새 기사 수집 및 저장

다음 글에서는 중복제거, 병렬 처리 기능 등을 추가하여 안정성과 속도를 개선해볼게요.

이전 글 참고

2025.11.07 - [기타] - 브라우저 자동화 도구 Playwright

2025.11.13 - [N8N] - N8N - Playwright를 통한 뉴스 스크래핑