111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
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()
|