기상청에서 날씨데이터를 받아 사용하는 방법은 2가지로 볼 수 있다
RSS의 경우 XML 파싱작업을 해야 하지만 어짜피 JSON으로 받아도 파싱해야 하는건 매 한가지
그래도 범용성이 좋은 JSON을 이용하면 좋을 듯 싶어 API를 사용하기로 했다
전국의 날씨정보를 수집하고 DB에 저장하려는게 1차 목표였는데
날씨정보를 받으려니 RSS나 API나 행정동을 기준으로 데이터를 제공하고 있었다
(정확히는 관측소 기준)
우선 공공데이터 포탈에서 제공되는 OPEN API 중
동네예보정보조회 서비스(이하, 날씨정보)를 활용신청 후 신규동네예보조회서비스.zip 를 다운받았다
안에는 API 활용가이드와 기상청_동네예보 행정동 정보 엑셀파일이 있는데
엑셀에는 행정동기준으로 읍면동과 기상청 관측소 격자 정보와 위도, 경도 좌표 데이터를 제공하고 있다
하지만 위도, 경도로는 API를 사용할 수 없고 관측소 좌표정보 혹은 행정동으로 조회 하는 것 같았다
변환 프로그램 소스를 제공하기는하지만 행정동 위경도 기준으로 보인다
처음 글을 작성하던 당시와는 달리 최신파일을 다시 받아보니 엑셀 파일명이 변경되었고
위경도 정보가 삭제되었다… 실제로 위경도는 안쓰이니 상관없다…
사실 API문서 버전은 그대로라.. 엑셀파일만 바뀜...
관측지점 정보 : http://minwon.kma.go.kr/main/obvStn.do 에서도 조회 가능하다
DB에 데이터를 넣기 위해 행정동을 코드화 시키기로 했지만 제공되는 엑셀파일에는
행정동 코드가 없어... 코드를 새로 만들 것 없이 행정자치부에서 제공하는
행정동 코드정보와 데이터를 매칭해서 사용하기로 했다
행정자차부 > 업무안내 > 지방행정실 > 주민등록 및 안감 > 주민등록 및 안감 순으로 들어가면 된다
주민등록 및 안감 : http://www.moi.go.kr/frt/bbs/type001/commonSelectBoardList.do?bbsId=BBSMSTR_000000000052
사이트내에 주민등록주소코드 변경내역 중 최신글에서 다운받으면 된다
다운받은 jscode20160201.zip에는 (최신, jscode20160905.zip)
KIKcd_B 로 시작하는 법정동코드 정보
KIKcd_H 로 시작하는 행정동코드 정보
KIKmix 로 시작하는 행정동 법정동 맵핑 정보
파일을 제공한다.
법정동코드와 행정동코드가 다른 이유는 여기 참고
파일중 KIKcd_H를 사용한다 법정동코드와 매칭하여 사용하려면 KIKmix만 보면된다
근데 행정동과 법정동을 동시에 PK를 잡아야 중복이 발생안한다…
법정동코드와 행정동 코드둘다 사용하려면 각각 테이블을 구성하고 맵핑 테이블을 만들어서 사용해야 하는데.. 1:1로 매칭이 안된다 해보면 깊은 빡침을 느 낄 수 있다
데이터 구성을 위해
API에서 제공하는 격자 데이터 DB테이블을 만들었다
차례대로 시도, 시군구, 행정동, x좌표, y좌표, 경도(lng), 위도(lat) 으로 데이터가 들어있다
귀찬으니 테이블은 대충 만들었다
최신은 위경도데이터가 삭제되있으니 위경도를 지우면 된다
구버전 |
신버전 |
CREATE TABLE `weather_tmp` ( `si_nm` varchar(40) DEFAULT NULL, `gu_nm` varchar(40) DEFAULT NULL, `dong_nm` varchar(40) DEFAULT NULL, `nx` int(11) DEFAULT NULL, `ny` int(11) DEFAULT NULL, `lng` double DEFAULT NULL, `lat` double DEFAULT NULL ) DEFAULT CHARSET=utf8 |
CREATE TABLE `weather_tmp` ( `si_nm` varchar(40) DEFAULT NULL, `gu_nm` varchar(40) DEFAULT NULL, `dong_nm` varchar(40) DEFAULT NULL, `nx` int(11) DEFAULT NULL, `ny` int(11) DEFAULT NULL, ) DEFAULT CHARSET=utf8 |
행정동코드를 위해 행정동 코드 테이블을 생성했다
차례대로 행정동코드, 시도, 시군구, 행정동 으로 데이터가 구성되 있다
행정동 코드는 시도(2) + 시군구(3) + 행정동(3) + 리(2) 이렇게 10자리 코드를 가진다
CREATE TABLE `hang_dong_tmp` ( `hang_dong_cd` char(10) DEFAULT NULL, `si_nm` varchar(40) DEFAULT NULL, `gu_nm` varchar(40) DEFAULT NULL, `dong_nm` varchar(40) DEFAULT NULL, ) DEFAULT CHARSET=utf8 |
요약하자면
날씨정보 API에서 제공하는 엑셀에는 행정동 코드가 없어
행정동 코드가 있는 행정자치부에서 제공하는 데이터와 합치는 작업을 진행하는 것이다
* MySQL의 기능인 FILELOAD DATA INFILE 을 이용하려고 CSV로 변경하여 데이터를 넣을경우 인천 데이터 3개가 잘못들어가니 참고 하면 될 듯 (숭의1,3동, 용현1,4동, 도화2,3동) - 201602 기준 |
행정동 코드를 기준 사용하기위해 LEFT OUTER JOIN을 걸었다
이 경우 이어도는 행정동 코드가 없어 데이터가 안들어 가는 문제가 발생한다
이어도를 포함해서 넣으려면 LEFT OUTER JOIN이 아닌 RIGHT OUTER JOIN으로 넣으면 되지만
시도명, nx, ny 이외에는 데이터가 NULL이기 때문에 무의미 하다고도 볼 수 있겠다
(전국이라 말해놓고 이어도는 버리....ㅁ)
최신은 위경도데이터가 삭제되있으니 위경도를 지우면 된다
구버전 |
SELECT h.hang_dong_cd, h.si_nm, h.gu_nm, h.dong_nm, w.nx, w.ny, w.lat, w.lng FROM hang_dong_tmp as h LEFT OUTER JOIN weather_tmp as w ON h.si_nm = w.si_nm AND h.gu_nm = w.gu_nm AND h.dong_nm = w.dong_nm |
신버전 |
SELECT h.hang_dong_cd, h.si_nm, h.gu_nm, h.dong_nm, w.nx, w.ny FROM hang_dong_tmp as h LEFT OUTER JOIN weather_tmp as w ON h.si_nm = w.si_nm AND h.gu_nm = w.gu_nm AND h.dong_nm = w.dong_nm |
조회되는 정보는 행정동을 기준으로 구성되는 행정동 코드와 기상청에서 사용되는 관측소 좌표정보를 포함하게 된다
이제 행정동코드를 이용하여 데이터 조회를 할 수 있는 기초 데이터를 만들었다고 볼 수 있으나
중복되는 데이터가 존재하니 정규화를 통해 데이터를 분할 해야 할 필요가 있다
시도명, 시군구명을 포함하기 보다는 별도의 테이블로 구성해서
JOIN 하는 편이 용량 측면에서도 그렇고 효율적이라고 볼 수 있기 때문이다
시도, 시군구, 행정동 테이블을 구성하고 격자정보 테이블을 별도로 구성하면 될 것 같다
격자정보 테이블에는 이런 식으로 행정동코드와 x, y, lat, lng 만 넣으면 될테니 말이다
시도 |
시군구 |
행정동 |
리 |
x |
y |
lat |
lng |
11 |
000 |
000 |
00 |
60 |
127 |
37.563568115234375 |
126.98001098632812 |
11 |
110 |
000 |
00 |
60 |
127 |
37.570377349853516 |
126.98164367675781 |
11 |
110 |
515 |
00 |
60 |
127 |
37.584136962890625 |
126.97064971923828 |
신버전은 위경도가 없으니 lat, lng이 없다...
리의 경우 전부 00이 들어가니 없어도 된다 대신 법정동 코드와 맵핑시 내용이 좀 달라지는데
그때는 맵핑테이블을 만들고 리까지 넣어서 맵핑하면되니 사실 문제 될 것도 없다
완성된 테이블은 시도, 시군구, 행정동, 좌표(격자)테이블 이렇게 4개를 만들었다
근데 테이블데이터를 보게되면…
기상청 격자가 심이 많이 중복되는걸 볼수 있다
위에 보이는 데이터만해도 3개의 동이 하나의 관측소를 호출하고 있으니 말이다
데이터 제공 방식에 따라 2가지로 구분할 수 있겠다
1번의 경우 서버에 데이터를 저장하질 않으니 행정동의 변동만 신경쓰면 된다 (최신 API데이터 반영)
2번의 경우 DB에 날씨정보를 지속적으로 쌓아야 하니 용량에도 신경을 쓰야한다
API에서 제공하는 서비스는
초단기실황조회, 초단기예보조회, 동네예보조회, 예보버전조회 이렇게 4가지에 대해
제공하고 있으며 이중 예보버전조회만 다른 성향을 가지고 있다
초단기실황조회 |
실황정보를 조회하기 위해 발표일자, 발표시각, 예보지점 X 좌표, 예보지점 Y 좌표의 조회 조건으로 자료구분코드, 실황값, 발표일자, 발표시각, 예보지점 X 좌표, 예보지점 Y 좌표의 정보를 조회하는 기능 |
초단기예보조회 |
초단기예보정보를 조회하기 위해 발표일자, 발표시각, 예보지점 X 좌표, 예보지점 Y 좌표의 조회 조건으로 자료구분코드, 예보값, 발표일자, 발표시각, 예보지점 X 좌표, 예보지점 Y 좌표의 정보를 조회하는 기능 |
동네예보조회 |
동네예보 정보를 조회하기 위해 발표일자, 발표시각, 예보지점 X좌표, 예보지점 Y 좌표의 조회 조건으로 발표일자, 발표시각, 자료구분문자, 예보 값, 예보일자, 예보시각, 예보지점 X 좌표, 예보지점 Y 좌표의 정보를 조회하는 기능 |
예보버전조회 |
동네예보정보조회서비스 각각의 오퍼레이션(초단기실황, 초단기예보, 동네예보)들의 수정된 예보 버전을 파악하기 위해 예보버전을 조회하는 기능 |
서비스 이용을 위한 필수 값 중 위치정보는 관측소 격자정보만 들어가며 (예보버전조회 제외)
필수 값은 서비스키, 발표일자, 발표시각, 예보지점 X, Y좌표 이렇게 5의 정보를 필요로 한다
ServiceKey |
서비스 키 |
base_date |
발표일자 |
base_time |
발표시각 |
nx |
예보지점 X 좌표 |
ny |
예보지점 Y 좌표 |
End Point 는 http://newsky2.kma.go.kr/service/SecndSrtpdFrcstInfoService2 로 모두 동일하다
서비스 별로 응답이 다르기때문에 데이터 파서는 서비스별로 구현하지만
요청은 단일 프로세스에 서비스만 변경해주면 되겠다 End Point 뒤에 들어가는 URL
Ex) http://newsky2.kma.go.kr/service/SecndSrtpdFrcstInfoService2/ ForecastSpaceData
모든예보는 카테고리별로 구분되는 코드(자료구분문자)와 매핑해야 한다 ( 기술문서 참고)
초단기실황조회를 사용해야 현재온도를 알수 있다 나머진 예보니...
테스트를 위해 서울의 날씨정보를 조회하였다
http://newsky2.kma.go.kr/service/SecndSrtpdFrcstInfoService2/ForecastGrib ? ServiceKey=서비스키 &nx=60 //예보지점 X좌표 &ny=127 //예보지점 Y좌표 &base_date=20160225 //발표일자 &base_time=2100 //발표시각으로 8회로 정해진 시각이용 &_type=json //json 데이터 반환 |
REST 방식으로 제공하기 때문에 브라우져에서도 테스트가 가능하다
문서 어딜봐도 json data라고 응답메시지만 보이지 요청방법은 없다.. &_type=json 이라고 넣어주자..
{ "response":{"header":{"resultCode":"0000","resultMsg":"OK"} ,"body":{"items":{"item":[ {"baseDate":20160225,"baseTime":1700,"category":"REH","nx":60,"ny":127,"obsrValue":44} ,{"baseDate":20160225,"baseTime":1700,"category":"RN1","nx":60,"ny":127,"obsrValue":0} ,{"baseDate":20160225,"baseTime":1700,"category":"SKY","nx":60,"ny":127,"obsrValue":4} ,{ "baseDate":20160225 //발표일자 ,"baseTime":1700 //발표시각 ,"category":"T1H" //(기온) 자료구분코드 참조 ,"nx":60,"ny":127 //예보지점 X, Y 좌표 ,"obsrValue":26.4 //실황 값 } ] } ,"numOfRows":20,"pageNo":1,"totalCount":10}} } |
데이터를 보게되면 성공을 의미하는 OK가 존재하는것을 알 수 있다
근데 URL말고 필수값 조금 틀린다고 OK가 안나오는건 아니다…. URL틀리면 없는페이지…
동네예보의 경우 예보이기때문에 현재를 기준으로 데이터를 조회 할 수 없다..
4시간 단위기때문에 현재시간 이전 발표시간으로 조회 해야 (현재를…?) 하며 온도는
3시간 온도를 나타낸다 말그대로 예보이기 때문에 초단기실황조회가 실시간에 적합하다
- Base_time : 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 (1일 8회)
- API 제공 시간(~이후) : 02:30, 05:30, 08:30, 11:30, 14:30, 20:30, 23:30
테스트를 위해 서울의 날씨정보를 조회하였다
과거 데이터의 경우 나오지 않으니 (삭제되니) 현재시각 기준으로 조회해야한다
http://newsky2.kma.go.kr/service/SecndSrtpdFrcstInfoService2/ForecastSpaceData ? ServiceKey= 서비스키 &nx=60 //예보지점 X 좌표 &ny=127 //예보지점 Y 좌표 &base_date=20160225 //발표일자 &base_time=2100 //발표시각 (정해진 시각이용) |
{ "response":{"header":{"resultCode":"0000","resultMsg":"OK"}, "body":{"items":{"item":[ { "baseDate":20160225 //발표일자 ,"baseTime":2000 //발표시각 ,"category":"POP" //자료구분 참조 ,"fcstDate":20160226 //예보일자 ,"fcstTime":"0000" //예보시각 ,"fcstValue":20 //예보 값 ,"nx":60 //예보지점 X 좌표 ,"ny":127 //예보지점 Y 좌표 } ,{"baseDate":20160225,"baseTime":2000,"category":"PTY" ,"fcstDate":20160226,"fcstTime":"0000","fcstValue":0,"nx":60,"ny":127} ] } ,"numOfRows":10,"pageNo":1,"totalCount":175}} } |
실황과 달리 4시간단위로 데이터를 제공하며 매 시각 온도를 보여주진 않는다
공공데이터 API - 대전광역시 버스정보 3부 (정류소별 도착정보 조회 서비스) (0) | 2017.08.28 |
---|---|
공공데이터 API - 대전광역시 버스정보 2부 (정류소정보조회 서비스, 버스위치정보 조회 서비스) (0) | 2017.08.14 |
공공데이터 API - 대전광역시 버스정보 1부 (노선정보조회 서비스) (14) | 2017.07.24 |
Tistory BlogAPI 중단 (MS WORD BLOGAPI) (4) | 2016.12.23 |
기상청 지진정보조회 API (지진정보조회 API) (9) | 2016.10.04 |
댓글 영역