끄적거림

[API]기상청 api로 데이터 가져오기 in Python(feat. ASOS 종관기상관측) 본문

Python

[API]기상청 api로 데이터 가져오기 in Python(feat. ASOS 종관기상관측)

Signing 2020. 2. 18. 13:04
728x90
반응형

공공 데이터 중에서 가장 활용도가 높은 기상청 데이터를 사용해볼까한다.

 

기본적으로 기상청에서는 file(CSV), API(Json, XML) 두 형태로서 데이터를 제공한다.

file형태는 원할 때마다 내려 받아서 분석에 활용하면 되지만, 분석에서 만든 모델링을 계속해서 사용하기에는 번거로움이 있다.

 

따라서 어떤 모델을 구축했다면, API로 데이터를 실시간으로 돌려가며 실시간 모델링을 진행할 수 있다.

 

그러면, 데이터를 실시간으로 가져올 수 있는 방법인 API에 대해서 알아보자.

 

 

 

API란, Application Programming Interface의 약어로, 기기 간 통신을 통하여 데이터나 정보를 주고 받을 수 있는 것이라고 간단히 생각하면 되겠다.

 

데이터 전송 시, 흔히 많이 쓰이는 자료구조로는 XML과 Json이 있다.

 

XML) Extensible Markup Language의 약어로, 다른 종류의 시스템, 특히 인터넷에 연결된 시스템끼리 데이터를 쉽게 주고받을 수 있게 한 HTML의 한계를 극복할 목적으로 만들어졌다.

언뜻보면 HTML의 구조와 비슷하다.

 

Json) JavaScript Object Notation의 약어로 key-value 형태로 tree구조를 이루고 있다. 대부분의 데이터 형식을 다 담을 수 있다는 장점이 있어 아마 가장 많이 활용되는 자료구조가 아닐까 생각한다.

 

주로 Json은 웹/앱의 로그를 쌓는데 사용되며, 이를 분석하기 위해 무작정 Table 형태로 변환하지는 말자. 

depth가 깊은 Json 파일을 Table 형태로 변환하기란 쉽지 않고, 굉장히 비효율적인 면이 있다.

먼저, 가독성이 매우 떨어진다.

두 번째로, 메모리 낭비가 심해진다.

이 밖에도 여러 가지 문제가 있기에 Json 파일의 구조를 먼저 파악하고, 목적과 의미에 따라 구조를 나누어 Table로 변환하여 분석에 활용하길 바란다.

 

 

 

그럼 이제 Python으로 기상청 API를 사용하여 데이터를 받아오는 작업을 해보자.

 

 

01. Open-API 활용 신청

 

기상청의 Open-API를 사용하기 위해선 먼저 회원가입/로그인을 하고나서 원하는 데이터에 대한 활용신청을 해야한다.

기상공공데이터 : https://data.kma.go.kr/api/selectApiDetail.do?pgmNo=42&openApiNo=241

 

기상자료개방포털

 

data.kma.go.kr

위의 URL로 들어가 활용신청을 하자.

내가 원하는 자료는 전체 - 기상관측 - 지상 - 종관기상관측(ASOS)의 데이터이다.

ASOS는 각 지역마다 일정히 위치한 관측소로부터 관측된 날씨 정보를 말한다.

활용 신청을 했다면 첨부 문서에 활용 가이드가 있을 것이다. 나중에 필요하니 먼저 다운받아놓자.

 

 

 

02. 사용자 API키

데이터를 받아오기 위해서는 나에 대한 정보가 필요하다. 이때 사용하는 것이 사용자 API Key이다.

01번에서 신청한 후

마이페이지 - 오픈API현황 에 들어가면 오픈 API Key를 확인할 수 있다.

이 키는 외부로 유출되지 않도록 조심하는 것이 좋다.

 

 

 

 

 

03.1. Import Module

from urllib.request import urlopen
from urllib.parse import urlencode, unquote, quote_plus
import urllib
import requests
import json
import pandas as pd

기본적으로 urllib이라는 패키지가 필요하다. urllib 패키지 안에는 다음과 같은 4개의 모듈이 존재한다.

  • urllib.request : URL base 요청에 관련된 함수와 객체가 있다.
  • urllib.parse : 필요한 데이터를 URL에 파싱하기 위한 함수와 객체가 있다.
  • urllib.error : urllib.request모듈에 의해 발생한 예외 처리를 위한 모듈이다.(여기서 사용 안함)
  • urllib.robotparse : 웹사이트의 robots.txt 파이에 대한 파싱을 위한 모듈이다.(여기서 사용 안함)

 

 

 

03.2 URL 설정

#   url for request
url = 'http://data.kma.go.kr/apiData/getData'

간단히 개념적으로 설명하면...

데이터를 가져오려면 먼저 기상청의 ASOS 데이터가 있는 장소에 데이터가 있는지 노크를 해야한다.

노크를 하기 위해선 데이터가 있는 장소를 알아야하니 그 장소를 지정해 주는 작업이 바로 위의 코드이다.

 

#   parameter for request
params = '?' + urlencode({
    quote_plus("type"): "json",
    quote_plus("dataCd"): "ASOS",
    quote_plus("dateCd"): "HR",
    quote_plus("startDt"): "20200212",
    quote_plus("startHh"): "00",
    quote_plus("endDt"): "20200212",
    quote_plus("endHh") : "23",
    quote_plus("stnIds"): "108",
    quote_plus("schListCnt"): "500",
    quote_plus("pageIndex"): "1",
    quote_plus("apiKey"): "사용자 키 입력"
})

req = urllib.request.Request(url + unquote(params))

그 장소에 도착하여 "나 이런 이런 데이터가 필요해~"라고 말하기 위해 준비하는 과정이다.

이 코드는 지역코드108번, 2020년 02월 12일 23시에 발생한 ASOS데이터를  json파일로 받아오라는 의미이다.

각 변수와 그에 상응하는 값이 Key : Value 형태인 python의 Dictionary 자료구조를 사용하였음을 알 수 있다.

 

원하는 데이터를 앞의 URL에 파라메터로 붙여서 request만 하면 된다.

이 코드의 마지막 줄이 원하는 정보를 URL로 파싱하여 Request 객체로 만드는 작업이다.

 

quote_plus("~") 안의 변수 명은 01번에서 받아두었던 가이드에 나와있으니 참고하길 바란다.

 

 

 

03.3 Data 읽어오기

# 의존성 추가
# import ssl
# context = ssl._create_unverified_context()

response_body = urlopen(req, timeout=60).read() # get bytes data
data = json.loads(response_body)	# convert bytes data to json data
print(data)

urllib.request 모듈에 있는 urlopen( )이란 함수를 사용하여 원하는 정보가 담긴 URL을 열어준다.

urlopen( )함수는 다음과 같은 함수들과 함께 사용할 수 있다.

  • geturl() : 받아온 리소스의 URL을 받환받는다.
  • info() : 패킷의 메타 데이터(헤더 등)을 반환받는다.
  • getcode() : 응답 패킷의 HTTP 상태 코드를 반환받는다.
  • read() : 받아온 데이터를 bytes 형으로 받환받는다.
  • readline() : 받아온 데이터를 bytes형으로 한 줄씩 반환받는다.
  • close() : 연결된 요청을 닫는다.

※ 이 때, [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed라는 에러 메세지와 함께 urlopen함수가 작동하지 않을 수 있다.(나도 다른 환경에서 동일한 코드를 돌리니 안돌아갔다ㅠ)
찾아보니 의존성이 없어서 생길 수 있는 에러라고 나온다. 위의 주석처럼 ssl 모듈을 import하여 의존성을 추가해준다. 의존성이 무엇이고 왜 의존성을 추가해야하는지는 공부해서 다음 글로 올려보겠다.

 

 

여기서는 read( )를 이용하여 데이터를 읽어오면 된다. 설명에서도 보이겠지만, read() 함수는 bytes 타입으로 데이터를 읽어온다. 따라서 byte 타입을 다루기 쉽고 효율적인 json으로 변환해줄 필요가 있다. 궁극적으로 우리가 필요한 것은 DataFrame 타입의 데이터지만 byte타입에서 바로 DataFrame으로 바꾸는 것은 쉽지 않다. json으로 바꾸는 코드 또한 한 줄이고, 큰 리소스도 낭비되지 않기 때문에 json으로 바꿔준다.

 

 

 

 

 

 

 

03.4 Convert Json to DataFrame

data[0]['status']
data[1]['msg']
data[2]['stnIds']
res = pd.DataFrame(data[3]['info'])
print(res)

03.3에서 알겠지만, 2depth 정도 되는 구조를 갖는 Json 객체로 바뀐다. 여기서 우리가 궁극적으로 필요한 정보는 info라는 객체에 담긴 table 형태의 데이터이다. 나머지(status : 반환 코드, msg : status의 코드값)는 log 데이터로 남겨두는 것도 좋은 방법이다. stnIds는 처음 request를 날릴 때 지정했기 때문에 기상 API를 만든다면 인자값으로 대체하여 공통화 시키는 것도 좋은 방법이다.

 

res의 행 이름이 바로 시간과 관련된 정보이다. 행 이름을 새로운 컬럼을 만들어 넣어주면 끗!

 

 

이상으로 기상청에서 제공하는 공공데이터 API를 활용한 데이터 받아오기였다.

 

 

 

 

728x90
반응형
Comments