공공데이터 API 연동 샘플 만들기: 기상청 단기예보 API를 Python으로 호출하고 Gmail로 공유하기

2026. 8. 4. 11:09파이썬

목차

  1. 글 요약
  2. 왜 이 샘플을 만들었나
  3. 사용한 공공데이터
  4. 기술 스택
  5. 프로젝트 구조
  6. 환경 변수 설정
  7. 실행 방법
  8. 이메일 공유 방식
  9. 오류 처리 기준
  10. 테스트
  11. 구현하면서 신경 쓴 점
  12. 마무리

글 요약

공공데이터 API를 처음 연동할 때는 "API를 어떻게 호출하지?"에서 끝나지 않는다. 실제로는 인증키 관리, 조회 파라미터 구성, 오류 처리, 결과 저장, 주기적 실행, 공유 방식까지 함께 고민해야 한다.

이 글에서는 기상청_단기예보 조회서비스를 예시로 Python 샘플 프로젝트를 구성한 과정을 정리한다. 목표는 운영용 완성 서비스가 아니라, 공공데이터 API를 어떻게 호출하고 활용하는지 소스 코드로 이해할 수 있는 학습용 샘플이다.


왜 이 샘플을 만들었나

공공데이터 API를 사용하려는 사람은 보통 다음 지점에서 막힌다.

  • 서비스키를 어디에 넣어야 하는지
  • 어떤 endpoint와 파라미터를 호출해야 하는지
  • 응답이 비었는지, 오류인지 어떻게 구분해야 하는지
  • 결과를 파일로 남기려면 어떤 구조가 좋은지
  • 주기적으로 조회하려면 어떻게 실행해야 하는지
  • 조회 결과를 다른 사람에게 공유하려면 어떻게 해야 하는지

그래서 이번 샘플은 단순 호출 예제보다 조금 더 실제 흐름에 가깝게 구성했다.

API 설정 입력
-> 공공데이터 API 호출
-> API 응답 수신
-> 결과 변환
-> 콘솔 출력
-> 로컬 JSON 파일 저장
-> HTML 이메일 공유

사용한 공공데이터

대상 API는 기상청_단기예보 조회서비스다.

서비스: 기상청_단기예보 조회서비스
방식: REST
응답 포맷: JSON 우선 사용
Endpoint:
https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst

샘플 기본 조회값은 다음처럼 잡았다.

파라미터 기본값 설명

pageNo 1 첫 페이지
numOfRows 1000 단기예보 항목을 충분히 받기 위한 샘플 행 수
dataType JSON JSON 응답 사용
base_date 실행일 기준 YYYYMMDD 형식
base_time 자동 선택 최신 사용 가능 발표시각
nx 60 서울 시청 인근 격자 X
ny 127 서울 시청 인근 격자 Y

base_time은 고정값으로 두지 않고 실행 시각 기준으로 자동 계산했다. 후보는 다음과 같다.

0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300

각 발표시각 10분 이후부터 사용할 수 있다고 보고, 아직 당일 첫 발표 전이면 전날 2300을 사용하도록 했다.


기술 스택

이번 샘플은 UI 없는 로컬 실행 예제다.

영역 선택

Runtime Python 3.12
API Client requests
환경 변수 python-dotenv
스케줄링 APScheduler
저장 로컬 JSON 파일
이메일 Gmail SMTP, smtplib, email.message
테스트 pytest

화면을 만드는 대신 코드 실행 결과, 저장 파일, 이메일 본문으로 흐름을 보여주는 데 집중했다.


프로젝트 구조

핵심 소스 구조는 다음과 같다.

src/open_data_sample/
  cli.py             # 실행 진입점
  config.py          # .env 설정 로딩
  forecast_time.py   # base_date/base_time 자동 계산
  weather_client.py  # 기상청 단기예보 API 호출과 응답 파싱
  presenter.py       # 콘솔 요약과 HTML 메일 본문 생성
  repository.py      # JSON 파일 저장
  email_share.py     # Gmail SMTP 전송
  service.py         # 전체 실행 흐름 조립
  errors.py          # 오류 코드와 사용자 안내 메시지

구조를 나눈 이유는 API 호출, 결과 변환, 저장, 이메일 공유 책임을 분리하기 위해서다. 학습용 샘플이어도 한 파일에 모두 넣으면 흐름을 이해하기 어려워진다.


환경 변수 설정

실제 API 키와 Gmail 앱 비밀번호는 코드에 넣지 않고 .env로 분리했다.

.env.example 예시는 다음과 같다.

PUBLIC_DATA_SERVICE_KEY=your-public-data-service-key

WEATHER_NX=60
WEATHER_NY=127
WEATHER_NUM_OF_ROWS=1000
WEATHER_PAGE_NO=1
WEATHER_DATA_TYPE=JSON
WEATHER_TIMEOUT_SECONDS=10
MONITOR_INTERVAL_SECONDS=3600

OUTPUT_DIR=data

GMAIL_SMTP_HOST=smtp.gmail.com
GMAIL_SMTP_PORT=587
GMAIL_USERNAME=your-gmail-address@gmail.com
GMAIL_APP_PASSWORD=your-gmail-app-password
EMAIL_FROM=your-gmail-address@gmail.com
EMAIL_TO=recipient@example.com
EMAIL_SUBJECT=기상청 단기예보 조회 결과
EMAIL_ATTACH_JSON=false

주의할 점은 Gmail 비밀번호다. 일반 계정 비밀번호가 아니라 Gmail 앱 비밀번호를 사용해야 한다.


실행 방법

의존성을 설치한다.

python -m pip install -e ".[dev]"

단발 조회를 실행한다.

python -m open_data_sample.cli

성공하면 콘솔에 요약이 출력되고 data/ 아래에 JSON 파일이 저장된다.

예시 출력:

기상청 단기예보 조회 성공
- 발표일자/시각: 20260804 0800
- 격자: nx=60, ny=127
- 항목 수: 871 / totalCount=871
- 카테고리: PCP, POP, PTY, REH, SKY, SNO, TMN, TMP, TMX, UUU, VEC, VVV, WAV, WSD
- 저장 파일: data\forecast_20260804_100048.json
- 이메일 전송: 건너뜀

이메일까지 보내려면 다음처럼 실행한다.

python -m open_data_sample.cli --send-email

주기적 모니터링 흐름을 확인하려면 다음 옵션을 사용한다.

python -m open_data_sample.cli --monitor

반복 간격은 .env의 MONITOR_INTERVAL_SECONDS로 조정한다.


이메일 공유 방식

처음에는 저장된 JSON 파일을 그대로 첨부하는 방식도 생각했다. 하지만 수신자 입장에서 원본 JSON 파일은 바로 읽기 어렵다.

그래서 기본 동작은 HTML 요약 메일로 바꿨다.

메일 본문에는 다음 정보가 들어간다.

  • 발표일자와 발표시각
  • 조회 격자
  • 조회 항목 수
  • 저장 시각
  • 가까운 예보 시간별 주요 항목 표

원본 JSON 첨부는 기본적으로 끈다.

EMAIL_ATTACH_JSON=false

원본 파일도 같이 보내고 싶을 때만 다음처럼 바꾼다.

EMAIL_ATTACH_JSON=true

이렇게 하면 HTML 요약 본문은 그대로 보내고, 원본 JSON 파일도 첨부한다.


오류 처리 기준

샘플에서는 오류를 한 덩어리로 처리하지 않고 코드로 구분했다.

코드 의미

API_AUTH_ERROR API 인증키 또는 권한 문제
API_REQUEST_ERROR API 호출 실패
API_EMPTY_RESULT 호출은 성공했지만 결과 없음
API_TIMEOUT 응답 지연 또는 타임아웃
API_SCHEMA_CHANGED 응답 형식 변경
FILE_WRITE_ERROR 파일 저장 실패
EMAIL_SEND_ERROR 이메일 전송 실패

CLI에서는 오류 코드, 사용자가 할 수 있는 조치, 재시도 가능 여부를 함께 보여준다.


테스트

테스트는 pytest로 작성했다.

python -m pytest

검증한 내용은 다음과 같다.

  • base_time 자동 선택
  • 공공데이터 API 응답 파싱
  • 빈 결과와 API 오류 구분
  • 로컬 JSON 저장
  • HTML 이메일 본문 생성
  • JSON 첨부 기본 비활성화
  • EMAIL_ATTACH_JSON=true일 때만 첨부

현재 테스트 결과는 다음과 같다.

13 passed

구현하면서 신경 쓴 점

1. 비밀값은 Git에 올리지 않는다

.env는 .gitignore에 넣고, .env.example만 공유한다. API 키, Gmail 앱 비밀번호, 수신자 같은 실제 값은 공개 문서와 로그에도 남기지 않는다.

2. 서비스키 인코딩 문제를 고려한다

공공데이터포털 서비스키는 인코딩된 키를 복사하는 경우가 있다. 그래서 설정 로딩 시 unquote를 적용해 인코딩된 키도 자연스럽게 처리하도록 했다.

3. 수신자가 읽을 수 있는 결과를 보낸다

원본 JSON은 개발자에게는 유용하지만 일반 수신자에게는 불편하다. 그래서 기본 공유 방식은 HTML 본문으로 정리하고, JSON 첨부는 선택 옵션으로 뺐다.

4. 운영용 서비스와 샘플의 경계를 분리한다

이 프로젝트는 학습용 샘플이다. 운영 환경용 권한 관리, 대규모 저장소, 고급 알림, 배포 자동화는 의도적으로 제외했다.


마무리

공공데이터 API 연동은 단순히 requests.get() 한 줄로 끝나지 않는다. 실제로 공유 가능한 샘플을 만들려면 설정 관리, 파라미터 계산, 오류 구분, 저장, 이메일 공유, 테스트까지 함께 정리해야 한다.

이번 샘플은 기상청 단기예보 API를 기준으로 만들었지만, 구조 자체는 다른 공공데이터 API에도 응용할 수 있다. endpoint와 파라미터, 응답 파싱 부분만 바꾸면 비슷한 흐름으로 확장할 수 있다.

weather_api_sample.md.pdf
0.36MB