요즘 날씨가 매우 불규칙하고, 장마철이라 한번 쏟아붇기 시작하면 엄청나게 쏟아붇는다. 별 생각 없이 나갔다가 신발을 다 적셔서 들어오기도 하고, 심지어 신발 뿐만 아니라 바지도 안전하지 않다.

그러던 와중에 기상청에서 제공하는 초단기예보가 6시간동안의 구름의 움직임을 예측하여 10분 단위로 알려주기 때문에 적중도가 굉장히 좋다는 이야기를 듣고 찾아보았는데, 10분 단위로 지도에 구름의 움직임과 함께 예상 강수량을 알려준다. 예측의 정확도는 아직 모르겠지만 이정도로 서비스 하는 것을 보면 그래도 6시간만은 어느정도 예상할 수 있기 때문에 서비스를 하는 것이 아닌가 싶었다.

기상청에서 제공하는 초단기예측, 중간에 강수량을 나타내는 색이 보인다.

이러한 정보를 매번 찾아서 들어가 확인하기 보다는, 휴대폰의 알림이나 메신저 등을 통해 받아볼 수 있으면 좋겠다는 생각을 했고, 이와 동시에 이러한 정보를 챗봇의 형태로 만들어 필요할 때 검색할 수 있게 하면 좋겠다는 생각을 해보았다.

기상청에서 날씨 정보 받아오기

가장 먼저 어떤 형태의 데이터를 받을 것인가를 생각했고, 시간별로 예측된 정보를 문자 형태로 받는것이 일단 가장 나을 것이라고 판단하였다.

날씨 정보를 받아오기 위해서 공공데이터포털의 기상청 초단기예보 api를 활용하기로 했다.

https://www.data.go.kr/data/15084084/openapi.do

 

기상청_단기예보 ((구)_동네예보) 조회서비스

초단기실황, 초단기예보, 단기((구)동네)예보, 예보버전 정보를 조회하는 서비스입니다. 초단기실황정보는 예보 구역에 대한 대표 AWS 관측값을, 초단기예보는 예보시점부터 6시간까지의 예보를,

www.data.go.kr

위의 사이트에 들어가 활용신청을 한다.

신청을 완료하고 나면 api 사용을 위한 인증키와 가이드, 위경도 엑셀파일을 얻을 수 있다.

혹시 작업을 공유하게 되었을 때 인증키를 노출하는 불상사가 생기면 안되기 때문에 인증키 또한 secrets.json 파일로 만들어 작업 폴더와 같은 위치에 두고 불러와서 사용하도록 한다.

# secrets.json
{
    "token": "인증키"
}
# python-weather-api.py

import os, json

path = os.path.dirname(os.path.abspath(__file__))

# 토큰을 secrets.json 파일로부터 읽어오는 함수
def get_token():
    try:
        secret_file = path + "\secrets.json"
        with open(secret_file) as f:
            secrets = json.loads(f.read())
        token = secrets["token"]
        return token
    except:
        return False

그리고 위경도 엑셀파일과 함께 받은 가이드를 읽어보면서 찬찬히 데이터 요청 항목을 채우도록 한다.

날씨 예보는 매 시 정각에 이루어지며 해당 예보의 발표는 해당 시 30분에, 그리고 45분에 api 사용이 가능하다. 따라서 45분 기준으로 현재 시간의 분 단위가 45보다 크다면 현재 시의 예보 정보를, 45보다 작다면 1시간 전의 예보 정보를 가져올 수 있도록 base_time을 조정해야 한다.

최종적으로는 지역 이름을 인풋으로 넣으면 해당 지역의 좌표를 알아서 찾아 날씨 정보를 받아오고 싶지만, 일단은 nx:60 ny:127 로 좌표를 두고 날씨 정보를 가져와보도록 한다.

초단기예보는 10개의 정보(기온, 강수량, 습도 등)에 대해 6시간 정보를 1시간 간격으로 주기 때문에 총 60개의 정보가 리턴되게 된다. 따라서 numOfRows 는 60으로 설정해주면 충분하다.

# python-weather-api.py

import os, json
from datetime import datetime, timedelta
from urllib.parse import urlencode, unquote, quote_plus
import requests

path = os.path.dirname(os.path.abspath(__file__))

# 초단기예보 정보 요청
def get_ultra_srt_fcst():
    token = get_token()
    if not token:
        print("no token")
        return False
    callback_url = (
        "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst"
    )
    # base_date, base_time 계산
    time_now = datetime.now()
    if time_now.minute < 45:
        time_target = time_now.replace(minute=30) - timedelta(hours=1)
    else:
        time_target = time_now.replace(minute=30)
    base_date = time_target.strftime("%Y%m%d")
    base_time = time_target.strftime("%H%M")
    params = "?" + urlencode(
        {
            quote_plus("serviceKey"): token,  # 인증키
            quote_plus("numOfRows"): "60",  # 한 페이지 결과 수 // default : 10
            quote_plus("pageNo"): "1",  # 페이지 번호 // default : 1
            quote_plus("dataType"): "JSON",  # 응답자료형식 : XML, JSON
            quote_plus("base_date"): base_date,  # 발표일자 // yyyymmdd
            quote_plus("base_time"): base_time,  # 발표시각 // HHMM, 매 시각 45분 이후 호출
            quote_plus("nx"): "60",  # 예보지점 X 좌표
            quote_plus("ny"): "127",  # 예보지점 Y 좌표
        }
    )
    res = requests.get(callback_url + unquote(params))
    items = res.json().get("response").get("body").get("items").get("item")
    print(items)

프린트된 items를 확인해보면 fcstTime, 즉 시간에 따른 예보 정보들이 api 가이드에 주어진 것과 같이 보여지게 된다.

이 자료들을 적절히 조작하여 내가 필요한 정보들만 골라 dictionary 형태로 만들어준다.

초단기 예보에서 얻고 싶은 자료는 온도나 풍향등의 자료보다는 당장 하늘이 흐린지, 비가 오는지, 비가 온다면 얼마나 오는지가 궁금하므로 이 세가지 정보만 얻도록 조정해보았다.

# python-weather-api.py

from collections import defaultdict
import os, json, requests
from datetime import datetime, timedelta
from urllib.parse import urlencode, unquote, quote_plus

path = os.path.dirname(os.path.abspath(__file__))

sky_code = {"1": "맑음", "3": "구름많음", "4": "흐림"}
pty_code = {
    "0": "없음",
    "1": "비",
    "2": "비/눈",
    "3": "눈",
    "5": "빗방울",
    "6": "빗방울눈날림",
    "7": "눈날림",
}

# 초단기예보 정보 요청
def get_ultra_srt_fcst():

    # ... 생략

    items = res.json().get("response").get("body").get("items").get("item")

    weather_data = defaultdict(dict)
    for item in items:
        fcstTime = item["fcstTime"][:2] + "시"
        # 하늘상태: 맑음(1) 구름많은(3) 흐림(4)
        if item["category"] == "SKY":
            weather_data[fcstTime]["sky"] = sky_code[item["fcstValue"]]
        # 1시간 동안 강수량
        if item["category"] == "RN1":
            weather_data[fcstTime]["rain"] = item["fcstValue"]
        # 강수형태 : 없음(0), 비(1), 비/눈(2), 눈(3), 빗방울(5), 빗방울눈날림(6), 눈날림(7)
        if item["category"] == "PTY":
            weather_data[fcstTime]["pty"] = pty_code[item["fcstValue"]]
    return weather_data

결과로 얻어지는 dictionary의 형태는 다음과 같다.

weather_data["22시"] = {"sky": "구름많음", "rain": "강수없음", "pty": "없음"}

현재 시간 기준으로 앞으로 5~6 시간의 날씨를 알게 되었다.

정리

기상청 api의 이용법을 알고, 이를 이용하여 정해진 지역의 날씨 정보를 얻어보았다. 다음 작업으로는 내가 원하는 위치(주소 혹은 명칭)이 주어졌을 때, 해당 위치의 격자를 얻어 날씨 정보를 얻어볼 예정이다.

내용 관련하여 도움이나 조언 언제든 환영합니다!

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기