<웹 API(Application Programming Interface)>

저번에 Web Scraping을 알아보고 난 후, 이번에는 웹 API를 이용하는 방법에 대해서 공부해 보았다.

웹 API를 이용하면, HTML 소스를 분석할 필요 없이 바로 웹 서버에서 내가 원하는 Data들을 요청하고, 받을 수 있다!

이러한 웹 API를 이용하여 Data를 받게 되면, 이 Data들의 형식은 주로 ‘XML’이나 ‘JSON’이다. 따라서 책을 통해서 이 두 가지 형식이 어떤 구조로 이루어져 있는 지도 공부를 했다.

‘XML’과 ‘JSON’ 형식이 어떠한 구조로 되어있고, 또 어떻게 Data를 웹 서버에 요청해야 하는 지에 대해서는 설명을 생략하도록 하겠다. 너무 귀찮아…ㅠㅠ

그래서 이번 포스트에서는 그냥 내가 웹 API를 이용해서 만들어 본!

‘사용자가 원하는 지역의 대기 오염 정보를 알아보는 프로그램(?)’ 코드에 대해서 포스팅하고자 한다. 프로그램이라기엔 인터페이스도 갖추어지지 않은 그저 코드뿐인 것이긴 하지만,,, 어떻게 설명해야 할지 몰라서…ㅇㅇ

책에서 웹 API의 마지막 예제로 대기 오염 정보를 가져오는 예제를 알려줬는데,

예제를 따라해보고 나니까,

‘이거 좀 다듬고, 새롭게 코드 추가하고 해보면 재밌겠다!’

라는 생각이 들어서 만들어보았다!!

 

 

 

공공 데이터 포털 이용하기

내가 웹 API를 알아보면서 놀란 것은 쉽게 양질의 Data를 이용할 수 있다는 점이다. 대표적으로 대한민국 정부에서도 공공기관들의 Data를 쉽게 이용할 수 있도록 포털을 운영하고 있다는 것이다.

그곳은 바로 공공 데이터 포털(https://www.data.go.kr)이다. 궁금한 사람은 링크를 타고 웹 페이지에 들어가보자.

웹 API를 이용하기 위해서 공공 데이터 포털 사이트에 회원가입을 하고, 내가 이용하고 싶은 데이터의 웹 API에 활용 신청을 하면 끝이다!

활용 신청을 하면 나의 고유 API 키가 생성되고, 이를 이용하여 웹 API를 이용하면 되는 것이다.

여기서 주의할 점!

나의 고유 API 키는 말 그대로 나만의 고유 정보이기 때문에 나만 알고 있어야 한다! 외부에 노출되면 새롭게 발급받아야 한다.

본인은 이번 코드를 구현하기 위해서

  1. 한국환경공단_에어코리아_측정소정보
  2. 한국환경공단_에어코리아_대기오염정보

이렇게 2가지의 웹 API를 이용하였다. (텍스트를 누르면 해당 웹 API 소개 페이지로 이동할 수 있음!)

2가지 모두 ‘한국환경공단’에서 제공하고 있는 Open API이다.

그리고 이렇게 공공 데이터 포털에서 제공하는 웹 API를 이용하면 좋은 점이 또 하나 있다. (포스트 쓰면서 생각났음.)

내가 여태 사용했던 웹 API 모두 참고문서(오픈 API 활용 가이드)를 제공하고 있다는 점이다!

이 활용 가이드에는 ‘Call Back URL’, ‘요청 변수’와 ‘변수에 대한 설명과 예시’, 그리고 ‘응답 Data에 대한 변수 설명’, ‘응답받은 Data 값들을 어떻게 해석해야하는 지’까지 아주 자세히 나와있다. 이를 이용하면 코드를 짜는데도 아주 큰 도움이 된다!

아무튼, 이제 각설하고 본격적으로 본인이 구현한 코드를 알아보고자 한다.

 

 

 

1. 내가 원하는 지역 근처의 측정소 찾기

한국환경공단_에어코리아_측정소정보’ API의 ‘TM 기준좌표 조회’ 기능에서는 읍면동 이름으로 검색해서 TM 기준좌표 내역을 조회할 수 있도록 하는 기능을 제공하고 있다.

이를 이용하여 내가 원하는 지역의 TM 기준좌표를 찾고, 그리고 동일한 API에서 제공하는 ‘근접측정소 목록 조회’ 기능을 이용하여 입력한 TM 좌표 주변의 측정소 정보와 TM 좌표와의 거리가 얼마나 떨어져 있는지 알 수 있도록 코드를 구현하였다.

일단, 내가 원하는 지역의 TM 기준좌표를 찾는 코드부터 소개하면 다음과 같다!

import requests


API_KEY = '발급받은 API키를 입력하면 됨!'
API_KEY_Decode = requests.utils.unquote(API_KEY) # API 키를 디코딩해서 변수에 저장

req_url1 = 'http://apis.data.go.kr/B552584/MsrstnInfoInqireSvc/getTMStdrCrdnt'
# TM 기준좌표 Data를 요청할 웹 API URL

ServiceKey = API_KEY_Decode
return_type = 'json'
# 사용자가 직접 원하는 지역의 읍면동 이름을 입력할 수 있도록 함.
umd_name = input('읍/면/동의 이름을 입력하십시오. >>> ')


req_parameter1 = {
    'serviceKey':ServiceKey,
    'returnType':return_type,
    'umdName':umd_name
} # URL에 제공할 요청 변수들을 딕셔너리 형태로 저장


r1 = requests.get(req_url1, params = req_parameter1)  # 웹 API를 이용해서 Data를 제공받았다!
dict_data1 = r1.json()  # 제공받은 Data를 'json'형식에서 딕셔너리 타입으로 변환에서 새로운 변수에 저장

import sys

# 'introduce()' 함수를 정의하였다.
# 입력받은 읍면동 이름을 이용하여 지역을 검색한 뒤, 검색 결과를 나타내주고,
# 사용자가 직접 원하는 결과를 선택하도록 해주는 함수이다.
def introduce():
    total_count = dict_data1['response']['body']['totalCount']
    print("\n입력한 읍/면/동 이름 : {0} \n".format(umd_name))
    if total_count == 0:
        sys.exit("[ 검색된 결과가 없습니다. ]") # 검색 결과가 없을 시, 코드를 종료시켜버리는 코드이다.
    else:
        print("[ 검색된 결과 : 총 {0}건 ] \n ".format(total_count)) # 총 몇 건의 검색 결과가 나왔는 지 알려주고
    for k in range(total_count):  # 각각의 결과마다 시군구 + 읍면동 정보를 알려준다.
        station_data = dict_data1['response']['body']['items'][k]
        print('[ {0} ]'.format(k + 1))
        print('[주소] : {0} {1} \n'.format(station_data['sggName'], station_data['umdName']))
    
    select_num = int(input('원하는 주소 정보의 번호를 입력하십시오. [ ex) 1 ] >>> '))
    select_station_info = dict_data1['response']['body']['items'][select_num - 1]
    # 사용자가 검색 결과를 보고 원하는 주소 정보의 번호를 입력하면 해당 주소의 웹 API로부터 요청받은 Data 모두를
    # 'select_station_info' 변수에 할당하고 return 해준다.
    return select_station_info

# 사용자가 원하는 곳의 TM 기준좌표를 tmX, tmY 값을 변수에 저장하기

ms_data = introduce() # 사용자가 선정한 지역의 정보를 새로운 변수에 할당한다.

# 그 중에서 TM 기준좌표의 x좌표와 y좌표를 각각의 변수에 저장한다.
tmX_val = ms_data['tmX']
tmY_val = ms_data['tmY']

 

 

2. 원하는 지역의 근접 측정소 목록 조회 및 선택하기

위에서 사용자가 원하는 지역의 읍면동 이름을 입력하여 직접 원하는 지역을 선택하였고, 그 지역의 TM 기준좌표 정보를 변수에 저장하는 것까지 했다.

이제 사용자가 원하는 지역의 TM 기준좌표를 알았으니, 이제 대기 오염 정보를 측정하는 ‘측정소’를 선택해야한다.

한 지역에는 1개의 측정소가 존재할 수도 있지만, 여러 개의 측정소가 존재할 수도 있다. 책의 예제에서는 그냥 TM 기준좌표에서 가장 가까운 곳을 선택해서 결과를 보여줬지만,

나는 측정소 또한 주소와 TM 기준좌표와의 거리를 보여줌으로써 사용자가 직접 선택할 수 있도록 코드를 작성하였다.

이번에는 근접 측정소의 목록을 조회하고, 그 결과를 보여주고 사용자가 선택하는 것까지의 코드를 보도록 하자!

# 근접 측정소 목록 조회

req_url2 = 'http://apis.data.go.kr/B552584/MsrstnInfoInqireSvc/getNearbyMsrstnList'
# 근접 측정소 목록 Data를 요청할 웹 API URL

req_parameter2 = {
    'serviceKey':ServiceKey,
    'returnType':return_type,
    'tmX':tmX_val,
    'tmY':tmY_val,
} # 해당 웹 API 요청 시 필요한 변수들을 하나의 딕셔너리 변수에 저장

r2 = requests.get(req_url2, params = req_parameter2)
dict_data2 = r2.json()
# 위에서와 동일하게 Data를 응답받고, json 형식의 데이터를 딕셔너리 타입으로 변환



# 근접 측정소 목록에 대한 이름, 거리, 주소 정보를 모두 출력

# 'choose_station()'이라는 함수를 정의하였다.
# 요청받은 근접 측정소의 이름, TM 기준좌표와의 거리, 측정소의 주소를 측정소 별로 출력하고,
# 사용자가 직접 원하는 측정소를 선택하도록 해주는 함수이다.
def choose_station():
    print("\n\n\n[ 선택한 지역의 측정소 목록 ]\n")

    for k in range(dict_data2['response']['body']['totalCount']):
    
        station_name = dict_data2['response']['body']['items'][k]['stationName']
        tm = dict_data2['response']['body']['items'][k]['tm']
        addr = dict_data2['response']['body']['items'][k]['addr']
        
        print('[ {0} ]'.format(k + 1))
        print('- 측정소 이름 : {0} / 거리 : {1}km'.format(station_name, tm))
        print('- 측정소 주소 : {0}'.format(addr), '\n')
        
    select_num = int(input('\n\n원하는 측정소의 번호를 입력하십시오. [ ex) 1 ] >>> '))
    select_station_name = dict_data2['response']['body']['items'][select_num - 1]['stationName']
    # 사용자가 원하는 측정소의 변호를 입력하면, 최종적으로 이 함수는 그 측정소의 이름 정보를 return한다.
    
    return select_station_name

 

 

3. 대기 오염 측정 결과 나타내기

이제 원하는 지역의 근접 측정소까지 선택했으니, 이제 그 근접 측정소가 측정한 대기 오염 정보를 출력하면 된다.

이것까지 하면, 최종적으로 사용자가 원하는 지역의 측정소에서 측정한 대기 오염 정보를 사용자가 알게되는 것이다.

이 대기 오염 정보를 요청하기 위해서는 이제 ‘한국환경공단_에어코리아_대기오염정보’ API를 이용해야한다.

해당 API의 기능 중에서 ‘측정소별 실시간 측정정보 조회’ 기능을 이용했다. 이 API의 요청 변수 중에는 ‘측정소명’ 변수가 존재한다.

이 변수의 값에 바로 위에서 최종적으로 return한 측정소의 이름 정보를 입력하게 된다.

이를 종합해 대기 오염 측정 결과를 보여주는 코드를 작성하면 다음과 같다.

# 대기 오염 측정 정보 가져오기

req_url3 = 'http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty'
# 대기 오염 측정 정보 Data를 요청할 웹 API URL

station_name = choose_station() # 위에서 정의한 'choose_station()' 함수를 통해서
                                # 측정소의 이름 정보를 'station_name' 변수에 입력한다.

date_term = 'DAILY'

version = 1.3

req_parameters3 = {
    'serviceKey':ServiceKey,
    'returnType':return_type,
    'ver':version,
    'stationName':station_name,
    'dataTerm':date_term,
} # 해당 웹 API 요청 시 필요한 변수들을 하나의 딕셔너리 변수에 저장

r3 = requests.get(req_url3, params = req_parameters3)
dict_data3 = r3.json()
# 위에서와 동일하게 Data를 응답받고, json 형식의 데이터를 딕셔너리 타입으로 변환



# 최종적으로, 대기 오염 측정 정보 결과를 나타내기

data = dict_data3['response']['body']['items'][0]

dataTime = data['dataTime'] # 측정된 날짜, 시간 정보 저장

so2Grade = data['so2Grade'] # 아황산가스 지수 정보
so2Value = data['so2Value'] # 아황산가스 농도 정보
coGrade = data['coGrade'] # 일산화탄소 지수 정보
coValue = data['coValue'] # 일산화탄소 농도 정보
o3Grade = data['o3Grade'] # 오존 지수 정보
o3Value = data['o3Value'] # 오존 농도 정보
no2Grade = data['no2Grade'] # 이산화질소 지수 정보
no2Value = data['no2Value'] # 이산화질소 농도 정보

pm10Grade1h = data['pm10Grade1h'] # 미세먼지 지수 정보
pm10Value = data['pm10Value'] # 미세먼지 농도 정보
pm25Grade1h = data['pm25Grade1h'] # 초미세먼지 지수 정보
pm25Value = data['pm25Value'] # 초미세먼지 농도 정보

Grade = {'1':'좋음', '2':'보통', '3':'나쁨', '4':'매우나쁨'}
# 각각의 지수 정보는 1 ~ 4까지의 정수를 값으로 갖는다. 활용 가이드를 참고해보면, 각각의 정수 값은
# 위의 'Grade' 딕셔너리에 해당하는 정보를 의미한다. 따라서 결과를 출력할 때 '좋음' ~ '매우나쁨'의
# 문자열 정보로 결과를 출력하기 위해 'Grade' 딕셔너리를 만들었다. 


# 결과 출력!

print('\n\n\n[ 측정소({0})에서 측정된 대기 오염 상태 ]\n'.format(station_name))
print('- 측정 시간 : {0}\n'.format(dataTime))
print('[지수] 아황산가스 : {0}, 일산화탄소 : {1}, 오존 : {2}, 이산화질소 : {3}'.format(Grade[so2Grade], Grade[coGrade], Grade[o3Grade], Grade[no2Grade])) # 지수 정보를 출력
print('[농도] 아황산가스 : {0}ppm, 일산화탄소 : {1}ppm, 오존 : {2}ppm, 이산화질소 : {3}ppm\n'.format(so2Value, coValue, o3Value, no2Value)) # 농도 정보를 출력
print('[지수] 미세먼지 : {0}, 초미세 먼지 : {1}'.format(Grade[pm10Grade1h], Grade[pm25Grade1h])) # 지수 정보를 출력
print('[농도] 미세먼지 : {0}㎍/㎥, 초미세 먼지 : {1}㎍/㎥'.format(pm10Value, pm25Value)) # 농도 정보를 출력

이렇게 대기 오염 정보를 출력해주는 프로그램(?)에 대한 코드 소개는 끝이다!

근데 코드랑 설명만 길게 작성해놓고, 정작 실행 결과를 보여주지 않으면 이상하지 않은가?

그래서 Jupyter Notebook으로 이 코드를 실행한 결과를 스크린샷으로 보여주면 다음과 같다!

 

Image

input()함수를 이용해 사용자가 직접 값을 입력할 수 있도록 한 부분은 이렇게 위의 사진과 같이

사용자가 직접 입력할 수 있도록 칸이 생긴다. 이러한 방식을 통해 사용자가 직접 값들을 입력하면…

 

Image

이렇게 코드가 실행된다. 따라서 이렇게 대기 오염 정보에 대한 정보를 얻을 수 있게 되는 것이다.

 

 

 

마무리

오늘은 이렇게 ‘공공 데이터 포털’과 웹 API를 활용하여 사용자가 원하는 지역의 측정소를 선택하여 해당 지역의 대기 오염 정보를 알아볼 수 있는 코드를 구현해보았다.

이번 코드 외에도 여러번 웹 API를 이용해보니 상당히 재미있다! ‘공공 데이터 포털’ 외에도 이용할 수 있는 Open API는 많으니까 내가 이용할 수 있는 Data 또한 얼마나 다양하다는 이야기인가!

책을 통해서 이렇게 Data를 다룰 수 있는 방법들을 여러가지로 배울 수 있다는 게 참 좋은 것 같다.

아직도 내가 모르는 방식들이 많겠지?

근데 이렇게 코드를 Jupyter Notebook으로 실행시키는 것 말고, 직접 GUI를 이용해서 뭔가 있어보이게 결과값을 출력해보고 싶다.

출력 결과들이 너무 텍스트만 띡띡 나오는게 좀 볼품없잖아?

나중에는 GUI에 대해서도 한번 공부해봐야겠다.

그럼, 오늘 포스트는 여기서 끝!

 

 

 

P.S.

근데 이렇게 포스트를 하는 시간이 코드를 구현하는 만큼의 시간을 온전히 사용해야한다. 블로거들은 정말 대단한 사람들인 것 같다…

댓글남기기