파이썬에서 오픈 API를 사용하면 더 다양한 데이터를 처리하고 서비스를 제공할 수 있습니다. 다양한 API들중 공공데이터포털(DATA.GO.KR)에 접속해보면 사이트내에서 제공하는 다양한 종류의 데이터가 있습니다.
파이썬에서 공공데이터포털이 제공하는 기상청 API를 사용하여 일기예보 형식의 현재 기온을 알아보도록 하겠습니다.
파이썬을 통해 공공데이터의 날씨API를 사용하면 오늘의 날씨를 텔레그램 메신저나 카카오톡 등에서 조회할 수도 있으며 요즘 핫한 AI에 기능을 추가하여 음성으로 질문하면 오늘의 날씨를 알려주는 등 다양하게 활용할 수 있습니다.
공공데이터포털 기상청 API활용 신청
먼저 사용할 API를 찾아보겠습니다. 공공데이터포털에 접속하여 데이터 목록을 확인해보면 현재 약 1만여개의 오픈API를 제공하고 있습니다.
각 데이터들은 분류별로 조건을 검색할 수 있으며 찾는 공공데이터를 직접 검색할 수도 있습니다.
공공데이터포털에서 인기가많은 데이터중에 기상청 데이터 API를 사용할 예정입니다.
API를 바로 사용할수는 없고 먼저 활용신청을하여 개인 key를 발급받아야합니다.
data.go.kr에 가입되어있지 않다면 먼저 가입을한뒤, 로그인하여 '활용신청'버튼을 클릭합니다.
활용목적에 맞게 작성한뒤 첨부파일은 선택사항이며 하단에 라이선스를 확인하여 동의한후 활용신청을하면 자동으로 승인이됩니다.
신청한 api의 승인여부 및 키를 확인하기 위해 '마이페이지' - 'API'신청으로 이동합니다.
API목록을 확인해보면 제목앞에 [승인]이라고 표시됩니다. 이제 해당 API를 자신의 서비스에서 사용할 수 있습니다.
승인된 API를 클릭해서 들어가보면 활용가능 기간과 자신의 고유 key가 발급됩니다. 파이썬에서 사용할때는 일반 인증키(Decoding)부분을 사용합니다.
단기예보 API 출력 테스트
'마이페이지'의 'API신청' 버튼을 클릭한뒤 승인된 API를 선택하여 페이지를 조금 내려보면 API를 사용한 결과값을 미리볼 수 있습니다.
4가지의 기능이 있는데 단기예보를 클릭합니다. 요청을위해 필요한 데이터를 입력해줘야합니다.
입력값에 대한 내용은 오픈API 상세페이지에서 참고문서를 제공하고있습니다.
ServiceKey는 발급받은 키중에서 일반인증키(Encoding)키를 넣어줘야 합니다.
base_date는 오늘 날짜를 입력해야 합니다. 포스팅 작성기준 날짜 20231217를 입력하겠습니다.
base_time은 정시단위로 발표시각을 말하는건데 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 1일 8회 발표하며 이 시각중 하나를 입력하면 됩니다.(참고문서 Base_time) 저는 기본값으로 설정되어있는 0500을 그대로 입력하겠습니다.
발표시간 이외의 값을 넣게되면 데이터가 나오지않습니다.
nx,ny값은 참고문서의 엑셀파일을 참고하여 측정을 원하는 지역정보의 위경도 정보를 입력하면됩니다.
미리보기 버튼을 클릭하면 웹페이지가 열리면서 XML형태로 데이터가 출력됩니다.
dataType을 XML이 아닌 JSON으로 설정하면 JSON형태로도 데이터가 출력됩니다.
반복되어 출력되는 결과중 category 부분이 TMP,UUU,VVV등 다른걸 확인할 수 있는데 이는 참고문서의 내용을 확인해보면 알 수 있습니다. 모든 정보를 가져올필요없고 저희는 1시간 기온인 TMP부분만 확인해보겠습니다.
TMP카테고리의 fcstValue값이 예보 값을 의미하며 실수 또는 정수값으로 제공됩니다.(참고문서 내용확인)
즉 23년12월17일 오전6시의 기온이 -12도라는걸 확인할 수 있습니다.
파이썬에서 API 사용하기
API상세 페이지에서 하단으로 내려보면 다양한 언어로 샘플코드가 제공됩니다.
해당코드에서 우선적으로 확인할게 url과 params인데 url부터 살펴보겠습니다.
단기예보API에서는 아까 4개의 미리보기가 가능한 기능을 제공하는걸 알수 있었는데 저희는 단기예보조회 url로 api를 요청해야합니다.
Python샘플코드에서 url값을 사용하고자하는 기능의 요청url로 변경해줍니다.
참고문서의 hwp파일에서 내용을 확인해보면 단기예보조회는 요청 url이 getVilbageFcst로 끝납니다.
params에는 serviceKey는 웹사이트에서 미리보기를 할때 입력했던 Encoding키가 아닌 Decoding키를 입력합니다. base_date를 오늘로 변경해주고 nx,ny는 참고문서의 엑셀파일을 참고하여 원하는 지역의 위치데이터를 입력해줍니다.
예제코드를 수정하여 vscode에서 실행해보면 결과값이 나오긴하는데 웹에서 봤을때보다 가독성이 많이 떨어집니다.
JSON으로 데이터 수정하기
xml데이터를 json데이터로 변환하면 파이썬에서 결과를보기 더 편합니다.
json으로 변환하려면 xmltodict라는 모듈을 설치합니다.
pip install xmltodict
import requests
import xmltodict
import json
url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst'
params ={'serviceKey' : 'your key', 'pageNo' : '1', 'numOfRows' : '1000', 'dataType' : 'XML', 'base_date' : '20231218', 'base_time' : '0500', 'nx' : '55', 'ny' : '127' }
response = requests.get(url, params=params)
xmlData = response.text # xml데이터
jsonStr = json.dumps(xmltodict.parse(xmlData), indent=4) # xml to json
dict = json.loads(jsonStr)
print(dict['response']['body']['items']['item'])
이후에 json데이터변환에 대해 자세히 정리되어있는 hellodoor블로그의 코드를 참고하여 json데이터로 변환하였습니다.
코드를 잠시 설명하자면 response.text에는 xml데이터가 담겨져 있으며, json.dumps(xmltodict.parse(변환할xml데이터가 담긴변수)로 xml을 json으로 변환합니다.
json.loads로 변환한 json파일을 넣어줘야 작성한 print문처럼 key값으로 접근이 가능합니다.
다시 출력해보면 웹에서 봤던것처럼 baseDate와 basetime, category등 알아볼수있게 출력이됩니다.
리스트에 넣어 가독성 높이기
for item in dict["response"]["body"]["items"]["item"]:
result= []
result.append({
"날짜" : item["fcstDate"][:4] + "년" + item["fcstDate"][4:6] + "월" + item["fcstDate"][6:] + "일",
"시간대" : item["fcstTime"][:2]+":"+item["fcstTime"][2:],
"기온" : item["fcstValue"]+"℃"
})
print(result)
for문을 사용하여 원하는 각 항목을 출력하면 조금더 깔끔하게 출력할 수 있습니다.
날짜의경우 슬라이싱을통해 년,월,일을 표시해주었습니다.
이전과 비교하면 훨씬 보기 편해졌습니다. 근데 이상한부분이 있습니다.
기온이 0도인 값도있고 한겨울에 15도까지 올라가있는 값도 있습니다.
값이 이상하게 나오는 이유는 기온은 키값이 fcstValue부분인데, 키값이 category인 항목에서 각 여러 값의 fsctValue를 전부 출력해서 그렇습니다.
즉 category의 value가 TMP,UUU,VVV,VEC 등 다양하게 존재하는데 저희는 기온에 해당하는 TMP값만 보고싶은데 다른 카테고리의 fsctValue값이 같이 출력되는겁니다.
TMP 기온만 표시하기
for item in dict["response"]["body"]["items"]["item"]:
if item["category"] != "TMP":
continue
result= []
result.append({
"날짜" : item["fcstDate"][:4] + "년" + item["fcstDate"][4:6] + "월" + item["fcstDate"][6:] + "일",
"시간대" : item["fcstTime"][:2]+":"+item["fcstTime"][2:],
"기온" : item["fcstValue"]+"℃"
})
print(result)
이럴때는 if문을 사용하여 category가 기온에해당하는 TMP가 아니면 아래코드를 건너뛰어 다음 반복회차로 넘거가고 category의 TMP에 해당하는 부분만 for문을통해 리스트에 넣어줄 수 있습니다.
다시 출력해보면 아까보다 데이터가 훨씬 줄어들고 보기좋게 출력되는걸 확인할 수 있습니다.
실행하는 날짜에 맞춰서 데이터 가져오기
프로그램을 실행할때마다 params의 base_date를 수정하기엔 번거로움이 있습니다.
그래서 datetime을 통하여 실행하는 날짜에 맞춰 자동으로 수정되게 할 수 있습니다.
from datetime import datetime
now = datetime.now().date()
datetime모듈을 가져온뒤 now 변수를 새로 생성하여 오늘 날짜를 가져옵니다.
now변수에는 포스팅 기준날짜인 '2023-12-18'이라는 데이터가 저장됩니다. 이제 now변수를 params의 'base_date' : 부분에 넣어주면되는데 그냥 넣고 실행하면 keyError라면서 에러가 발생합니다. 잘못된 값을 입력해서 api호출시 오류가 발생하는건데 날짜에서 년,원,일 사이의 '-'를 제거해줘야합니다.
tonow = str(now).replace('-','')
새로 변수를 생성한뒤 now를 문자열로 바꾸어 하이픈('-')을 제거해줍니다.
params ={'serviceKey' : 'decoding key', 'pageNo' : '1', 'numOfRows' : '1000', 'dataType' : 'XML', 'base_date' : now, 'base_time' : '0500', 'nx' : '55', 'ny' : '127' }
그리고 parmas값에는 tonow를 입력합니다.
다시 실행한뒤 결과를보면 오늘 날짜인 12월 18일 06:00 기온부터 23년 12월 21일 0:00 기온까지 조회되는걸 확인할 수 있습니다.
이 데이터를 텔레그램 메신저에서 받아보고 싶을경우 텔레그램 봇을 만들고, 텔레그램 봇을 적용하는 방법에관해 포스팅한 이전글을 확인해주세요.
특정 지역의 날씨만 확인하는법
날씨를 조회하는건 좋은데 각 지역마다 기온이 다르기 때문에, 프로그램을 사용하는 사용자가 자신이 살고 있는 지역의 nx와 ny 값을 매번 엑셀 파일에서 확인하고 기억하는 것은 번거로울 수 있습니다. 또한 사용자가 자신이 살고 있는 지역이 아닌 다른 지역의 기온을 알고 싶을 수도 있습니다. 이런 문제를 통해, 사용자가 직접 위치를 선택하고, 이에 해당하는 nx값과 ny값을 자동으로 입력할 수 있는 방법을 고민하게 되었습니다.
nx와 ny 값은 실제 위경도와 다르므로, 해당 지역을 엑셀 파일에서 검색하여 nx, ny 값을 찾아야 합니다. 초기에는 사용자의 위치 정보를 받아와 '부산광역시 기장군 기장읍'과 같이 띄어쓰기를 기준으로 슬라이싱하여 해당하는 데이터 값을 찾는 방법을 고려하였습니다. 또한, 구글 지도에서 IP 주소를 기반으로 주소를 가져오는 방법도 고려하였으나, 이 방법은 정밀도가 떨어질 수 있고, 현재 위치만 확인할 수 있다는 한계가 있었습니다. 따라서, 사용자가 직접 조회하고자 하는 지역을 선택할 수 있도록 구현하기로 했습니다.
이에 관한 내용은 다음편에서 다루도록 하겠습니다.