import os import requests import csv from datetime import datetime, timedelta import concurrent.futures import threading import time # 1. API 인증키 설정 def get_env_variable(var_name): if os.path.exists(".env"): with open(".env", "r") as f: for line in f: if "=" in line: k, v = line.split("=", 1) if k.strip() == var_name: return v.strip() return os.getenv(var_name) API_KEY = get_env_variable("WEATHER_KEY") or get_env_variable("KMA_API_KEY") TARGET_LAT = 34.925323 TARGET_LON = 127.710838 BASE_URL = "https://apihub.kma.go.kr/api/typ01/url/sfc_nc_var.php" OBS_ELEMENTS = "ta,hm,td,wd_10m,ws_10m,uu,vv,rn_ox,vs" INTERVAL = 5 # 추출 기간 start_dt = datetime(2026, 4, 1, 0, 0) end_dt = datetime(2026, 5, 7, 23, 55) def fetch_chunk(tm1, retries=2): tm2 = tm1 + timedelta(minutes=55) params = { "tm1": tm1.strftime("%Y%m%d%H%M"), "tm2": tm2.strftime("%Y%m%d%H%M"), "obs": OBS_ELEMENTS, "itv": INTERVAL, "lon": TARGET_LON, "lat": TARGET_LAT, "help": 0, "authKey": API_KEY } for attempt in range(retries): try: response = requests.get(BASE_URL, params=params, timeout=30) response.raise_for_status() rows = [] for line in response.text.strip().split('\n'): if line.startswith('#') or not line.strip(): continue parts = [p.strip() for p in line.replace(',', ' ').split()] if len(parts) >= 10: rows.append({ "tm": parts[0], "ta": parts[1], "hm": parts[2], "td": parts[3], "wd_10m": parts[4], "ws_10m": parts[5], "uu": parts[6], "vv": parts[7], "rn_ox": parts[8], "vs": parts[9] }) return rows except Exception: if attempt < retries - 1: time.sleep(1) else: return [] def main(): time_chunks = [] curr = start_dt while curr <= end_dt: time_chunks.append(curr) curr += timedelta(hours=1) print(f"--- 연속 데이터 추출 시작 (총 {len(time_chunks)}개 구간, 5개 스레드) ---") output_filename = "weather_data_continuous_20260401_20260507.csv" keys = ["tm", "ta", "hm", "td", "wd_10m", "ws_10m", "uu", "vv", "rn_ox", "vs"] all_data = [] completed = 0 lock = threading.Lock() with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: future_to_chunk = {executor.submit(fetch_chunk, t): t for t in time_chunks} for future in concurrent.futures.as_completed(future_to_chunk): res = future.result() if res: all_data.extend(res) completed += 1 if completed % 20 == 0: print(f" 진행 상황: {completed}/{len(time_chunks)} 완료 ({int(completed/len(time_chunks)*100)}%)") # 정렬 및 저장 print("정렬 및 저장 중...") all_data.sort(key=lambda x: x['tm']) with open(output_filename, 'w', newline='', encoding='utf-8-sig') as f: writer = csv.DictWriter(f, fieldnames=keys) writer.writeheader() writer.writerows(all_data) print(f"최종 완료: {output_filename} (총 {len(all_data)}행)") if __name__ == "__main__": main()