지난 API 활용 노트 01번에서는 API에 대한 기본적인 개념과 흐름을 정리해 보았었습니다.
하지만, 아직 서비스를 만들기에는 근본적인 문제점들이 몇가지 있습니다.
URL에 아직 어떤 정보(파라미터)를 수정하고, 무엇을 작성해서 요청을 보내야 하는지도 모를 뿐더러,
심지어는 받은 XML데이터가 무엇인지 얼추 알고있지, 실제로 데이터가 무엇을 의미하는지 어떤 데이터를 선정해서 보여줄지는 모릅니다.
이번 포스팅에서는 API를 더 잘 쓸수 있는 방법에 대해 알아보고, 실제로 서비스를 완성시켜 보겠습니다.
(이 게시글은 API에 대해 공부하며 작성한 순한맛 설명 버전의 게시글입니다.)
Get 요청시 파라미터 전달법
요청변수인 파라미터 값을 수정할 수 있도록 코딩
일단 아래의 코딩은 실행이 되어서 기분은 좋지만, 너무 가독성이 떨어집니다. 😤
1
2
3
4
5
6
import requests
URL = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst?serviceKey=인증키&pageNo=1&numOfRows=100&dataType=XML&base_date=20231010&base_time=2000&nx=61&ny=126'
response = requests.get(URL)
print(response.status_code)
print(response.text)
개발에 있어서 가독성과 문법, 규칙은 굉장히 중요합니다. 왜냐하면, 코딩을 나혼자 다 할 수는 없거든요..
(똑똑한 사람들 붙잡아서 같이 해야해요..! ㅋㅋㅋ)
requsets.get을 사용할 때 파라미터(요청 변수)를 전달하는 기본적인 코드의 형태입니다.
1
2
3
4
5
6
7
8
9
10
### requsets.get을 사용할 때 파라미터(요청 변수)를 전달하는 기본적인 코드
import requests
URL = 'http://www.google.com'
params = { 'key' : 'value' }
response = requests.get(URL, params=params)
print(response.status_code)
print(response.url)
print(response.text)
이전과는 다르게, ‘params’라는 딕셔너리 형태의 변수를 선언해, key값과 value를 넣어주었습니다.
'key'와 'value'는 쉽게 말해, '데이터의 이름'과 '실제로 들어있는 데이터'의 관계라고 생각하면 됩니다.
이렇게 하면 내가 작성한 ‘URL’과 ‘파라미터’를 requests모듈이 적당히 엮어서
실제로 내가 보내고자 하는 요청 URL으로 만들어 주는 것입니다.
코드를 실행하여 응답 객체(response)의 url을 찍어보면, 작성한 URL과 파라미터가 엮여있음을 확인할 수 있다.
이렇게 파라미터(요청 변수)를 딕셔너리 형식으로 정리하면, 매번 바뀌는 데이터를 변수로 지정할 수 있고
심지어는 코드의 가독성도 높일 수 있기에 이렇게 작성하는 것이 휠씬 좋습니다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
### requests.get으로 URL과 파라미터를 기상청 API를 사용해 요청하고 XML데이터를 받아 출력
import requests
URL = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst'
key = '인증키'
params = {'serviceKey' : key,
'numOfRows' : 100,
'dataType' : 'XML',
'base_date' : '20231011',
'base_time' : 2000,
'nx' : 61,
'ny' : 126
}
response = requests.get(URL, params=params)
print(response.status_code)
print(response.url)
print(response.text)
우리의 작고 귀엽고 소중한 URL을 ‘Call Back URL’과 ‘파라미터’로 분리해서 코드를 작성해 줍니다.
key값은 너무 길어서 분리해서 작성해 주었습니다.
정상적으로 응답해 주었습니다. 😆
요청 메세지 알아보기
서버에 요청할 데이터 뜯어보기
드디어… API의 기본 사용법을 알았고, 이제는 이 기상청 API를 쓰는 방법에 대한 이야기 입니다.
https://www.data.go.kr/index.do
다시 처음으로 돌아가서, 우리가 사용하고자 하는 API에 대한 참고문서를 확인해 줍니다.
보통 어떤 API를 사용하고자 할때 관련 정보가 설명되어 있는 웹문서나 PDF파일을 한번 슥 봐주면 좋습니다.
- 정신없는 아침 출근시간,
- 오늘 기온은 어느 정도 이며 옷은 어떻게 입고 나가야 할지,
- 강수 예보가 있는지에 따라 우산을 챙길지 말지,
- 굳이… 핸드폰을 켜서 날씨를 검색해 보는게 귀찮다..
우리가 만들고자 하는 서비스에서, 실제로 어떤 기능을 구현할지 문서를 참고해 정리해 보면 다음과 같습니다.
- [정신없는 아침 출근 루트] : 성수동
- [오늘 옷을 어떻게 챙길지] : 오늘의 최고 기온과 최저기온
- [지금 옷을 어떻게 입고 나갈지] : 앞으로의 기온
- [우산을 챙길지 말지] : 앞으로의 강수확률(적어도 퇴근할 때까지, 보통 8시간 근무 + 출퇴근 4시간 = 12시간 정도?)
이제 다시 본론으로 돌아가서 API가 제공하는 상세기능내역 4가지 중에서,
'예보기간과 구역을 시공간적으로 세분화한 예보를 제공'하는 '단기예보조회'를 사용하면 될 것 같습니다.
(사실 이때까지 쓰고있던 것이었다!)
우리가 써왔던 것처럼, Call Back URL(API를 제공하는 기상청 서버가 지정한 URL규칙)이 있고
요청 메세지와, 응답 메세지(아래에서 다루겠습니다), 그리고 아래에는 예시 URL코드가 있습니다.
문서를 참고하여, 어떤 파라미터들이 있고 값을 어떻게 결정할지 한번 보겠습니다.
항목명 | 비고(설명) |
---|---|
serviceKey | 우리가 계속 사용하던 인증키 입니다. |
numOfRows | 한 페이지 결과 수 입니다. 우리가 원하는 양의 데이터 개수 만큼만 지정하면 될 것 같습니다. |
기본적으로 받은 XML파일을 참고해 보면 category별로 시간당 12개의 데이터가 날라오고,
앞으로 12시간 동안의 정보를 필요합니다.
우리가 필요한 한 페이지 데이터 결과 수 12 x 12 = 144면 될 것 같습니다.
항목명 | 비고(설명) |
---|---|
pageNo | 페이지는.. 1장이면 되겠죠..? |
dataType | 응답 자료 형식인데, 저는 XML말고 JSON으로 바꾸어서 쓰겠습니다.(개인취향…🙃) |
base_date | 발표 일자입니다. |
base_time | 발표 시각입니다. |
제공된 문서의 아래쪽 참고자료 부분에 더 자세한 내용이 있습니다.
일단 발표 시각 파라미터는 1일에 8회 진행되는 시간 중에 골라야 하는데…
현재 시간에 따라 8개의 시간대 중에서 고르고, 또 API제공 시간이 조금 늦기 때문에 파라미터를 잘 정해야 합니다.
(아… ㅋㅋ 골치 아프네;; 그래도 파라미터를 정확히 정해서 요청해야합니다…ㅜ)
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
31
32
33
34
35
### 조회하는 순간 기준으로 base_date, base_time 파라미터 값을 API문서에 따라 계산하는 코드
import datetime
now_date = datetime.datetime.now() # 코드를 실행한 순간의 날짜와 시간
base_date = '00000000'
base_time = '0000'
std = [
datetime.datetime(2023, 1, 1, 2, 10).time(),
datetime.datetime(2023, 1, 1, 5, 10).time(),
datetime.datetime(2023, 1, 1, 8, 10).time(),
datetime.datetime(2023, 1, 1, 11, 10).time(),
datetime.datetime(2023, 1, 1, 14, 10).time(),
datetime.datetime(2023, 1, 1, 17, 10).time(),
datetime.datetime(2023, 1, 1, 20, 10).time(),
datetime.datetime(2023, 1, 1, 23, 10).time()
]
std_time = ['0200', '0500', '0800', '1100', '1400', '1700', '2000', '2300']
if now_date.time() < std[0]: # 조회시간 < 2시 10분
now_date = now_date - datetime.timedelta(days=1) # 현재 날짜에서 하루 빼기
base_date = now_date.strftime('%Y%m%d')
base_time = '2300'
elif now_date.time() >= std[7]: # 조회시간 >= 23시 10분
base_date = now_date.strftime('%Y%m%d')
base_time = '2300'
else:
for i in range(1, 8): # 조회시간 별 가장 최근 시간
if now_date.time() < std[i]:
base_date = now_date.strftime('%Y%m%d')
base_time = std_time[i - 1]
break
print(base_date)
print(base_time)
현재 테스트 시간 2023년 10월 12일, 01시 35분 기준으로 아직 02시 10분이 지나지 않았기 때문에
base_date : 20231011, base_time : 2300 로 정상적으로 출력되는 것을 볼 수 있습니다.. 헉헉🥵
항목명 | 비고(설명) |
---|---|
nx | 예보지점의 x좌표. 첨부파일에 있는 엑셀에 값이 나와 있습니다. |
ny | 예보지점의 y좌표. 첨부파일에 있는 엑셀에 값이 나와 있습니다. |
첨부되어 있는 엑셀파일을 열어서, 조회하고 싶은 지역 성수동의
nx : 61, ny : 126입니다!
응답 메세지 알아보기
서버에서 응답받은 데이터 뜯어보기
위에서 이래저래 알아보았던 내용을 토대로, 앞으로 12시간의 기상데이터를 요청하는 코드입니다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
### 코드 실행 시간 기준으로, 앞으로 12시간의 기상 데이터 JSON파일로 받는 코드
import requests
import datetime
now_date = datetime.datetime.now() # 코드를 실행한 순간의 날짜와 시간
base_date = '00000000'
base_time = '0000'
std = [ # API제공 시간, 년월일은 더미값
datetime.datetime(2023, 1, 1, 2, 10).time(),
datetime.datetime(2023, 1, 1, 5, 10).time(),
datetime.datetime(2023, 1, 1, 8, 10).time(),
datetime.datetime(2023, 1, 1, 11, 10).time(),
datetime.datetime(2023, 1, 1, 14, 10).time(),
datetime.datetime(2023, 1, 1, 17, 10).time(),
datetime.datetime(2023, 1, 1, 20, 10).time(),
datetime.datetime(2023, 1, 1, 23, 10).time()
]
std_time = ['0200', '0500', '0800', '1100', '1400', '1700', '2000', '2300']
if now_date.time() < std[0]: # 조회시간 < 2시 10분
now_date = now_date - datetime.timedelta(days=1) # 현재 날짜에서 하루 빼기
base_date = now_date.strftime('%Y%m%d')
base_time = '2300'
elif now_date.time() >= std[7]: # 조회시간 >= 23시 10분
base_date = now_date.strftime('%Y%m%d')
base_time = '2300'
else:
for i in range(1, 8): # 조회시간 별 가장 최근의 API제공 시간을 계산
if now_date.time() < std[i]:
base_date = now_date.strftime('%Y%m%d')
base_time = std_time[i - 1]
break
URL = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst'
key = '인증키'
params = {'serviceKey' : key,
'numOfRows' : 144,
'dataType' : 'JSON',
'pageNo' : 1,
'base_date' : base_date,
'base_time' : base_time,
'nx' : 61,
'ny' : 126
}
response = requests.get(URL, params=params)
print(response.status_code)
print(response.url)
print(response.text)
이렇게 요청을 날리게 되면, JSON 파일이 날아옵니다.
그렇게 날라온 파일을 복사해서, 웹 JSON parser를 이용해서 한번 쭉 보기좋게 정리해 줍니다.
이렇게 정리해서 옆에 띄워두고, 어떤 데이터를 뽑아낼지 보기에 편합니다!
정리된 JSON파일과, 기상청 API의 문서의 응답 메세지 변수 설명을 함께 보다보면 이제 느낌이 옵니다.
이 파일은 1시간 단위로 12개의 기상 정보가 있다는 것을 알 수 있습니다.
1
2
3
4
5
6
7
8
9
10
import json
...
response = requests.get(URL, params=params)
response_json = json.loads(response.content) # JSON문자열을 파이썬 객체로 변환
for i in range(0, 12):
item = response_json['response']['body']['items']['item'][i]['category']
print(item)
이제는 정말 쉽습니다.
JSON파일에서 필요한 변수가 있는 위치까지 한번 출력해 보면서, 원하는 값을 찾으면 됩니다.
위의 코드는 받은 JSON 데이터 파일에서 category에 해당하는 value값들을 찍어보았습니다.
드디어 Python으로 날씨 예측 서비스 만들기
Python으로 기상청 API를 사용해 JSON데이터를 받아 내가 원하는 값 출력하기
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import requests
import datetime
import json
# 코드를 실행 순간을 기준으로 base_date, base_time 파라미터 값을 결정
now_date = datetime.datetime.now()
base_date = '00000000'
base_time = '0000'
std = [ # API제공 시간, 년월일은 더미값
datetime.datetime(2023, 1, 1, 2, 10).time(),
datetime.datetime(2023, 1, 1, 5, 10).time(),
datetime.datetime(2023, 1, 1, 8, 10).time(),
datetime.datetime(2023, 1, 1, 11, 10).time(),
datetime.datetime(2023, 1, 1, 14, 10).time(),
datetime.datetime(2023, 1, 1, 17, 10).time(),
datetime.datetime(2023, 1, 1, 20, 10).time(),
datetime.datetime(2023, 1, 1, 23, 10).time()
]
std_time = ['0200', '0500', '0800', '1100', '1400', '1700', '2000', '2300']
if now_date.time() < std[0]: # 조회시간 < 2시 10분
now_date = now_date - datetime.timedelta(days=1) # 현재 날짜에서 하루 빼기
base_time = '2300'
elif now_date.time() >= std[7]: # 조회시간 >= 23시 10분
base_time = '2300'
else:
for i in range(1, 8): # 조회시간 별 가장 최근 시간
if now_date.time() < std[i]:
base_time = std_time[i - 1]
break
base_date = now_date.strftime('%Y%m%d')
# requests.get 모듈 사용해서 기상청에 데이터를 요청하고 JSON파일로 데이터 받기
URL = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst'
key = '인증키'
params = {'serviceKey' : key,
'numOfRows' : 144,
'dataType' : 'JSON',
'pageNo' : 1,
# 'base_date' : '20231010',
'base_date' : base_date,
'base_time' : base_time,
'nx' : 61,
'ny' : 126
}
response = requests.get(URL, params=params) # 응답
if(response.status_code == 200): # 응답 코드가 200(서버에서 정상적인 응답을 보내줌)
try: # 정상적으로 JSON데이터를 받았다면
response_json = json.loads(response.content) # JSON문자열을 파이썬 객체로 변환
item = response_json['response']['body']['items']['item']
time = [] # 예보시각=
tmp = [] # 온도
pop = [] # 강수확률
# 받은 JSON데이터에서 예보시각, 온도, 강수확률에 해당하는 변수들을 파싱하여 배열에 저장
for i in range(0, 144):
category = item[i]['category']
if category == 'TMP': # key값이 온도(TMP)인 value들을 리스트에 저장, 예보시간도 함께 저장
time.append(item[i]['fcstTime'])
tmp.append(item[i]['fcstValue'])
elif category == 'POP': # key값이 강수확률(POP)인 value들을 리스트에 저장
pop.append(item[i]['fcstValue'])
# 값 출력
print('======================')
print('시간 | 기온 | 강수확률')
print('======================')
for i in range(0, 12):
print(time[i][0] + time[i][1] + '시 | ' + tmp[i] + '도 | ' + pop[i] + '%')
except:
print(response.content)
else:
print(response.status_code)
최종적으로 작성한 코드입니다. if문과, try except구문을 사용해서 응답에 대한 예외처리도 해 주었습니다.
조회시간 기준으로 앞으로 12시간동안의 기온, 강수확률 데이터를 알려줍니다.
API를 사용할때 알맞지 않는 파라미터값을 보내면, 오류 메세지가 날라옵니다.
예를 들어, 2일전의 날씨 데이터를 요청하면 에러코드 03번, 오류코드표를 참고해 보면 ‘데이터 없음 에러’가 뜹니다.
반면에 적절한 파라미터를 전송하면 우리가 원하는 데이터를 얻을 수 있습니다.
API 서비스에 대한 가이드 문서를 잘 참고하여 예외처리를 하는 등의 작업이 필요합니다.
Python으로 날씨 예측 서비스 만들기 성공!
( 이 게시글은 저의 첫번째 블로그의 게시글 네이버 블로그 ‘호기심 대마왕 공대생’ 에서도 보실 수 있습니다. )