- 개요
2025년 7월 16일 ~ 19일, 중부지방과 남부지방에 많은 비가 내렸습니다.
이 기간의 호우 관련 재난문자를 다운로드 받아 시각화하고 싶었지만 재난문자 홈페이지에서는 과거 일주일치 재난문자 데이터까지만 조회할 수 있습니다.
다행히도 아래 링크의 재난문자번호만 바꾸면 과거 재난문자 데이터를 얻을 수 있습니다.
https://m.safekorea.go.kr/idsiSFK/neo/sfk/cs/sfc/dis/disasterMsgView.jsp?menuSeq=679&md101_sn={재난문자번호}
하지만 재난문자 분류에 대한 내용은 없기에 자연재해 중 "호우"에 의한 재난문자인지 알려면 문자내용을 읽어봐야하죠.
이걸 언제 다 눈으로 보고 분류하겠습니까?
이럴 때 ChatGPT와 같은 LLM 모델을 이용하면 이 일을 쉽게 할 수 있습니다.
- 과거 재난문자 크롤링
1. 분석기간에 맞는 md101_sn 찾기
md101_sn은 재난문자의 번호입니다.
분석기간은 7월 16 ~ 19일이라 칩시다.
먼저 md101_sn에 숫자를 넣어 날짜를 확인합니다.
2025년 7월 16일 가장 첫 재난문자 번호는 239577번, 7월 19일의 마지막 번호는 241604번입니다.
분석기간이 여러 개면 이 부분을 자동화해보세요.


2. 크롤링 코드 작성
그럼 저 숫자를 바탕으로 크롤링하는 코드를 짜봅시다.
time.sleep(1)은 1초 대기하라는 것이므로 재난문자 1개당 최소 1초를 씁니다.
크롤링한 재난문자의 수는 1000개가 넘습니다.
1시간이 3600초니까 이 코드는 20분은 넘게 돌아가겠죠...
time.sleep()을 더 짧게 하면 되지 않나?라는 생각이 들텐데요.
재난문자번호를 넣어서 링크에 접속해보시면 화면에 먼저 "조회중"이라 뜨고 좀 기다려야 html 스크립트가 로드됩니다.
대기시간이 너무 짧으면 html 요소가 없다고 오류납니다.
(0.5초로 지정해보니 가끔 늦게 조회될 때 오류납니다.)
더 빠르게 만들려면 대기시간을 짧게 만들되 try, except를 활용해서 실패한 재난문자번호를 추출하고 while문으로 실패한 재난문자번호로 다시 크롤링을 하면 됩니다.
이 부분은 따로 구현하지 않았습니다.
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
import pandas as pd
snum = 239577
enum = 241604
driver = webdriver.Chrome()
nums = []
dates = []
regions = []
msgs = []
for md101_sn in range(snum, enum+1, 1):
try:
driver.get(f'https://www.safekorea.go.kr/idsiSFK/neo/sfk/cs/sfc/dis/disasterMsgView.jsp?menuSeq=679&md101_sn={md101_sn}')
time.sleep(1)
date_elem = driver.find_element(By.ID, "smsTitle")
region_elem = driver.find_element(By.ID, "bbsDetail_0_cdate")
msg_elem = driver.find_element(By.ID, "msg_cn")
region_elem_split = [item.strip() for item in region_elem.text.split(',')]
for region in region_elem_split:
nums.append(md101_sn)
dates.append(date_elem.text[0:19])
regions.append(region)
msgs.append(msg_elem.text)
except:
print(md101_sn)
df_webpage = pd.DataFrame({
"번호": nums,
"date": dates,
"region": regions,
"message": msgs
})
df_webpage.to_csv(f'num_{snum}-{enum}.csv')
첨부파일은 크롤링 코드로 다운로드한 파일입니다.
- LLM기반 호우 관련 재난문자 판별
1. 프롬프트 엔지니어링
모든 종류의 재난문자를 크롤링했고, 호우에 의한 재난문자만 추출하고자 합니다.
LLM에 재난문자 내용을 입력값으로 주어 '호우'인지 아닌지 판별하는 코드를 작성해봅시다.
사용할 LLM은 openAI의 gpt-4.1-mini로 가격이 싸서 쓴겁니다.
openAI 홈페이지에서 결제를 하고 APIkey를 받아야 파이썬 코드로 openAI의 모델을 사용할 수 있습니다.
공짜로 이 부분을 구현하고 싶다면 ollama로 무료 LLM을 설치해서 사용하세요.
import pandas as pd
"""
재난문자의 내용이 없는 경우가 있습니다.
이것은 크롤링이 잘못된 게 아니라 진짜로 내용이 없는 것이므로
dropna()로 내용이 없는 행(NaN값)을 제거합시다.
"""
df_j = pd.read_csv(r'num_239577-241604.csv')
df_j.dropna(inplace=True)
APIkey = f'{APIkey를 넣어주세요}'
from openai import OpenAI
"""
ChatGPT, Gemini를 써보셨나요?
이런 LLM을 쓸 때 질문을 입력하는 창은
{"role":"user", "content"que"}와 관련 있습니다.
번역 그대로 유저(user)가 내용(content)을 LLM에 주는 것이죠.
다음으로 {"role":"system", "content":~~}을 봅시다.
역할(role)은 시스템(system)으로 LLM에게 조건, 규칙, 지시사항 등의 내용(content) 등을 넣습니다.
예를 들어 전 "호우"인지 아닌지 판별하는 것이 중요하므로
최적의 답변을 얻기위한 지시사항을 주었습니다.
이러한 일을 프롬프트 엔지니어링이라고 합니다.
"""
def get_answer(que):
client = OpenAI(api_key=APIkey)
messages = [
{
"role": "system",
"content": (
"재난문자는 재해에 따른 분류가 있고, 너는 이것을 분류하는 AI야. 사용자로부터 재해 문자 내용을 입력받으면, "
"재해 문자 내용에 많은 비, 강한 비, 호우주의보, 호우경보와 같은 표현이 있으면(단 호우로 다른 일이 발생했다는 내용은 없어야 함) '호우'"
"그렇지 않으면 '비호우' 이라는 단어 중 하나만 정확하게 대답해."
"추가 설명이나 문장은 하지 마."
)
},
{
"role": "user",
"content": que
}
]
response = client.chat.completions.create(
model="gpt-4.1-mini",
messages=messages
)
return response.choices[0].message.content
"""
재난문자 내용을 LLM 함수에 넣어줍시다.
결과로 '호우' 또는 '비호우'가 반환됩니다.
"""
ans = []
for que in df['message'].tolist():
ans.append(get_answer(que))
2. 판별 결과
호우로 판별된 재난문자내용 10개만 살펴봅시다.
재난문자가 모두 호우랑 관련 있습니다.

다음으로 비호우로 판별된 재난문자내용 10개만 보겠습니다.
댐방류, 산림 인접지 접근 금지, 말라리아, 교통통제, 산사태 등 호우랑 관련없는 내용입니다.

3. 시간에 따른 호우 재난문자 송출지역 시각화 및 레이더 강수 비교
시각화 코드는 이전 포스트(링크)를 참고하세요.
왼쪽은 재난송출지역, 오른쪽은 기상청 레이더 하루내 강수 분포도입니다.


16~19일동안 처음에는 중부지방에서 이후에는 남부지방에서 재난문자가 많이 송출되었습니다.
레이더 강수 분포도에서도 중부지방에서 남부지방으로 강수대가 움직입니다.
재난문자 송출지역과 강수량이 많은 지역이 거의 일치합니다.
'여러가지 데이터 > 프로그래밍 & 분석' 카테고리의 다른 글
| [재난문자 송출지역 시각화] 3. 재난문자 읍면동단위 송출지역 그리기(folium, matplotlib 사용) (0) | 2025.08.01 |
|---|---|
| [재난문자 송출지역 시각화] 2. 재난문자 시군구단위 송출지역 그리기(folium, matplotlib 사용) (0) | 2025.08.01 |
| [재난문자 송출지역 시각화] 1. 파이썬 기반 재난문자 크롤링 (0) | 2025.07.26 |
| [python][지하철 승하차 자료] 회사원은 언제 연차를 낼까? 2. 연차를 내는 시기 (0) | 2025.03.15 |
| [python][지하철 승하차 자료] 회사원은 언제 연차를 낼까? 1. 승하차인원 분석기간 선정 (0) | 2025.03.09 |