project/personal project

[API] 공공데이터 기상청 API 기능 구현

박허디 2024. 1. 17. 21:02

참조 홈페이지 

https://www.data.go.kr/

카카오맵과 마찬가지로 코드를 작성하기 전에 먼저 위 사이트에 들어가서 만들어 줘야 될 것들이 있다.

먼저 위 공공데이터포털 사이트에 들어가서 회원가입 한 후 

 

 

원하는 데이터를 입력해 준 후

 

아래쪽에 보이는 오픈 API에 들어간 후 

 

 

본인이 원하는 데이터에 활용신청을 한 후 

메인 페이지에서 마이페이지로 들어가면 아래와 같은 화면이 보이는데 

API신청을 클릭하면 

신청되어 있는 글에 들어가 보면 본인이 부여받은 키를 확인할 수 있는데

그 키를 이용해서 코드를 작성하면 된다.

 

++

 

활용 신청 상세기능정보에서 이용하려는 데이터의 요청변수가 어떤 식으로 나오는지 미리 볼 수 있는 기능도 있으니 이용하면 좋다.

 

이런 식으로 확인할 수 있다.

 

또 개발계정 상세보기에서 기본정보에서 상세설명을 클릭하면 출력결과도 확인할 수 있다.

 

 

 

관련 화면

 

사진과 같이 지역을 입력해서 검색하면 입력한 지역에 맞게 날씨와 관련 정보들을 보여준다.

 

관련 코드
1.  JavaScript 작성
/* Javascript 샘플 코드 */


var xhr = new XMLHttpRequest();
var url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst'; /*URL*/
var queryParams = '?' + encodeURIComponent('serviceKey') + '='+'서비스키'; /*Service Key*/
queryParams += '&' + encodeURIComponent('pageNo') + '=' + encodeURIComponent('1'); /**/
queryParams += '&' + encodeURIComponent('numOfRows') + '=' + encodeURIComponent('1000'); /**/
queryParams += '&' + encodeURIComponent('dataType') + '=' + encodeURIComponent('JSON'); /**/
queryParams += '&' + encodeURIComponent('base_date') + '=' + encodeURIComponent('20210628'); /**/
queryParams += '&' + encodeURIComponent('base_time') + '=' + encodeURIComponent('0600'); /**/
queryParams += '&' + encodeURIComponent('nx') + '=' + encodeURIComponent('55'); /**/
queryParams += '&' + encodeURIComponent('ny') + '=' + encodeURIComponent('127'); /**/
xhr.open('GET', url + queryParams);
xhr.onreadystatechange = function () {
    if (this.readyState == 4) {
        alert('Status: '+this.status+'nHeaders: '+JSON.stringify(this.getAllResponseHeaders())+'nBody: '+this.responseText);
    }
};

xhr.send('');

 

 

공공데이터 포털 홈페이지에서 제공하는 javascript 샘플 코드에서

 

'서비스키'에 일반 인증키(Encoding)를 붙여 넣는다.

let latPoint = "";  // 위도
let lonPoint = "";  // 경도
let xPoint = "";    // 격자 x 포인트
let yPoint = "";    // 격자 y 포인트

// 위도, 경도
let xValue = parseFloat(result[0].x);
let yValue = parseFloat(result[0].y);

latPoint = yValue;  // 위도
lonPoint = xValue;  // 경도

 

 

주소에 따른 위도, 경도 값을 통해 해당 위치의 현재 기상 정보를 조회하는데

 

일단 위도, 경도 값이 아닌 기상 정보 API에서 요구하는 격자 x, y 포인트 값으로 조회한다.

 

위도, 경도는 이전에 작성했던 카카오맵 geocoder에서 뽑았다.

 

    // 현재 날짜 구하기
    let currentDate = new Date();
    let year = currentDate.getFullYear();
    let month = ('0' + (currentDate.getMonth() + 1)).slice(-2);
    let day = ('0' + currentDate.getDate()).slice(-2);
    let formattedDate = year + month + day;

    // 시간 구하기
    let hours = ('0' + currentDate.getHours()).slice(-2);
    let minutes = ('0' + (currentDate.getMinutes() - 30)).slice(-2);

    // 만약 minutes가 30보다 작으면 hours에서 1을 빼주기
    if (currentDate.getMinutes() < 30) {
        hours = ('0' + (currentDate.getHours() - 1)).slice(-2);
        minutes = ('0' + (currentDate.getMinutes() + 30)).slice(-2);
    }

    let formattedTime = hours + minutes;

    // 좌표를 격자 x,y point로 바꾸기
    let result = dfs_xy_conv("toXY", latPoint, lonPoint);
    console.log("X:", result.x, "Y:", result.y);

    xPoint = result.x;
    yPoint = result.y;

 

샘플 코드에 요청 변수에 조회하고 싶은 값을 입력한다.

base_date는 20240117 형식으로

base_time은 1730 형식으로

nx와 ny에는 변환된 x, y 포인트 값을 입력한다.

 

주의할 점은 base_time 발표시각은 30분마다 갱신되는 거여서 현재 시간에서 30분 전 시간을 입력해야 된다.

 

/** 위도, 경도를 x,y 격자 포인트로 변경 */
var RE = 6371.00877; // 지구 반경(km)
var GRID = 5.0; // 격자 간격(km)
var SLAT1 = 30.0; // 투영 위도1(degree)
var SLAT2 = 60.0; // 투영 위도2(degree)
var OLON = 126.0; // 기준점 경도(degree)
var OLAT = 38.0; // 기준점 위도(degree)
var XO = 43; // 기준점 X좌표(GRID)
var YO = 136; // 기1준점 Y좌표(GRID)

// LCC DFS 좌표변환 ( code : "toXY"(위경도->좌표, v1:위도, v2:경도), "toLL"(좌표->위경도,v1:x, v2:y) )
function dfs_xy_conv(code, v1, v2) {
    // LCC DFS 좌표변환을 위한 기초 자료
    var DEGRAD = Math.PI / 180.0;
    var RADDEG = 180.0 / Math.PI;

    var re = RE / GRID;
    var slat1 = SLAT1 * DEGRAD;
    var slat2 = SLAT2 * DEGRAD;
    var olon = OLON * DEGRAD;
    var olat = OLAT * DEGRAD;

    var sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5);
    sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn);
    var sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
    sf = Math.pow(sf, sn) * Math.cos(slat1) / sn;
    var ro = Math.tan(Math.PI * 0.25 + olat * 0.5);
    ro = re * sf / Math.pow(ro, sn);
    var rs = {};
    if (code == "toXY") {
        rs['lat'] = v1;
        rs['lng'] = v2;
        var ra = Math.tan(Math.PI * 0.25 + (v1) * DEGRAD * 0.5);
        ra = re * sf / Math.pow(ra, sn);
        var theta = v2 * DEGRAD - olon;
        if (theta > Math.PI) theta -= 2.0 * Math.PI;
        if (theta < -Math.PI) theta += 2.0 * Math.PI;
        theta *= sn;
        rs['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
        rs['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
    }
    else {
        rs['x'] = v1;
        rs['y'] = v2;
        var xn = v1 - XO;
        var yn = ro - v2 + YO;
        ra = Math.sqrt(xn * xn + yn * yn);
        if (sn < 0.0) - ra;
        var alat = Math.pow((re * sf / ra), (1.0 / sn));
        alat = 2.0 * Math.atan(alat) - Math.PI * 0.5;

        if (Math.abs(xn) <= 0.0) {
            theta = 0.0;
        }
        else {
            if (Math.abs(yn) <= 0.0) {
                theta = Math.PI * 0.5;
                if (xn < 0.0) - theta;
            }
            else theta = Math.atan2(xn, yn);
        }
        var alon = theta / sn + olon;
        rs['lat'] = alat * RADDEG;
        rs['lng'] = alon * RADDEG;
    }
    return rs;

}

 

위 코드는 위도, 경도, x, y 격자 포인트 변경하는 코드 함수다.

 

var xhr = new XMLHttpRequest();
    var url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst'; /*URL*/
    var queryParams = '?' + encodeURIComponent('serviceKey') + '='+'5CZW8vE4f16CFpvpKdt5RwisoNCWGjCG%2FlZqcpESy8NaGCdcB8vPI6aDpHCKyQcqTImAERfoVVHuzLJsaDHitg%3D%3D'; /*Service Key*/
    queryParams += '&' + encodeURIComponent('pageNo') + '=' + encodeURIComponent('1'); /* 페이지 번호 */
    queryParams += '&' + encodeURIComponent('numOfRows') + '=' + encodeURIComponent('1000'); /* 한 페이지 결과 수 */
    queryParams += '&' + encodeURIComponent('dataType') + '=' + encodeURIComponent('JSON'); /* 응답자료형식 */
    queryParams += '&' + encodeURIComponent('base_date') + '=' + encodeURIComponent(formattedDate); /* 발표일자 */
    queryParams += '&' + encodeURIComponent('base_time') + '=' + encodeURIComponent(formattedTime); /* 발표시각 */
    queryParams += '&' + encodeURIComponent('nx') + '=' + encodeURIComponent(xPoint); /* 예보지점 X 좌표 */
    queryParams += '&' + encodeURIComponent('ny') + '=' + encodeURIComponent(yPoint); /* 예보지점 Y 좌표 */
    xhr.open('GET', url + queryParams);
    xhr.onreadystatechange = function () {
        if (this.readyState == 4) {
            if (this.status == 200) {
                console.log("Success!");

                // JSON 파싱
                var jsonResponse = JSON.parse(this.responseText);

                // 필요한 정보 추출
                var items = jsonResponse.response.body.items.item;

                console.log("items length: " + items.length);

                for (var i = 0; i < items.length; i++) {
                    var item = items[i];

                    console.log("item: " + JSON.stringify(item));
                    console.log("자료구분코드: " + item.category);
                    console.log("예보일자: " + item.fcstDate);
                    console.log("예보시각: " + item.fcstTime);
                    console.log("예보값: " + item.fcstValue);
                    
                }

            } else {
                console.log("Error: " + this.status);
            }
        }
    };

    xhr.send('');

 

준비된 요청 변수를 통해서 현재 위치에 따른 기상 정보를 조회한다.

 

완성된 화면