본문으로 건너뛰기
취준생을 위한 n8n 실전 워크플로우 레시피 · 8/44시리즈 보기 →

공공데이터 API를 10분마다 구글시트에 쌓기 — 응급실 가용 병상 데이터로 배우는 수집 자동화

· 약 8분
Datapopcorn CEO / AI automation educator
이 글과 연결된 글 보기
7편 · 15개 연결
100%
n8n Data Table 처음 써보기 — 트렌드 3개를 합쳐 매일 아침 분석 주제 뽑는 워크플로우n8n으로 정적 웹서버 운영하기 — 수료증 발급부터 진위 확인까지, 멱등 처리로 안전하게벡터DB 없이 실시간으로 사이트를 읽는 챗봇 — 경복대학교 안내 챗봇 해부n8n으로 반복업무 자동화 포트폴리오 만들기공공데이터 API를 10분마다 구글시트에 쌓기 — 응급실 가용 병상 데이터로 배우는 수집 자동화서브워크플로우를 Tool로 감싸 AI Agent에게 서버 점검시키기 — 그리고 시스템 프롬프트만으로는 부족한 이유공공데이터 수집에서 막히는 6가지와 해결법: 공공데이터포털·KOSIS·PDF 통계표 (Colab 노트북 포함)

드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.

표시된 글 7편 목록
전체 글 연결 탐색

data.go.kr이 공개하는 응급실 실시간 가용병상 API에 인증키 하나만 발급받으면, n8n 노드 몇 개로 10분마다 최신 데이터를 구글시트에 스냅샷으로 쌓는 자동화를 만들 수 있습니다. 인증키를 코드에 박아 넣지 않는 법과, 같은 데이터를 시트에 넣는 두 가지 방식의 차이까지 한 워크플로우 안에 들어 있습니다.

이 워크플로우 하나로 보여줄 수 있는 것​

지금까지 이 시리즈는 구글시트(재고 알림 편)와 날씨 API(날씨 알림 편)처럼 이미 구조가 정해진 데이터를 다뤘습니다. 이번 편은 국가가 공개한 공공데이터 API를 처음부터 붙여보는 편이라, 실무에서 자주 마주치는 역량 네 가지가 한 번에 들어갑니다.

  • API 활용신청 — data.go.kr에서 직접 활용신청을 넣고 인증키를 발급받아본 경험
  • 인증키를 안전하게 다루기 — 키를 URL에 박아 넣지 않고 credential로 분리하는 습관
  • 중첩 JSON 펼치기 — 여러 겹으로 감싸인 배열을 Split Out으로 아이템 단위로 바꾸는 경험
  • 적재 방식 선택 — 같은 데이터를 시트에 넣는 두 가지 방법(한 번에 vs 한 행씩)의 속도와 안정성 트레이드오프를 눈으로 비교해본 경험

배경​

이 워크플로우는 원본 캔버스에 "(유즈케이스)"라는 이름이 붙어 있는 것에서 보이듯, 실제 운영 중인 서비스가 아니라 공공데이터 API를 다루는 법을 보여주기 위한 예시로 만들어졌습니다. 소재는 국립중앙의료원이 공개하는 응급의료기관 정보 조회 서비스입니다. 병원별로 지금 당장 남은 응급실 병상 수, 중환자실 여유, CT·MRI 같은 장비 가동 여부까지 실시간으로 담고 있는 API입니다.

취준생이 포트폴리오에 넣을 데이터 수집 자동화를 고를 때 공공데이터만큼 무난한 소재가 없습니다. 무료로 인증키가 나오고, API 문서가 공식적으로 정리돼 있고, 결과물을 "어떤 데이터를 어떻게 정제했는지"로 설명하기 좋기 때문입니다. n8n 설치나 기본 노드는 n8n으로 반복업무 자동화 포트폴리오 만들기에서 다뤘으니, 이 글은 API 연결부터 시작합니다.

구조 — Trigger / Task / Target​

  • Trigger — 10분 간격 스케줄
  • Task — API 호출 → 응답 배열을 아이템으로 펼치기 → 컬럼 타입 정리 → 시트를 비우고 다시 채우기
  • Target — 구글시트 스냅샷 (+ 선택: S3·드라이브에 CSV 아카이브)

Schedule Trigger는 HTTP Request와 별도로 Clear 노드에도 바로 연결돼 있습니다. 실행할 때마다 시트를 먼저 비우고, API에서 받아온 최신 데이터로 다시 채우는 스냅샷 구조라고 이해하면 됩니다.

만들기​

1. data.go.kr에서 인증키 발급받기​

공공데이터포털에서 전국 응급의료기관 정보 조회 서비스 페이지를 열고 활용신청을 넣으면 인증키가 발급됩니다. 개발계정 기본 트래픽은 하루 1,000회입니다(2026년 8월 기준, 공공데이터포털). 이 워크플로우처럼 10분마다 한 번씩, 하루 144회 호출하는 정도라면 여유 있게 남습니다.

2. Schedule Trigger — 10분마다​

Trigger Interval을 Minutes, Minutes Between Triggers를 10으로 둡니다. 재고 알림 편의 1시간 간격보다 훨씬 촘촘한데, 응급실 병상은 몇 분 단위로 바뀌는 정보라 그만큼 자주 갱신할 가치가 있기 때문입니다.

3. HTTP Request — 인증키는 URL이 아니라 credential로​

원본 워크플로우는 인증키를 URL 쿼리 파라미터에 그대로 적어 뒀습니다. 실제 URL 형태는 이렇습니다.

https://apis.data.go.kr/B552657/ErmctInfoInqireService/getEmrrmRltmUsefulSckbdInfoInqire?serviceKey={API_KEY}&STAGE1=&STAGE2=&pageNo=1&numOfRows=500

이 방식은 워크플로우를 내보내거나 캔버스를 공유하는 순간 키가 그대로 노출됩니다. 지금 새로 만든다면 Authentication을 Generic Credential Type → Query Auth로 두고, Name에 serviceKey, Value에 발급받은 키를 넣는 credential을 만들어 URL에서 키 부분을 지우는 편이 안전합니다. 최소한으로 줄이더라도, 키만은 워크플로우 JSON 안이 아니라 별도 필드로 빼야 합니다.

나머지 파라미터는 API 자체의 조회 조건입니다. STAGE1·STAGE2는 시도·시군구 코드로, 비워두면 전국이 대상이 됩니다. pageNo=1·numOfRows=500은 500건을 한 페이지로 받겠다는 뜻이고, 이 워크플로우는 그 이상의 페이지를 넘기지 않습니다. 다음 편에서는 이 페이지네이션 자체를 다룹니다.

4. Split Out — 병원 배열을 아이템으로​

data.go.kr의 이 API는 응답 최상위가 response 하나로 감싸여 있고, 그 안의 body.items.item이 병원 목록 배열로 들어옵니다. Split Out 노드에서 Field To Split Out을 response.body.items.item으로 두면 병원 하나가 n8n 아이템 하나가 됩니다. 이후 노드들은 dutyName(병원명), hvidate(자료 갱신 시각), hv로 시작하는 병상·장비 가용 여부 필드를 그대로 씁니다.

5. Code — 숫자로 오는 컬럼을 문자열로​

Code 노드(Python, Run Once for All Items)를 하나 만들어 hvidate 컬럼값을 문자열로 바꿔줍니다.

items = _input.all()

for item in items:
item["json"]["hvidate"] = str(item["json"].get("hvidate", ""))

return items

hvidate는 API가 내려주는 자료 갱신 시각으로, 큰 자릿수의 정수 형태로 옵니다. 이 값을 숫자 그대로 시트에 넣으면 구글시트가 셀 서식을 자동으로 적용해 화면에 보이는 값이 원본과 달라질 수 있습니다. 문자열로 감싸두면 API가 준 값 그대로 시트에 남습니다.

6. Google Sheets — 적재 두 가지 방식​

Code 노드 뒤에는 같은 데이터를 시트에 넣는 방법 두 가지가 나란히 붙어 있고, 캔버스의 스티키 노트가 각각에 번호를 붙여뒀습니다.

1. 한번에 입력 — Insert 노드는 Operation을 Append or Update로, dutyName(병원명)을 matching column으로 둡니다. Split Out을 통과한 아이템 전체를 한 번의 노드 실행으로 시트에 씁니다. 이 앞에서 Clear 노드(Operation: Clear, Keep First Row 체크)가 시트를 먼저 비우기 때문에, 실질적으로 매번 최신 스냅샷으로 갈아 끼우는 구조가 됩니다.

2. 한 행씩 입력 — Loop Over Items(Split In Batches) 노드로 아이템을 하나씩 꺼내 Insert (One By One) 노드로 한 행씩 쓰고, Wait 노드로 짧게 쉬었다가 다음 아이템으로 넘어갑니다. 한 번에 입력보다 느리지만, 짧은 시간에 요청이 몰려 시트 API가 거부하는 상황을 피하고 싶을 때 쓰는 방식입니다.

7. 선택 — 원본 JSON을 파일로 보관​

Code 노드 출력은 Convert to File 노드로도 이어져 있습니다. 파일명이 .csv로 끝나는 걸 보면, 이 시점의 데이터를 CSV로 바꿔 AWS S3와 구글 드라이브 두 곳에 동시에 올려 아카이브해 두는 구조입니다. 시트는 스냅샷이라 과거 데이터가 사라지므로, 시계열로 남기고 싶다면 이 아카이브 branch가 필요합니다.

S3를 새로 붙인다면 비용을 확인해두는 게 좋습니다. AWS는 S3 표준 스토리지와 PUT 요청에 일정량의 무료 제공량을 두고 있는데, 계정을 만든 시점의 정책에 따라 조건이 다를 수 있어(AWS 공식 확인 필요) 정확한 한도는 콘솔에서 직접 확인하는 편이 안전합니다. 다만 이 워크플로우처럼 10분마다 파일 하나씩 올리면 한 달 PUT 요청이 4,000건을 넘습니다. 과거 계정 기준으로 흔히 알려진 무료 한도(월 2,000건)를 넘는 수치이므로, 아카이브 주기를 늘리거나 사용량을 확인해가며 켜는 편이 안전합니다.

원본 캔버스에 남아 있는 흔적​

이 워크플로우는 "Update History"라는 스티키 노트에 만든 사람이 바꾼 이력을 직접 적어뒀습니다. 그중 하나가 "숫자로 되어 있는 hvidate 컬럼 값을 문자열로 변환"입니다. 다만 내보낸 파일을 열어보면 그 의도를 구현한 Code 노드는 이름과 언어 설정(Python)만 남아 있고, 실제 코드 본문은 비어 있습니다. "무엇을 해야 하는지"는 캔버스에 남았지만 "어떻게"는 지워진 셈이라, 위 5번 단계의 코드는 그 의도를 그대로 구현한 것입니다.

또 하나는 적재 두 branch가 원본에는 Code 노드 출력에서 동시에 연결돼 있다는 점입니다. 스티키 노트에 붙은 번호(1, 2)로 보아 두 방식을 나란히 두고 비교해보라는 의도로 보이지만, 이 상태 그대로 워크플로우를 Active로 켜면 같은 데이터가 시트에 두 번 들어갑니다. 실습해보고 하나만 남긴 뒤 Active를 켜는 걸 권합니다.

한계​

  • 페이지네이션 없음 — numOfRows=500에서 멈추기 때문에, 대상 병원 수가 늘어나 500을 넘으면 뒤쪽 데이터가 잘립니다. 다음 편에서 다루는 페이지네이션으로 보완할 수 있습니다.
  • 시계열 없음 — Clear로 매번 비우는 스냅샷 구조라 "10분 전엔 병상이 몇 개였는지"는 시트에 남지 않습니다. 과거 이력이 필요하면 아카이브 CSV를 따로 쌓거나, Insert를 append 전용으로 바꾸고 타임스탬프 컬럼을 추가해야 합니다.
  • matching column이 병원명 — dutyName으로 매칭하는데, 동명 병원이 있으면 갱신이 엉킬 수 있습니다. 스키마에 있는 hpid(병원 고유 ID)를 matching column으로 쓰는 편이 더 안전해 보입니다.
  • 재시도 없음 — API 호출이 실패해도 별도 처리가 없습니다. Error Trigger 편에서 다룬 방식을 붙이는 걸 권합니다.

포트폴리오·면접 포인트​

같은 구조(HTTP Request → Split Out → 타입 정리 → Sheets 적재)를 다른 공공데이터 API로 바꿔 재현하면 바로 새 포트폴리오가 됩니다. 기상청 API, 서울 열린데이터광장 API 모두 같은 뼈대로 만들 수 있습니다.

면접에서는 "왜 시트를 매번 지우고 다시 채우나요?"라는 질문이 올 수 있습니다. 답은 이 API가 "현재 상태"를 보여주는 실시간 지표이기 때문에, 과거 값을 쌓기보다 최신 값만 정확히 보여주는 스냅샷이 목적에 맞는다는 것입니다. "왜 적재 방식을 두 가지 비교했나요?"라는 질문에는 속도(한번에)와 안정성(한 행씩) 사이의 트레이드오프를 직접 확인해본 경험으로 답하면 됩니다.

다음 액션​

같은 API 호출 구조에 페이지네이션이 더해지면 어떻게 되는지는 학교 급식 API 편에서 이어집니다. 이 편은 500건 한 페이지로 끝났지만, 다음 편은 데이터가 한 페이지에 다 안 들어올 때 페이지 번호를 늘려가며 끝까지 받아오는 법을 다룹니다.