>

상세 컨텐츠

본문 제목

기상청 날씨 api를 내 사이트에 적용해보자 & 웹api(api url) 만들기

7. 봉드로이드_개발공부

by 마켓플레이어, 마케터 봉 2024. 11. 1. 18:33

본문

공공데이터포털에 접속해 인증키값을 받고, 데이터를 확인해보는 과정을 해봤다.

https://marketerbong.tistory.com/99

 

이제, 여기서 받은 정보를 내 사이트에 적용해보자.

내가 원하는 것은 아래 이미지처럼 현재 온도이다.

 

 

기본적인 파이썬 코드는 다음과 같다.

from flask import Flask, request, jsonify
from datetime import datetime
import requests

app = Flask(__name__)

@app.route('/weather', methods=['GET'])
def get_weather():
    # Retrieve current date and time
    now = datetime.now()
    base_date = now.strftime("%Y%m%d")  # Format: YYYYMMDD
    base_time = now.strftime("%H%M")    # Format: HHMM (24-hour clock)

    # Retrieve latitude and longitude from query parameters
    nx = request.args.get('nx')
    ny = request.args.get('ny')

    # Check if nx and ny were provided
    if not nx or not ny:
        return jsonify({"error": "Latitude (nx) and Longitude (ny) are required"}), 400

    # Construct the API URL with real-time parameters
    api_url = f"https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst" \
              f"?serviceKey=이건디코딩키값넣으세요" \
              f"kW%2BcJaIK6g%3D%3D&pageNo=1&numOfRows=1000&dataType=json" \
              f"&base_date={base_date}&base_time={base_time}&nx={nx}&ny={ny}"

    # Make the request to the external API
    try:
        response = requests.get(api_url)
        response.raise_for_status()  # Check if the request was successful
        data = response.json()
        return jsonify(data)  # Return the API response in JSON format
    except requests.exceptions.RequestException as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

 

근데, 저렇게 하면 안될 것이다.

왜냐하면 위치정보를 알 수 없기 때문이다.

 

아래의 과정이 추가로 필요하다.

1. 현재 gps 좌표 정보를 업데이트 한 후 전달하기

2. gps 좌표를 받은 후 경도/위도를 nx, ny값으로 치환하기

 

번외로 아래 2가지 작업도 필요하다.

3. 내 사이트는 블루프린트로 페이지를 관리한다. 그렇기에 블루프린트 처리도 해줘야한다.

4. 만약 gps 좌표를 못불러올 경우 지정 좌표로 쏴주기. (구글지도나 크롬 같은 브라우저에서 현재 위치 확인 미허용을 누른 경우에 해당)

 

일단 1번과 3번은 자바스크립트로 작업했기에, 2번과 4번을 반영한 스크립트를 공유한다.

1) 엑셀파일이 한글로 너무 길어서 nxny.xlsx로 파일명을 바꿔, pandas로 불러왔다 (이건 sql, 데이터 분석을 하는 마케터라면 조금 익숙할 것이다)

2) 현재 좌표에서 가까운 nx, ny를 찾는다.

3) 날씨 라우터에서 현재날짜, 현재시간, 경도, 위도를 변수로 설정하여, api 요청 url에 넣었다.

from flask import Flask, request, jsonify, Blueprint
from datetime import datetime
from geopy.distance import geodesic
import requests
import pandas as pd

# Flask 블루프린트 설정
bp = Blueprint("api_weather", __name__)

# 위치 데이터 파일 불러오기 (파일 경로 확인 필요)
location_data = pd.read_excel('static/file/nxny.xlsx')[['격자 X', '격자 Y', '경도(초/100)', '위도(초/100)']]

# 가장 가까운 격자 좌표(nx, ny) 찾는 함수
def find_nearest_grid_coordinates(latitude, longitude):
    min_distance = float('inf')
    nearest_nx = None
    nearest_ny = None
    
    for _, row in location_data.iterrows():
        grid_point = (row['위도(초/100)'], row['경도(초/100)'])
        distance = geodesic((latitude, longitude), grid_point).meters
        if distance < min_distance:
            min_distance = distance
            nearest_nx = row['격자 X']
            nearest_ny = row['격자 Y']
    
    return nearest_nx, nearest_ny

# 날씨 API 라우트 설정
@bp.route('/', methods=['GET'])
def get_weather():
    print("Received parameters:", request.args)

    # 현재 날짜와 시간 가져오기
    now = datetime.now()
    base_date = now.strftime("%Y%m%d")
    base_time = now.strftime("%H%M")

    # 쿼리 파라미터에서 위도와 경도 가져오기
    latitude = request.args.get('latitude')
    longitude = request.args.get('longitude')

    # 위도와 경도 값 검증
    if latitude is None or longitude is None:
        print(f"Missing parameters: latitude={latitude}, longitude={longitude}")  # Debug log
        return jsonify({"error": "Both latitude and longitude parameters are required"}), 400

    # 위도와 경도를 float로 변환
    try:
        latitude = float(latitude)
        longitude = float(longitude)
    except ValueError:
        return jsonify({"error": "Latitude and longitude must be valid numbers"}), 400

    # 가장 가까운 격자 좌표 찾기
    nx, ny = find_nearest_grid_coordinates(latitude, longitude)
    if nx is None or ny is None:
        return jsonify({"error": "Unable to find nearest grid coordinates"}), 500

    # API 요청 URL 생성
    api_url = (
        f"https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst"
        f"?serviceKey=디코딩키값을넣으면됩니다"
        f"kW%2BcJaIK6g%3D%3D&pageNo=1&numOfRows=1000&dataType=json"
        f"&base_date={base_date}&base_time={base_time}&nx={int(nx)}&ny={int(ny)}"
    )

    # 외부 API 호출 및 결과 반환
    try:
        response = requests.get(api_url)
        response.raise_for_status()  # HTTP 오류가 있으면 예외 발생
        data = response.json()
        return jsonify(data)  # API 응답을 JSON 형식으로 반환
    except requests.exceptions.RequestException as e:
        return jsonify({"error": str(e)}), 500

일단 위와 같이 만들면 url이 생긴다.

bongdroid.info/api_weater 라는 주소로 접속하면 api_weather 페이지가 json 형태로 나올 것이다.

즉, API URL(웹API)가 만들어진 것이다.

 

사실 "json url 만드는 법", "api url 만드는 방법" 등으로 검색해봤는데, 안나왔다.

그러다 우연히 웹API가 내가 만들려고 했던 api url인 것 같았다. 그래서 그걸로 검색해보니 얼추 나오더라.

 


이제 자바스크립트로 현재 경도/위도를 가져와야한다.

아참, geopy 라는 라이브러리 설치는 말안해도 하는 센스-👏

 

자바스크립트 코드는 다음과 같다.

1) 페이지가 불려오자마자 실행되어야 하기때문에 document.ready로 함수를 불러왔다.

2) navigator.geolocation으로 현재 좌표를 불러오고, 실패한다면 지정한 좌표값을 불러오도록 했다.

3) 불러온 좌표값을 fetchWeatherData 함수에 각각 위도/경도를 넣도록 했다.

4) Flask API URL에 위도와 경도를 전송하도록 했다.

5) 온도를 아이디값 temp에 넣으라고 했다.

    <script>
        $(document).ready(function () {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(success, error);
            } else {
                fetchWeatherData(37.563569, 126.980008333333); // Use default coordinates
            }

            function success(position) {
                const latitude = position.coords.latitude;
                const longitude = position.coords.longitude;
                fetchWeatherData(latitude, longitude);
            }

            function error() {
                console.warn("Unable to retrieve location. Using default coordinates.");
                fetchWeatherData(37.563569, 126.980008333333); // Use default coordinates
            }

            function fetchWeatherData(latitude, longitude) {
                // Send latitude and longitude to Flask API
                $.get(`/api_weather/`, { latitude: latitude, longitude: longitude })
                    .done(function (data) {
                        let temp = null;

                        // Loop through the items and find the "T1H" category
                        const items = data.response.body.items.item;
                        for (const item of items) {
                            if (item.category === "T1H") {
                                temp = item.obsrValue;
                                break;
                            }
                        }

                        // Display temperature or error message
                        if (temp !== null) {
                            $('#temp').text(`${temp}`);
                        } else {
                            $('#temp').text('Temperature data not available');
                        }
                    })
                    .fail(function () {
                        $('#temp').text('Error retrieving weather data');
                    });
            }
        });
    </script>

관련글 더보기