티스토리 뷰

반응형

+추가

공공데이터 불러오는 기초에 대한 글을 적기 이전에, 코로나 관련 API를 가지고 오는 질문이 많아서, 샘플 코드를 만들었다. 코드만 필요한 분들은 바로 아래의 URL을 참고하기 바란다.

 

 

2021.04.26 - [프로그램 언어/Python] - [공공데이터 API] 코로나 확진자 감염 현황 불러오는 코드

 

 

 


다 생략하고 핵심 위주로 진행해 보겠다.

API(Application Programming Interface)란, 기기 간 통신을 통하여 데이터나 정보를 주고 받을 수 있는 것이다. 즉, 사이트끼리 정보를 주고 받는 것이라고 생각하면 된다. 이때 데이터 전송 시 아무꺼나 주는것이 아니라 약속으로 전해논 XML과  Json을 주로 사용한다. (JSON을 더 많이 사용한다.)

 

우리는 python을 이용해서 기상청 API를 JSON으로 받아오는 작업을 해볼것이다. 아래의 사이트를 들어가자.

data.kma.go.kr/api/selectApiDetail.do?pgmNo=42&openApiNo=241

 

기상자료개방포털[데이터:오픈 API]

자료설명 기상청에서 제공하는 Open-API 목록을 조회하고 활용 신청할 수 있도록 링크를 제공합니다. > Open-API 이용방법   > Open-API 활용신청 방법 - 공공데이터포털 이용가이드를 참고하시기 바랍

data.kma.go.kr

물론 회원가입은 필수다. 

 

 

2020.09.24 기준으로 위의 사진을 보면, 나는 전체=>기상관측=>지상=>종관기상관측(ASOS) 에 들어갔지만 필요한 정보에 맞게 들어가면 된다. ASOS는 각 지역마다 일정히 위치한 관측소로부터 관측된 날씨 정보이다. 스크롤을 내려보자.

 

 

활용신청 버튼을 누르고, 활용가이드도 다운받아보자. 사이트가 공공데이터포털로 넘어가는데, 신청을 하자! 신청을 하면 중요한 것이, 인증키이다! 유출이 안되게 조심하자!

 

사실 인증키받았으면 이제 코드작성을 해보자.

 


일단은 위의 사이트에서 아래로 내려보면 아래 처럼 예시코드가 나와있다. 

 

역시나, 엄청 옛날 코드다. urllib2가 없어졌다.... 그리고 queryParams의 딕셔너리에서 quote_plus('ServiceKey')의 value값에 위에서 얻은 보안 키를 넣으면 되는데...... quote_plus('ServiceKey')가 바로 뒤에 하나 더 있다. 이거 안지우면 오류가 계속 나온다.(나처럼 이거 못보고 넘어가면 오류와의 긴 싸움을 할지도 모른다....)

 

 

자, 그러면 내가 1차 뻘짓을 한 코드를 보자. 결과론적으로 데이터가 들어온다... 아래의 코드는 짬뽕으로 짠 코드고 공부할 부분이 있어서 올렸다. 아래의 코드는, XML로 받아 놓고 JSON이 왜 안되지 그러면서 고민을 한 것이다. 나중에 안 사실이지만, quote_plus('dataType') : 'XML', 부분의 XML을 JSON으로 수정하면 된다. 하지만 아래의 코드에서는 XML을 받은 후 bytes로 바꾸고, 다시 string으로 바꾼 후에 다시 딕셔너리로 바꾼 후에 maxTa라는 값을 얻은 것이다.

from urllib.request import urlopen
from urllib.parse import urlencode, unquote, quote_plus
import urllib
import requests
import json
from xml.etree.ElementTree import parse
import xmltodict

# 데이터를 받고자하는 사이트의 포멧에 맞게 url을 수정하고 보내는 코드
url = 'http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList'
queryParams = '?' + urlencode({ quote_plus('ServiceKey') : '#### 인증키 넣자 ####', quote_plus('pageNo') : '1', quote_plus('numOfRows') : '10', quote_plus('dataType') : 'XML', quote_plus('dataCd') : 'ASOS', quote_plus('dateCd') : 'DAY', quote_plus('startDt') : '20100101', quote_plus('endDt') : '20100601', quote_plus('stnIds') : '108' })
request = urllib.request.Request(url + unquote(queryParams))


response_body = urlopen(request, timeout=60).read() # get bytes data


decode_data = response_body.decode('utf-8')
print(type(decode_data))

xml_parse = xmltodict.parse(decode_data)     # string인 xml 파싱
xml_dict = json.loads(json.dumps(xml_parse))

print(xml_dict['response']['body']['items']['item'][0]['maxTa'])

 

요청(request)와 응답(response) 기초 내용

우선 웹 브라우저에서 일어나는 요청과 응답의 순서를 알아보자.

  1. user가 웹 브라우저에 url을 입력 후 엔터
  2. request : 웹 브라우저는 요청 메시지를 웹 서버로 전송
  3. response : 웹 서버는 요청받은 정보를 user에게 보내면 웹 브러우저로 전달
  4. 응답온 메시지를 웹 브라우저가 해석하여 사용자에게 정보를 출력

즉, 우리는 요청을 보내는 코드와 서버에서 주는 응답을 해석하면 된다. 파이썬에서 URL과 웹 요청에 관련된 모듈은 urllib이라는 패키지로 묶어서 제공한다. 첫번째로 urllib.request(HTTP 요청 기능을 담은 모듈)에 대해 알아보고 두번째로 urllib.parse(URL 해석 조작기능을 담은 모듈)에 대해 알아보자.

 

urllib.request

urllib.request 모듈을 임포트 한 후 urllib.request.urlopen(요청할URL).read().decode('utf-8') 을 하면 웹에 요청을 보내게 된다. 코드를 하나씩 뜯어보자.

  • urllib.request.urlopen() - 함수는 웹 서버에 정보를 요청한 후, 돌려받은 응답을 저장하여 ‘응답 객체(HTTPResponse)’를 반환한다.
  • .read() - 반환된 응답 객체의 read() 메서드를 실행하여 웹 서버가 응답한 데이터를 바이트 배열로 읽어들인다.
  • .decode('utf-8') - byte 배열은 이진수로 이루어 졌기 때문에 그대로 사용하기가 어렵다. 웹 서버가 응답한 내용이 텍스트 형식의 데이터라면, decode('utf-8') 메서드를 실행하면 바이트 배열을 문자열로 변환가능하다. 이 때 'utf-8'은 유니코드 부화화 형식의 한 종류이다. 이때 utf-8은 디폴트 값이므로 생략하고 decode()로 적어도 된다.
더보기

추가적으로 url을 많이 불러오고 싶다면 함수로 정의해도 된다.  url만 넣어주면 요청을 하고 데이터를 받아 문자열로 변환한다.

import urllib.request

def request(url):

    response = urllib.request.urlopen(url)

    byte_data = response.read()

    text_data = byte_data.decode('utf-8')

    return text_data

초보자을 위한 팁 - 나도 처음에 요청을 받는거에 대해 JSON, XML 기타 등등 에 따라받는게 다르지 않을까? 라는 생각을 해서 쉽게 개념이 안 와닿았다. 그런 종류를 생각하지 말자. point는 받아서 문자열로 바꾼후에 내가 처리하기 쉽게 바꾼다가 핵심이다. 혹시나 받은데이터가 JSON으로 안보인다면, 데이터를 JSON으로 안받은거다. (처음공부할 때 이거 이해하기가 어려웠다.)

 

여기서 JSON 데이터를 받았으면, import json을 통해 json.load()를 사용하자. 기존의 json을 읽으면 text형식으로 string으로 읽는다. 그러나 json.load()의 ()안에 json파일을 넣어서 바꿔주면 dictionary로 변환다. 그리고 사용하면 된다!!

 

 

마지막으로 헷갈렸던 것에 대해 적어보겠다.

urllib.request.Request(url)로 요청을 보내는 건 알겠다. 그런데 request.GET()으로도 요청을 보내는 코드도 본적이 있는데 뭐가 다른가???? 간단히 말하면 urllib.request.Request(url)은 자동으로 GET요청을 보낸다. 그리고 데이터를 포함시킨다면 자동으로 POST로 바뀐다. ex) urllib.request.Request(url, data)

즉, urllib.request.Request(url)과 request.GET(url)은 같은 말이다.

import urllib.parse
import urllib.request

url = '요청 보낼 url을 적어주자'
values = {'name' : 'Hanpy',
          'location' : 'seoul',
          'language' : 'Python' }

data = urllib.parse.urlencode(values)
data = data.encode('ascii') # data는 바이트열이어야 합니다
req = urllib.request.Request(url, data)

위의 코드와 같이 urllib.request.Request에 url과 data도 포함 된다면 자동으로 urllib라이브러리에서 POST요청으로 보내게 된다.

 

 

위에서 불러온 코드 API를 간단하게 간출이면 다음과 같다.

from urllib.request import urlopen
from urllib.parse import urlencode, unquote, quote_plus
import requests

# 데이터를 받고자하는 사이트의 포멧에 맞게 url을 수정하고 보내는 코드
url = 'http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList'
queryParams = '?' + urlencode({ quote_plus('ServiceKey') : '___인증키___', quote_plus('pageNo') : '1', quote_plus('numOfRows') : '10', quote_plus('dataType') : 'JSON', quote_plus('dataCd') : 'ASOS', quote_plus('dateCd') : 'DAY', quote_plus('startDt') : '20100101', quote_plus('endDt') : '20100601', quote_plus('stnIds') : '108' })

get_data = requests.get(url + unquote(queryParams))
result_data = get_data.json()
print(result_data['response']['body']['items']['item'][0]['maxTa'])



#print(xml_dict['response']['body']['items']['item'][0]['maxTa'])
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함