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

| 구분 | 기존 워크플로우 | 개선된 워크플로우 |
|---|---|---|
| 최종 단계 | Convert to File (엑셀 다운로드) | Google Sheets (자동 저장) ✨ |
| 데이터 확인 | 파일을 열어야 함 | 실시간 확인 가능 |
| 공유 | 수동으로 파일 전송 | 자동으로 공유됨 |
| 데이터 누적 | 매번 새 파일 생성 | 하나의 시트에 계속 추가 |
1단계: Google Sheets API 설정
N8N이 Google Sheets에 접근하려면 Google Cloud Console에서 API를 활성화하고 인증 정보를 만들어야 해요.
Google Cloud Console 프로젝트 생성
- Google Cloud Console 접속
- 상단의 프로젝트 선택 클릭 → 새 프로젝트 버튼 클릭
- 프로젝트 이름 입력 (예: n8n-news-scraper)
- 만들기 클릭
Google Sheets API 활성화
- 왼쪽 메뉴에서 API 및 서비스 → 라이브러리 클릭
- 검색창에 Google Sheets API 입력
- Google Sheets API 클릭 → 사용 버튼 클릭
OAuth 동의 화면 구성
- 왼쪽 메뉴에서 API 및 서비스 → OAuth 동의 화면 클릭
- 중앙 Google 인증 플랫폼이 아직 구성되지 않음 -> 시작하기 클릭
- 앱 정보 입력:
- 앱 이름: N8N News Scraper (자유롭게 입력)
- 사용자 지원 이메일: 본인 이메일 선택
- 사용자 유형 선택:
- 외부 선택 (개인 계정이라면)
- 만들기 클릭
- 연락처 정보:
- 사용하는 메일 입력
- 완료:
- Google API 서비스: 사용자 데이터 정책 에 동의합니다. 체크
- 만들기 클릭
- 좌측 사이드 메뉴에서 데이터 액세스 선택:
- 범위 추가 또는 삭제 클릭
- Google Sheets API 선택
- 업데이트 클릭
- Save 선택
- 좌측 사이드 메뉴에서 대상 선택:
- 테스트 사용자 아래 사용자 추가 클릭
- Google Sheets를 사용할 본인의 Gmail 주소 입력
- 저장 클릭
OAuth 2.0 클라이언트 ID 생성
- 왼쪽 메뉴에서 API 및 서비스 → 사용자 인증 정보 클릭
- 상단의 + 사용자 인증 정보 만들기 → OAuth 클라이언트 ID 클릭
- 애플리케이션 유형 선택:
- 웹 애플리케이션 선택
- 이름 입력: N8N OAuth Client (자유롭게)
- 승인된 리디렉션 URI에 N8N 주소 입력:
https://<N8N 도메인>/rest/oauth2-credential/callback
💡 중요
N8N이 다른 주소(예: https://your-domain.com)에서 실행 중이라면 해당 주소를 입력해요.
예시: https://your-domain.com/rest/oauth2-credential/callback
- 만들기 클릭
- 생성된 클라이언트 ID와 클라이언트 보안 비밀번호를 복사해서 메모장에 저장하고 JSON도 다운로드 받아둬요.(분실 대비)

2단계: N8N에서 Google Sheets 인증
이제 N8N에서 Google 계정을 연동할 거예요.
- N8N 웹 인터페이스 접속
- 우측 상단의 설정(톱니바퀴) 아이콘 클릭 → Credentials 메뉴 클릭
- 우측 상단의 + Add Credential 버튼 클릭
- 검색창에 Google 입력 → Google Sheets OAuth2 API 선택
- 정보 입력:
| 항목 | 값 | 설명 |
|---|---|---|
| Credential Name | Google Sheets account | 알아보기 쉬운 이름이면 돼요. |
| Client ID | (1단계에서 복사한 클라이언트 ID) | Google Cloud Console에서 발급받은 값 |
| Client Secret | (1단계에서 복사한 클라이언트 보안 비밀번호) | Google Cloud Console에서 발급받은 값 |
- Sign in with Google 버튼 클릭
- Google 계정 선택 후 권한 허용
- "이 앱은 Google에서 확인하지 않았습니다" 경고가 나올 수 있어요
- 계속 → 모든 Google Sheets 스프레드시트 확인, 수정, 생성, 삭제 선택
- 계속 버튼 클릭
- N8N으로 자동 리디렉션되면 자격증명 등록 완료
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를 미리 만들어 둘 거예요.
새 스프레드시트 생성
- Google Sheets 접속
- 상단의 + 빈 스프레드시트 클릭
- 제일 상단 제목없는 스프레드시트 -> 이름 변경: 웹 스크래핑 데이터-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 노드 추가
- N8N에서 이전에 만든 워크플로우 열기
- Convert to File 노드 삭제 (또는 연결 끊기)
- 삭제된 노드 자리에 Google Sheets - Append row in sheet 추가
- 노드 설정:
| 기본 설정 | ||
|---|---|---|
| 항목 | 값 | 설명 |
| 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 노드 추가
- WebpageContentExtractor뒤에 Code 노드 추가
- 노드 이름 설정 : Google Sheet 헤더 포맷 정규화
- 다음 코드 입력:
// 이전 노드(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단계: 실행 및 테스트
워크플로우 실행
- 워크플로우 저장 (상단의 Save 버튼)
- 우측 상단의 Execute Workflow 버튼 클릭
실행 과정 확인
N8N 화면에서 각 노드를 클릭하면 실행 결과를 볼 수 있어요:
- RSS Read: RSS 피드에서 가져온 기사 목록
- Code (URL 추출): 추출된 URL과 요청 데이터
- Loop Over Items: 현재 처리 중인 아이템 번호
- HTTP Request: FastAPI 응답 (HTML, 제목 등)
- WebpageContentExtractor: 추출된 본문
- Code (데이터 정리): Google Sheets 형식으로 정리된 데이터
- Google Sheets: 성공 여부
Google Sheets 확인
- Google Sheets 스프레드시트 열기
- 새로운 행들이 추가되었는지 확인

워크플로우 활성화
- 워크플로우 상단의 Inactive 토글을 Active로 변경
- 이제 Schedule Trigger에 설정한 시간마다 자동으로 실행돼요
트러블슈팅 (Q&A)
"Insufficient Permission" 오류
증상: Google Sheets 노드가 "Insufficient Permission" 또는 "권한이 없습니다" 오류를 반환해요.
원인: Google Cloud Console의 OAuth 동의 화면에서 Spreadsheets API 범위(Scope)를 추가하지 않았어요.
해결:
- Google Cloud Console → OAuth 동의 화면 이동
- 앱 수정 클릭
- 범위 단계에서 https://www.googleapis.com/auth/spreadsheets 범위가 있는지 확인
- 없다면 범위 추가 또는 삭제 → 검색 후 추가
- N8N의 Credential을 삭제하고 2단계부터 다시 인증
"Unable to parse range" 오류
증상: Google Sheets 노드가 "Unable to parse range" 오류를 반환해요.
원인: Sheet 이름이 잘못되었어요. (예: Sheet1이 아닌 다른 이름)
해결:
- Google Sheets 스프레드시트 열기
- 하단의 시트 탭 이름 확인 (예: Sheet1, 시트1 등)
- N8N의 Google Sheets 노드 설정에서 Sheet 필드에 정확한 이름 입력
데이터가 엉뚱한 컬럼에 들어가요
증상: 제목이 URL 컬럼에 들어가는 등 데이터가 뒤섞여요.
원인: Code(데이터 정리) 노드의 키 이름과 Google Sheets 헤더명이 일치하지 않아요.
해결:
- Google Sheets의 헤더명을 정확히 확인 (띄어쓰기, 대소문자 주의!)
- Code 노드의 키 이름을 정확히 일치시켜요:
// 잘못된 예
"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 Mode를 Use Range로 하고 Range에 B2:B (B컬럼이 URL이고 1행이 헤더일 경우)를 입력해도돼요.
2. 'Filter' 노드 추가
- WebpageContentExtractor 노드와 Code (데이터 정리) 노드 사이에 Filter 노드를 추가해요.
- Conditions → Add 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)' 노드 추가
- Filter의 true 경로를 따라 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회)
해결:
- RSS Read 노드의 Limit을 줄여서 한 번에 처리하는 기사 수를 줄여요.
- Schedule Trigger 실행 간격을 늘려요. (15분 → 30분)
- Google Cloud Console에서 API 할당량을 확인하고 필요 시 증액 요청
OAuth 인증이 만료되었어요
증상: 워크플로우가 "Token has been expired or revoked" 오류를 반환해요.
원인: Google OAuth 토큰은 일정 시간 후 만료돼요. (앱이 "테스트" 모드일 경우 7일)
해결:
- Google Cloud Console → OAuth 동의 화면 이동
- 게시 상태를 테스트 → 프로덕션으로 변경
- 앱 게시 버튼 클릭
- (개인 사용이므로 Google 검토는 필요 없어요)
- N8N Credential에서 Sign in with Google 버튼을 다시 클릭해서 재인증
정리
이번 글에서 아래와 같은 내용을 진행했어요.
- Google Cloud Console에서 Sheets API 활성화 및 OAuth 설정
- N8N에서 Google 계정 인증
- 스크래핑 데이터를 Google Sheets에 자동 저장
- 15분마다 자동으로 새 기사 수집 및 저장
다음 글에서는 중복제거, 병렬 처리 기능 등을 추가하여 안정성과 속도를 개선해볼게요.
이전 글 참고
'N8N' 카테고리의 다른 글
| N8N - 웹 스크래핑 자동화: JWT 인증 + 병렬 처리 + PostgreSQL 중복 방지 (0) | 2025.11.19 |
|---|---|
| N8N - Playwright를 통한 뉴스 스크래핑 (0) | 2025.11.13 |
| N8N 사용법 - RSS 피드 본문 추출 후 엑셀 저장하기 (0) | 2025.09.18 |
| N8N Guide - 커뮤니티 노드(Community Node) 설치 (0) | 2025.09.10 |
| N8N 사용법 - HTTP Request 노드 및 HTTP 메소드 이해 (0) | 2025.09.08 |