slides = tree.css("div.slide-wrap div.slide")
if not slides:
print(">> 데이터를 포함한 슬라이드를 찾지 못했습니다. HTML 구조가 변경되었을 수 있습니다.")
return
for slide in slides:
# 날짜는 slide 바로 아래 div.daily 태그의 data-date 속성에 있습니다.
daily_node = slide.css_first("div.daily")
if not daily_node:
continue
date_str = daily_node.attributes.get('data-date', '').strip()
# [수정 2] 상세 데이터 리스트 찾기
#
형태를 모두 찾습니다.
ul_items = daily_node.css("ul") # daily_node 내부에서 검색
for ul in ul_items:
# class에 'item'이 없는 ul(헤더 등)은 건너뜀
if "item" not in ul.attributes.get("class", ""):
continue
# 데이터를 저장할 딕셔너리
w_data = {
"time": "-", "weather": "-", "temp": "-",
"feels_like": "-", "prob": "-", "wind": "-", "humid": "-"
}
# 속성에서 시간 가져오기 (가장 정확함)
if 'data-time' in ul.attributes:
w_data['time'] = ul.attributes['data-time']
# li 태그 순회 (숨겨진 라벨 기반 매핑)
lis = ul.css("li")
for li in lis:
label_node = li.css_first("span.hid")
if not label_node:
continue
label_text = label_node.text(strip=True)
# 1. 시각 (속성값이 없을 경우 대비)
if "시각" in label_text and w_data['time'] == "-":
val = li.css_first("span:not(.hid)")
if val: w_data['time'] = val.text(strip=True)
# 2. 날씨
elif "날씨" in label_text:
wic = li.css_first(".wic")
if wic:
w_data['weather'] = wic.attributes.get("title") or wic.text(strip=True)
# 3. 기온 (체감온도 괄호 제거)
elif "기온" in label_text:
feel_node = li.css_first(".feel")
if feel_node:
# deep=False로 자식 노드 제외하고 순수 텍스트만 추출
w_data['temp'] = feel_node.text(deep=False, strip=True)
# 4. 체감온도
elif "체감온도" in label_text and "기온" not in label_text:
spans = li.css("span")
if len(spans) > 1:
w_data['feels_like'] = spans[-1].text(strip=True)
# 5. 강수확률
elif "강수확률" in label_text:
spans = li.css("span")
if len(spans) > 1:
prob = spans[-1].text(strip=True)
w_data['prob'] = prob if prob else "-"
# 6. 바람 (텍스트 정제)
elif "바람" in label_text:
wd_node = li.css_first(".wdic")
# 약/강 텍스트(.qwsd) 제외하고 숫자(.wspd)만
ws_node = li.css_first(".wspd:not(.qwsd)")
wd = wd_node.text(strip=True) if wd_node else ""
ws = ws_node.text(strip=True) if ws_node else ""
w_data['wind'] = f"{wd} {ws}".strip()
# 7. 습도
elif "습도" in label_text:
spans = li.css("span")
if len(spans) > 1:
w_data['humid'] = spans[-1].text(strip=True)
# 데이터 출력
if w_data['time'] != "-":
print(f"{date_str:<12} {w_data['time']:<6} {w_data['weather']:<8} "
f"{w_data['temp']:<6} {w_data['feels_like']:<6} "
f"{w_data['prob']:<8} {w_data['wind']:<14} {w_data['humid']:<6}")
# ==========================================
# 실행 부
# ==========================================
if __name__ == "__main__":
filename = "weather_debug.html"
# 1. 파일이 있으면 파일로 테스트
if os.path.exists(filename):
print(f"📂 파일 '{filename}'을 로드합니다...")
with open(filename, "r", encoding="utf-8") as f:
parse_weather_data(f.read())
# 2. 파일이 없으면 네트워크 요청 (실제 사용 시)
else:
print("🌐 네트워크 요청을 시작합니다...")
url = "https://www.weather.go.kr/w/wnuri-fct2021/main/digital-forecast.do"
params = {
"code": "2638057200",
"unit": "m/s",
"hr1": "Y",
"lat": "35.0952286648109",
"lon": "128.960618556493"
}
headers = {
"User-Agent": "Mozilla/5.0",
"Referer": "https://www.weather.go.kr/w/index.do",
"X-Requested-With": "XMLHttpRequest"
}
try:
res = requests.get(url, params=params, headers=headers, impersonate="chrome120")
if res.status_code == 200:
parse_weather_data(res.text)
else:
print("통신 오류")
except Exception as e:
print(e)