Post

공공데이터포털 Open API 사용하기 with Python

본 문서는 Python으로 공공데이터포털의 API를 사용해 데이터를 수집하는 방법을 담고 있다.

공공데이터포털

공공데이터포털은 행정안전부에서 운영하는 공공데이터 통합제공 시스템이다. 대한민국 정부가 보유한 다양한 공공데이터를 개방하여 쉽게 활용할 수 있다.

1. 사용할 데이터의 API 키 발급 받기

공공데이터포털에서 원하는 데이터의 API 활용 신청을 통해 API Key를 발급받는다.

그림1

사용할 데이터의 상세 내용 또는 참고 문서의 활용가이드를 살펴보면, 요청 주소, 요청 변수, 요청 결과 를 확인할 수 있다. 요즘은 Swagger-UI를 제공하는 데이터들이 많아져 쉽게 테스트하고 요청 방법과 결과를 파악할 수 있다.

Python으로 API 데이터 불러오기

1. Libraries

필요한 library를 import 한다.

1
2
3
import json
import requests
import pandas as pd

2. API 요청 url 완성하기

1
2
3
# 데이터 요청 주소와 발급받은 API Key
url = 'http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList'
servicekey = 'servicekey'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 요청변수 채우기 > 변하는 값은 따로 정의하였다(반복문 등을 사용해 쉽게 처리할 수 있도록).
s_d = '20230101'
e_d = '20230105'
stn_Ids = 108

params = {
        "ServiceKey": servicekey,
        "pageNo": "1",
        "numOfRows": "720",
        "dataType": "JSON",
        "dataCd": "ASOS",
        "dateCd": "DAY",
        "startDt": s_d,
        "endDt": e_d,
        "stnIds": stn_Ids
}

3. API 요청 및 결과

1
response = requests.get(url, params=params)
1
2
3
4
5
6
# 요청에 성공하면 내용을 json 형태로 출력하도록
if response.status_code == 200:
        js = json.loads(response.content)
        print(js)
else:
        print(response.getcode())
1
{'response': {'header': {'resultCode': '00', 'resultMsg': 'NORMAL_SERVICE'}, 'body': {'dataType': 'JSON', 'items': {'item': [{'stnId': '108', 'stnNm': '서울', 'tm': '2023-01-01', 'avgTa': '-0.2', 'minTa': '-4.3', 'minTaHrmt': '2350', 'maxTa': '3.8', 'maxTaHrmt': '1343', 'mi10MaxRn': '', 'mi10MaxRnHrmt': '', 'hr1MaxRn': '', 'hr1MaxRnHrmt': '', 'sumRnDur': '', 'sumRn': '', 'maxInsWs': '8.1', 'maxInsWsWd': '290', 'maxInsWsHrmt': '1406', 'maxWs': '5.3', 'maxWsWd': '320', 'maxWsHrmt': '2135', 'avgWs': '2.7', 'hr24SumRws': '2314', 'maxWd': '270', 'avgTd': '-8.7', 'minRhm': '28', 'minRhmHrmt': '1656', 'avgRhm': '54.5', 'avgPv': '3.3', 'avgPa': '1019.8', 'maxPs': '1033.2', 'maxPsHrmt': '2253', 'minPs': '1028.6', 'minPsHrmt': '0137', 'avgPs': '1030.8', 'ssDur': '9.6', 'sumSsHr': '9.0', 'hr1MaxIcsrHrmt': '1200', 'hr1MaxIcsr': '1.87', 'sumGsr': '10.81', 'ddMefs': '', 'ddMefsHrmt': '', 'ddMes': '', 'ddMesHrmt': '', 'sumDpthFhsc': '', 'avgTca': '1.3', 'avgLmac': '1.1', 'avgTs': '-1.4', 'minTg': '-8.1', 'avgCm5Te': '-0.2', 'avgCm10Te': '-0.5', 'avgCm20Te': '-0.5', 'avgCm30Te': '0.6', 'avgM05Te': '2.8', 'avgM10Te': '6.3', 'avgM15Te': '10.1', 'avgM30Te': '15.9', 'avgM50Te': '18.0', 'sumLrgEv': '1.6', 'sumSmlEv': '2.3', 'n99Rn': '', 'iscs': '{연무}0125-{연무}{강도0}0300-0450. {연무}0550-{연무}{강도0}0600-{연무}{강도0}0900-1030.', 'sumFogDur': ''}, {'stnId': '108', 'stnNm': '서울', 'tm': '2023-01-02', 'avgTa': '-4.5', 'minTa': '-7.4', 'minTaHrmt': '0804', 'maxTa': '-0.4', 'maxTaHrmt': '1525', 'mi10MaxRn': '', 'mi10MaxRnHrmt': '', 'hr1MaxRn': '', 'hr1MaxRnHrmt': '', 'sumRnDur': '', 'sumRn': '', 'maxInsWs': '7.4', 'maxInsWsWd': '250', 'maxInsWsHrmt': '1501', 'maxWs': '4.4', 'maxWsWd': '290', 'maxWsHrmt': '1307', 'avgWs': '2.5', 'hr24SumRws': '2176', 'maxWd': '270', 'avgTd': '-14.6', 'minRhm': '32', 'minRhmHrmt': '1543', 'avgRhm': '45.9', 'avgPv': '2.0', 'avgPa': '1021.0', 'maxPs': '1034.0', 'maxPsHrmt': '1005', 'minPs': '1030.3', 'minPsHrmt': '1521', 'avgPs': '1032.2', 'ssDur': '9.6', 'sumSsHr': '9.1', 'hr1MaxIcsrHrmt': '1200', 'hr1MaxIcsr': '1.99', 'sumGsr': '11.63', 'ddMefs': '', 'ddMefsHrmt': '', 'ddMes': '', 'ddMesHrmt': '', 'sumDpthFhsc': '', 'avgTca': '0.0', 'avgLmac': '0.0', 'avgTs': '-4.2', 'minTg': '-13.4', 'avgCm5Te': '-0.9', 'avgCm10Te': '-1.0', 'avgCm20Te': '-0.5', 'avgCm30Te': '0.6', 'avgM05Te': '2.7', 'avgM10Te': '6.2', 'avgM15Te': '9.9', 'avgM30Te': '15.8', 'avgM50Te': '17.9', 'sumLrgEv': '1.3', 'sumSmlEv': '1.9', 'n99Rn': '', 'iscs': '', 'sumFogDur': ''}, {'stnId': '108', 'stnNm': '서울', 'tm': '2023-01-03', 'avgTa': '-5.0', 'minTa': '-9.0', 'minTaHrmt': '0551', 'maxTa': '0.6', 'maxTaHrmt': '1555', 'mi10MaxRn': '', 'mi10MaxRnHrmt': '', 'hr1MaxRn': '', 'hr1MaxRnHrmt': '', 'sumRnDur': '', 'sumRn': '', 'maxInsWs': '6.7', 'maxInsWsWd': '290', 'maxInsWsHrmt': '1459', 'maxWs': '3.9', 'maxWsWd': '320', 'maxWsHrmt': '1304', 'avgWs': '1.8', 'hr24SumRws': '1542', 'maxWd': '270', 'avgTd': '-14.6', 'minRhm': '27', 'minRhmHrmt': '1416', 'avgRhm': '49.0', 'avgPv': '2.0', 'avgPa': '1019.5', 'maxPs': '1032.1', 'maxPsHrmt': '0306', 'minPs': '1028.7', 'minPsHrmt': '1500', 'avgPs': '1030.7', 'ssDur': '9.7', 'sumSsHr': '9.1', 'hr1MaxIcsrHrmt': '1200', 'hr1MaxIcsr': '2.0', 'sumGsr': '11.77', 'ddMefs': '', 'ddMefsHrmt': '', 'ddMes': '', 'ddMesHrmt': '', 'sumDpthFhsc': '', 'avgTca': '0.0', 'avgLmac': '0.0', 'avgTs': '-4.8', 'minTg': '-16.4', 'avgCm5Te': '-1.5', 'avgCm10Te': '-1.5', 'avgCm20Te': '-0.8', 'avgCm30Te': '0.5', 'avgM05Te': '2.6', 'avgM10Te': '6.1', 'avgM15Te': '9.8', 'avgM30Te': '15.7', 'avgM50Te': '17.9', 'sumLrgEv': '1.3', 'sumSmlEv': '1.9', 'n99Rn': '', 'iscs': '', 'sumFogDur': ''}, {'stnId': '108', 'stnNm': '서울', 'tm': '2023-01-04', 'avgTa': '-1.8', 'minTa': '-5.7', 'minTaHrmt': '0229', 'maxTa': '3.3', 'maxTaHrmt': '1510', 'mi10MaxRn': '', 'mi10MaxRnHrmt': '', 'hr1MaxRn': '', 'hr1MaxRnHrmt': '', 'sumRnDur': '', 'sumRn': '', 'maxInsWs': '7.2', 'maxInsWsWd': '320', 'maxInsWsHrmt': '1256', 'maxWs': '4.2', 'maxWsWd': '290', 'maxWsHrmt': '1238', 'avgWs': '1.9', 'hr24SumRws': '1644', 'maxWd': '270', 'avgTd': '-10.7', 'minRhm': '34', 'minRhmHrmt': '1517', 'avgRhm': '51.4', 'avgPv': '2.7', 'avgPa': '1019.5', 'maxPs': '1031.5', 'maxPsHrmt': '1014', 'minPs': '1029.5', 'minPsHrmt': '1459', 'avgPs': '1030.5', 'ssDur': '9.7', 'sumSsHr': '8.7', 'hr1MaxIcsrHrmt': '1200', 'hr1MaxIcsr': '1.91', 'sumGsr': '10.89', 'ddMefs': '', 'ddMefsHrmt': '', 'ddMes': '', 'ddMesHrmt': '', 'sumDpthFhsc': '', 'avgTca': '1.9', 'avgLmac': '1.9', 'avgTs': '-2.9', 'minTg': '-13.9', 'avgCm5Te': '-1.1', 'avgCm10Te': '-1.2', 'avgCm20Te': '-0.8', 'avgCm30Te': '0.3', 'avgM05Te': '2.5', 'avgM10Te': '6.0', 'avgM15Te': '9.7', 'avgM30Te': '15.6', 'avgM50Te': '17.9', 'sumLrgEv': '1.5', 'sumSmlEv': '2.1', 'n99Rn': '', 'iscs': '', 'sumFogDur': ''}, {'stnId': '108', 'stnNm': '서울', 'tm': '2023-01-05', 'avgTa': '-1.6', 'minTa': '-5.6', 'minTaHrmt': '0749', 'maxTa': '3.6', 'maxTaHrmt': '1536', 'mi10MaxRn': '', 'mi10MaxRnHrmt': '', 'hr1MaxRn': '', 'hr1MaxRnHrmt': '', 'sumRnDur': '', 'sumRn': '', 'maxInsWs': '5.6', 'maxInsWsWd': '230', 'maxInsWsHrmt': '1553', 'maxWs': '3.2', 'maxWsWd': '200', 'maxWsHrmt': '1558', 'avgWs': '1.6', 'hr24SumRws': '1386', 'maxWd': '20', 'avgTd': '-8.9', 'minRhm': '39', 'minRhmHrmt': '1554', 'avgRhm': '58.1', 'avgPv': '3.1', 'avgPa': '1019.6', 'maxPs': '1032.3', 'maxPsHrmt': '0945', 'minPs': '1029.2', 'minPsHrmt': '2059', 'avgPs': '1030.6', 'ssDur': '9.7', 'sumSsHr': '4.7', 'hr1MaxIcsrHrmt': '1100', 'hr1MaxIcsr': '1.06', 'sumGsr': '6.09', 'ddMefs': '', 'ddMefsHrmt': '', 'ddMes': '', 'ddMesHrmt': '', 'sumDpthFhsc': '', 'avgTca': '3.6', 'avgLmac': '1.6', 'avgTs': '-3.3', 'minTg': '-12.5', 'avgCm5Te': '-1.0', 'avgCm10Te': '-1.1', 'avgCm20Te': '-0.8', 'avgCm30Te': '0.2', 'avgM05Te': '2.4', 'avgM10Te': '5.9', 'avgM15Te': '9.5', 'avgM30Te': '15.5', 'avgM50Te': '17.8', 'sumLrgEv': '0.9', 'sumSmlEv': '1.2', 'n99Rn': '', 'iscs': '', 'sumFogDur': ''}]}, 'pageNo': 1, 'numOfRows': 720, 'totalCount': 5}}}

4. JSON to DataFrame

필요한 값만 추출하여, 각 기상요소를 column으로 갖는 데이터프레임을 만든다.

1
2
3
4
5
6
7
8
# 결과가 정상적으로(200) 받아지면 다음 작업을 수행하도록 함
 if response.status_code == 200:
        js = json.loads(response.content)
        item = js['response']['body']['items']['item']
        df = pd.DataFrame(item)
        display(df)
else:
        print(response.getcode())
stnIdstnNmtmavgTaminTaminTaHrmtmaxTamaxTaHrmtmi10MaxRnmi10MaxRnHrmt...avgM05TeavgM10TeavgM15TeavgM30TeavgM50TesumLrgEvsumSmlEvn99RniscssumFogDur
0108서울2023-01-01-0.2-4.323503.81343...2.86.310.115.918.01.62.3{연무}0125-{연무}{강도0}0300-0450. {연무}0550-{연무}{강도0...
1108서울2023-01-02-4.5-7.40804-0.41525...2.76.29.915.817.91.31.9
2108서울2023-01-03-5.0-9.005510.61555...2.66.19.815.717.91.31.9
3108서울2023-01-04-1.8-5.702293.31510...2.56.09.715.617.91.52.1
4108서울2023-01-05-1.6-5.607493.61536...2.45.99.515.517.80.91.2

5 rows × 62 columns

This post is licensed under CC BY 4.0 by the author.