2026. 8. 4. 11:09ㆍ파이썬
목차
- 글 요약
- 왜 이 샘플을 만들었나
- 사용한 공공데이터
- 기술 스택
- 프로젝트 구조
- 환경 변수 설정
- 실행 방법
- 이메일 공유 방식
- 오류 처리 기준
- 테스트
- 구현하면서 신경 쓴 점
- 마무리
글 요약
공공데이터 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와 파라미터, 응답 파싱 부분만 바꾸면 비슷한 흐름으로 확장할 수 있다.
'파이썬' 카테고리의 다른 글
| 공공데이터포털 오픈 API 신청 및 활용 가이드 (0) | 2026.08.04 |
|---|---|
| Python에서 Gmail SMTP 사용하기 (0) | 2026.08.04 |
| 텔레그램 봇으로 Google Calendar 일정 관리하기 (0) | 2026.07.25 |
| 파이썬으로 텔레그램 Echo Bot 만들기 (0) | 2026.07.25 |
| 텔레그램 봇으로 Google Calendar 일정 등록하기 (0) | 2026.07.25 |