이번 개인 프로젝트에는 일평균 기온이 필요하다.
데이터 소스를 찾다가, 기상청에서 API를 통해 기상 관측 관련 정보를 제공하는 것을 확인.
기상청 API 사용 관련 블로그 글들을 읽어봤는데, 데이터 수집보다는 단기 예보 정보를 API를 통해 수집하여 다른 개빌에 활용하는 경우가 더 많았다.
나는 JSON으로 호출한 다음 DataFrame으로 데이터를 변환하고 싶은데, 관련 내용은 찾기가 어려워 그냥 하나씩 고쳐가며 수집 방법을 찾아봤다.
1. 기상청 API 허브
기상청에서 제공하는 API 허브 사이트. 여기서 API를 통해 무료로 데이터를 받을 수 있다.
단, 회원가입과 필요로 하는 항목 별로 활용신청이 필요하다.
2. 특정 기간 내의 일일 데이터 받기
* 25년 1월 기준
[ 지상관측 ] ▶ [ 종관지상관측 ] ▶ [ 1. 지상관측자료 조회 ] ▶ [ 호출URL정보 - 일자료(기간 조회) ]
처음 지상관측 페이지에 들어가면 url이 여러 개 있는데, 그 중에서 네 번째 url 이다.
시간 단위로 하루의 데이터만 출력되거나, 최근 한 달 데이터만 출력되는 등, 서로 호출되는 데이터가 다르니 참고.
3. Python으로 API 호출하기
java, js, C/C++, Node.js 등 다른 언어로 호출 가능하지만, 나는 Python으로 호출했다.
최상단에 언어 별로 예제 코드를 제시하고 있지만, 1차 시도 때 잘 되지 않아 나는 예제 코드 활용 실패.
- 사용한 라이브러리들
# import
import requests
import pprint
import json
import pandas as pd
from io import StringIO
import re
- url 발행
- https://apihub.kma.go.kr/api/typ01/url/kma_sfcdd3.php?tm1=20151211&tm2=20151214&stn=108&help=1&authKey='YOUR API KEY'
- 노란 부분에 원하는 값으로 변경하여 사용하면 된다.
- help 는 있는 게 각 컬럼 별로 어떤 값인지 알 수 있어 좋긴 한데, 가공할 때는 행수를 불필요하게 늘려서 없는 게 편하다. 가능하면 help=0과 help=1 을 둘 다 호출하는 게 좋을 것 같다.
request는 예전에 사용해봤지만, 계속 에러가 발생하고 JSON 형태로 저장이 되지 않아 지피티의 도움으로 코드를 짰다.
그리고 확인한 request.text 내용은 아래와 같았다. (호출 url : help=1)
일단 호출은 성공적이었지만, dataframe으로 변환하기 위해서는 약간의 가공과... 수정이 필요한 상태로 값이 출력되는 것을 알 수 있다.
컬럼 별 설명해주는 행이 너무 많아서, (호출 url : help=0) 으로 다시 호출.
네 번째 줄과 다섯 번째 줄을 합친 게 각 컬럼명이고, 여섯 번째 줄은 각 컬럼 별 수치의 단위이다.
즉, 4 ~ 6번째 줄을 합쳐야 한 줄짜리 헤더가 완성됨.
빈 칸이 존재하므로 합칠 때 확인 필요.
아래 코드의 결과로 dataframe은 결측치 없이 성공적으로 출력되었다.
# API 요청
url_period = 'https://apihub.kma.go.kr/api/typ01/url/kma_sfcdd3.php?tm1=20140101&tm2=20250107&stn=108&help=0&authKey="YOUR_API KEY"'
response_period = requests.get(url_period)
# 응답 데이터 처리
if response_period.status_code == 200:
raw_text = response_period.text # 데이터 텍스트로 변환
cleaned_text = re.sub(r'#.*', '', raw_text) # 주석 제거
cleaned_lines = [line for line in cleaned_text.splitlines() if line.strip()] # 불필요한 빈 줄 제거
cleaned_text = "\n".join(cleaned_lines)
# get column headers
col_names = raw_text.split('\n')[2]
col_names = col_names.split(" ")
col_names_detail = raw_text.split('\n')[3]
col_names_detail = col_names_detail.split(" ")
col_names_units = raw_text.split('\n')[4]
col_names_units = col_names_units.split(" ")
list_col = []
for i in col_names:
if i != ',' and i != '':
list_col.append(i)
list_col = list_col[1:]
list_col_detail = []
for j in col_names_detail:
if j != ',' and j != '':
list_col_detail.append(j)
list_col_detail = list_col_detail[1:]
list_col_units = []
for k in col_names_units:
if k != ',' and k != '':
list_col_units.append(k)
list_col_units = list_col_units[1:]
list_col_units = [f"({item})" for item in list_col_units] # 단위는 괄호 안에 들어가도록 편집
# raw data 상 공백이 있는 위치에 공백 삽입 : detail -> 22, 23 / units -> 0, 1, 35
list_col_detail.insert(22, ' ')
list_col_detail.insert(22, ' ')
list_col_units.insert(35, ' ')
list_col_units.insert(0, " ")
list_col_units.insert(0, " ")
col_names_for_use = [" ".join(pair) for pair in zip(list_col, list_col_detail, list_col_units)]
# DataFrame으로 변환
try:
data = pd.read_csv(StringIO(cleaned_text), delim_whitespace=True, header=None, names=col_names_for_use)
print(data)
except ValueError:
print("CSV 형식으로 변환할 수 없습니다.")
else:
print("API 요청 실패:", response_period.status_code)
print("응답 내용:", response_period.text)
4. Further Study
- 호출 url 에서 확인 가능하다시피, station number가 108 로 고정되어 있다.
[ 지상관측 ] ▶ [ 지상관측 지점정보 ] 에서 추가로 API 사용 신청을 하여 관측소의 위치값을 받아와야 하는데, 누락하여 추가 작업이 필요함 - API 사용 관련하여, 공개 리포에 코드 업로드 예정이지만 아직 완료하지는 못함.
일단 주소는 아래 참고. 관련된 코드들(나중에 EDA 관련 등)도 업데이트 할 예정
'프로젝트 > 관련 스터디' 카테고리의 다른 글
[돈독한 가계부_02] 템플릿에 삽입할 더미 데이터(dummy data) 생성하기 (10) | 2024.11.07 |
---|---|
[돈독한 가계부_01] 프로젝트를 위한 DB 설계 여정_어렵다! (2) | 2024.11.04 |
Python으로 PDF 파일 표로 읽고, csv 파일로 변환하기 (3) | 2024.10.11 |