kpublic
한국 공공데이터포털(data.go.kr) API를 함정 없이 쓰는 파이썬 SDK.
포털에서 키를 받고 처음 API를 붙이면 거의 모두가 같은 곳에서 넘어진다.
인코딩 키를 넣어서 SERVICE_KEY_IS_NOT_REGISTERED_ERROR, JSON을 요청했는데 XML 에러가 와서 json.loads 크래시,
HTTP 200인데 본문 resultCode는 실패, 데이터 없음이 items: ""로 오는 것, 기상청 격자 좌표…
kpublic은 그 함정들을 코어에서 전부 처리하고, 자주 쓰는 API는 어댑터로 감싼다.
pip install kpublic
import kpublic
c = kpublic.Client("포털에서 복사한 키") # 인코딩 키든 디코딩 키든 그대로 붙여넣으면 된다
# 어댑터 — 서울시청 지금 날씨
kma = kpublic.kma.Forecast(c)
now = kma.ultra_now(lat=37.5665, lon=126.9780) # 격자 변환·발표시각 계산 자동
now.values # {'T1H': 23.1, 'RN1': 0.0, 'REH': 78.0, 'PTY': 0.0, ...}
now.label("T1H") # '기온(℃)'
# 어댑터 — 미세먼지 / 공휴일
kpublic.airkorea.AirKorea(c).by_sido("서울")[0].pm25 # 18.0 (결측 '-'는 None)
kpublic.holidays.Holidays(c).get(2026, 9) # [Holiday(date=2026-09-24, name='추석', ...), ...]
# 범용 — 어떤 data.go.kr API든 경로만 알면 된다
r = c.get("1360000/AsosDalyInfoService/getWthrDataList",
dataCd="ASOS", dateCd="DAY", startDt="20260901", endDt="20260907", stnIds=108, dataType="JSON")
r.items, r.total_count
# 자동 페이징 — totalCount 보고 끝까지
for row in c.iter_items("B552584/ArpltnInfrqncyInqireSvc/getCtprvnRltmMesureDnsty",
sidoName="전국", returnType="json", ver="1.3", page_size=100):
...
코어가 대신 처리하는 것
| 함정 | kpublic |
|---|---|
인코딩 키(%2B…)를 넣으면 두 번 인코딩돼 30번 에러 |
어느 형태든 원본 키로 정규화 → 전송선엔 정확히 한 번 인코딩 |
실패해도 HTTP 200, 사유는 본문 resultCode |
코드별 예외: ServiceKeyError(21/30/31) RateLimitError(22) UnregisteredIPError(32) InvalidParameterError(10/11) AccessDeniedError(12/20/33) ServerError(01/02/04/05/99) |
| JSON 요청해도 게이트웨이 에러는 XML | 첫 글자 보고 자동 판별, OpenAPI_ServiceResponse/cmmMsgHeader 봉투 해석 |
items가 "" / null / 누락 / dict 하나 / list |
전부 list[dict] |
| 데이터 없음(03)이 예외인가 | 기본은 빈 Response(총건수 0). raise_on_nodata=True면 NoDataError |
| 페이징 수동 | iter_items() — totalCount가 없어도 짧은 페이지에서 멈춤 |
| 서버 일시 장애 | 5xx·타임아웃·01/02/04/05/99만 지수 백오프 재시도. 22(일일 초과)·키 오류는 재시도하지 않는다 — 해봐야 소용없고 트래픽만 태운다 |
어댑터
| 모듈 | API | 제공 |
|---|---|---|
kpublic.kma |
기상청 단기예보 2.0 | Forecast.ultra_now / ultra_forecast / village, latlon_to_grid, grid_to_latlon, latest_base_time(발표시각 규칙) |
kpublic.airkorea |
에어코리아 대기오염정보 | AirKorea.by_sido / by_station → AirQuality(결측 None, 등급 라벨) |
kpublic.holidays |
천문연 특일정보 | Holidays.get(year, month=None), is_holiday(date) |
어댑터가 없는 API는 Client.get(path, **params)로 그대로 부른다. 코어의 함정 처리는 똑같이 적용된다.
활용신청은 API마다 따로
키는 계정당 하나지만 API마다 활용신청을 해야 한다(대부분 자동승인). 안 하면 ServiceKeyError(30).
- 기상청 단기예보 — https://www.data.go.kr/data/15084084/openapi.do
- 에어코리아 대기오염 — https://www.data.go.kr/data/15073861/openapi.do
- 천문연 특일정보 — https://www.data.go.kr/data/15012690/openapi.do
신청 후 확인: KPUBLIC_SERVICE_KEY=발급키 python scripts/smoke.py
검증 상태 (0.1.0, 2026-09-09)
| 항목 | 방법 | 결과 |
|---|---|---|
| 코어 전 경로 · 어댑터 파싱 · 격자 기준값 | 단위 테스트 82개, httpx.MockTransport |
✅ |
기상청 ultra_now (서울시청) |
실서버 | ✅ T1H 24.0 · REH 59 · WSD 5.0 … 8개 카테고리 |
에어코리아 by_sido("서울") |
실서버 | ✅ 측정소 40곳, "-" 결측 → None 확인 |
천문연 Holidays.get(2026) |
실서버 (두 번째 키) | ✅ 공휴일 22일 |
인코딩 키(%2B…) 그대로 넣기 |
실서버 (두 번째 키는 인코딩 형태로 입력) | ✅ 정규화 후 정상 인증 |
| 게이트웨이 오류가 HTTP 400/403 + JSON 봉투로 오는 경우 | 실서버에서 발견 → 테스트 5개 추가 | ✅ ServiceKeyError(30) / AccessDeniedError(12) 매핑 |
| 미신청 API 호출 | 실서버 (각 키가 미신청인 API로) | ✅ ServiceKeyError(30) + 활용신청 링크 안내 |
키 두 개(각각 다른 API에 신청됨)로 나눠 찍어 어댑터 3종 모두 happy path를 실서버에서 확인했다.
실서버 검증에서 잡힌 것 2건: 게이트웨이 오류의 4xx 처리 순서, 에어코리아 서비스 ID 오타(ArpltnInfrqncy… → ArpltnInforInqireSvc). 둘 다 단위 테스트만으로는 못 잡는 종류다.
개발
uv sync --group dev
uv run pytest
uv run ruff check . && uv run mypy src
uv build
배포
토큰 없이 PyPI Trusted Publishing으로 배포한다. pyproject.toml·__init__.py 버전을 올리고 CHANGELOG에 항목을 추가한 뒤:
git tag v0.2.0 && git push origin v0.2.0
release.yml이 태그와 버전이 일치하는지 확인하고 테스트 → 빌드 → 업로드까지 한다.
로드맵
- 0.2 —
AsyncClient(같은 코어), 응답 캐시(sqlite), 기상청 ASOS·중기예보, 한강홍수통제소 - 0.3 — pandas/polars 변환 헬퍼, CLI
라이선스
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kpublic-0.1.1.tar.gz.
File metadata
- Download URL: kpublic-0.1.1.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
599f7586c78a4b98070f02b7a2465fc6ecfa09d2d1890494057fef9baf4e883c
|
|
| MD5 |
0abcd8ba27bf3e6e23c2aab52c84dc61
|
|
| BLAKE2b-256 |
8a33febe63070daff76ad437cda4aa11dcbee89d033f486454248e1ecb870e5c
|
Provenance
The following attestation bundles were made for kpublic-0.1.1.tar.gz:
Publisher:
release.yml on HyaC1107/kpublic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kpublic-0.1.1.tar.gz -
Subject digest:
599f7586c78a4b98070f02b7a2465fc6ecfa09d2d1890494057fef9baf4e883c - Sigstore transparency entry: 2763681689
- Sigstore integration time:
-
Permalink:
HyaC1107/kpublic@2b4c7ca20e633c40b3d46bfe8c3e8e5d424aec51 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/HyaC1107
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2b4c7ca20e633c40b3d46bfe8c3e8e5d424aec51 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kpublic-0.1.1-py3-none-any.whl.
File metadata
- Download URL: kpublic-0.1.1-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39d52180de3f5fcbd355bc47b88bed38e72e292d3ccda3dd6a198063885ce591
|
|
| MD5 |
e96d169cf3c5b8f2f5a2141d09558510
|
|
| BLAKE2b-256 |
636bd0b4df3c35ecd9c6d27425cee475f2dae8fe100391a196a5784521c449ae
|
Provenance
The following attestation bundles were made for kpublic-0.1.1-py3-none-any.whl:
Publisher:
release.yml on HyaC1107/kpublic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kpublic-0.1.1-py3-none-any.whl -
Subject digest:
39d52180de3f5fcbd355bc47b88bed38e72e292d3ccda3dd6a198063885ce591 - Sigstore transparency entry: 2763681692
- Sigstore integration time:
-
Permalink:
HyaC1107/kpublic@2b4c7ca20e633c40b3d46bfe8c3e8e5d424aec51 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/HyaC1107
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2b4c7ca20e633c40b3d46bfe8c3e8e5d424aec51 -
Trigger Event:
push
-
Statement type: