실습 로그 / 여울목 · 계곡 급류 사전경보 서비스

여울목 3단계 · 관측 데이터 수집과 DB

원주 대상 계곡을 정하고, 계곡별로 쓸 강수·수위 관측소를 찾아 API로 데이터를 받을 수 있는지 확인한다. 이후 서버가 주기적으로 수집해 DB에 쌓는다.

진행 과정은 실습 내용을 AI와 함께 정리했고, 배운 점은 그걸 보고 제가 이해한 대로 직접 썼습니다. 배운 점 바로가기 ↓

공공데이터API관측소

목표

원주 대상 계곡을 정하고, 계곡별로 쓸 강수·수위 관측소를 찾아 API로 데이터를 받을 수 있는지 확인한다. 이후 서버가 주기적으로 수집해 DB에 쌓는다.

A. 데이터 API 호출 확인

  • 쓰는 데이터 API 전체
기관 용도 주소 형식 상태
한강홍수통제소 수위·유량 waterlevel/list/10M·1H JSON 10/31 확인
한강홍수통제소 강수량 rainfall/list/10M·1H JSON 10/31 확인
한강홍수통제소 관측소 제원 (기준 수위 4단계) waterlevel/info.json JSON 10/29 확인, 전체 목록은 잘림
기상청 API허브 관측 강수 (1분, RN_1HR 1시간 누적) nph-flood_sfc_sts_pkg 텍스트, disp=1이면 CSV 10/29 확인
기상청 API허브 수치모델 강수 예보 nph_flood_nwp_txt 세로줄 구분 표 10/29 확인
  • 기상청 확인한 것 (10/29)
    • 키 하나로 활용신청한 API 전부 사용 (관측-통계 묶음형, 수치모델, 일통계)
    • 관측은 약 4분 지연 → 수집은 '현재−5분' 기준
    • 결측값 -99.9 → 0이 아니라 판정 불가로 처리
    • 수치모델 tm·tmef는 UTC, 6시간 간격
    • 원주 관측소 stn=114
  • 한강홍수통제소 관측소 제원에 4단계 기준 수위가 있음: attwl(관심) / wrnwl(주의) / almwl(경보) / srswl(심각). 위경도는 도-분-초 문자열
  • 보류: 기상청 레이더 추정강수(신청 페이지 없음), 산림청 산악기상(계곡 정한 뒤 필요하면)
  • VM yeoulmok에서 한강홍수통제소 API를 직접 호출해 강수량·수위 데이터가 오는지 확인
    • 키 불러오기: set -a; source ~/secrets/yeoulmok.env; set +a
  • 강수량 관측소 목록 (같은 HRFCO_KEY로 열림 → 강수량 API도 사용 가능 확인)
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/info.json" | head -c 600
  • 관측소 번호 rfobscd, 이름 obsnm, 주소 addr·etcaddr, 위경도 lon·lat(도-분-초 문자열)
  • 수위 최신값 (10분 단위)
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/waterlevel/list/10M.json" | head -c 600
{ "wlobscd" : "1001603", "ymdhm" : "202610311150", "wl" : "0.16", "fw" : "0.05" }
  • wl: 수위(m), fw: 유량(m³/s). 유량은 빈칸(" ")인 관측소가 있음 → 0이 아니라 '없음'으로 처리
  • 11:59에 조회했는데 시각이 11:50 → 약 10분 늦게 들어옴. 시각은 한국시간
  • 강수량 최신값 (10분 단위)
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/list/10M.json" | head -c 400
  • rf: 10분 강수량(mm)
  • 관측소 하나만 지정해서 부르기
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/waterlevel/list/10M/1006664.json"
  • 응답이 작아서 잘리지 않음 → 서버 수집은 이 방식으로 함 (트러블슈팅 1번 참고)
  • 과거 자료 조회: list/{단위}/{번호}/{시작}/{끝}.json
    • 10분(10M)은 12자리 yyyymmddhhmm, 1시간(1H)은 10자리 yyyymmddhh (트러블슈팅 2번 참고)
    • 결과를 시각·값만 보기 좋게 출력
P='import sys,json;[print(x["ymdhm"],x.get("wl",x.get("rf"))) for x in reversed(json.load(sys.stdin)["content"])]'
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/list/1H/10064070/2025071900/2025071923.json" | python3 -c "$P"

B. 원주 관측소 찾기

  • 관측소 전체 목록을 파일로 받아 주소에 '원주'가 들어간 것만 골라내려 했으나 응답이 중간에 잘림 (트러블슈팅 1번 참고)
  • 강수량: 잘린 파일 안에 원주 관측소가 들어 있어서 grep으로 찾음
curl -s -o rf_info.json "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/info.json"
grep -B2 -A4 "obsnm.*원주" rf_info.json
번호 이름 위치
10024240 원주시(황둔리) 신림면 황둔리
10054010 원주시(법천교) 부론면 법천교
10064010 원주 원주시
10064050 원주시(지정면사무소) 지정면
10064060 원주시(문막교) 문막읍
10064070 원주시(서곡초교) 판부면 용수골길 서곡초등학교
10064075 원주시(신촌리) 판부면 신촌리
10064090 원주시(흥양초교) 소초면
  • 수위: 잘린 파일엔 부론면 남한강 본류 2곳(법천교, 남한강대교)뿐이라 계곡 경보엔 못 씀
    • 본류: 강의 가장 큰 줄기. 계곡 물은 작은 지류를 거쳐 들어옴
  • 한강홍수통제소 홈페이지 → 수문 → 실시간 수문자료 → 수위 자료에서 원주 수위 관측소 11곳 확인
    • 가현교, 남한강대교, 동부교, 문막교, 법천교, 봉미교, 옥산교, 원주교, 장현교, 지정대교, 판됀2교
  • 관측소 팝업의 엑셀 다운로드로 주소, 팝업 주소창의 obscd로 번호 확인
    • 예: wlpopup.do?obscd=1006664 → 동부교
번호 이름 주소 해발 10/31 12:00 수위
1006664 원주시(동부교) 반곡동(단구동) 동부교 151m 0.08m, 유량 없음
1006665 원주시(원주교) 봉산동 원주교 120m 0.27m, 유량 0.43
  • 두 번호 모두 API로 호출해 홈페이지 값과 같은 것 확인

C. 대상 계곡과 사고일 데이터

  • 네이버 지도로 계곡 물이 어느 수위 관측소를 지나는지 확인
    • 동부교로 오는 원주천은 금대리 → 판부면 → 동부교 방향(중앙고속도로를 따라)으로 내려옴
    • 서곡리 개울은 서곡초 서쪽을 지나 북쪽으로 가지만 동부교 줄기가 아님
  • 서곡리 물(서곡천)은 섬강 수계로, 흥업면 사제리 사제교를 지나 호저면 만종리 쪽으로 흐름 (강원일보 기사 기준). 원주 시내 원주천 위 동부교·원주교는 안 지남
    • 수계: 물이 모여 같은 큰 강으로 흘러가는 하천 묶음
  • 대상 계곡 2곳으로 정함 (신청서의 '계곡 2~3곳'과 맞음)
계곡 상류 강수 하류 수위 비고
금대리 계곡 원주시(신촌리) 10064075 원주시(동부교) 1006664 물이 동부교로 바로 내려옴
서곡리 계곡 원주시(서곡초교) 10064070 없음 2025-07-19 고립 사고 지점. 상류 강수 사전 경보만
  • 서곡리 하류 수위 후보 3곳 주소 확인 (홈페이지 팝업 엑셀)
번호 이름 주소 판단
1006677 원주시(판대2교) 지정면 판대리 섬강 본류 쪽, 서곡천 아님
1006672 원주시(장현교) 호저면 신현리 방향은 맞지만 15km 이상 하류, 유량 5.42로 큰 물이 합쳐진 지점
1006670 원주시(옥산교) 호저면 옥산리 방향은 맞지만 너무 멀어서 경보에 의미 없음
  • 결정 방향: 서곡리는 상류 강수 사전 경보만, 하류 수위 즉시 경보는 금대리만 (회의에서 확정)
  • 사고일(2025-07-19) 1시간 자료 조회
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/list/1H/10064070/2025071900/2025071923.json" | python3 -c "$P"
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/list/1H/10064075/2025071900/2025071923.json" | python3 -c "$P"
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/waterlevel/list/1H/1006664/2025071900/2025071923.json" | python3 -c "$P"
  • 서곡초교 강수 (mm/시간)
03시 1   04시 12   05시 11   06시 1   07시 8   08시 11
10시 2   12시 1    19시 4    21시 4   23시 1   (나머지 0)
하루 약 56mm, 새벽~아침에 몰림
  • 신촌리 강수, 동부교 수위: 그날 24시간 전부 결측
    • 결측: 관측소가 그 시각 값을 못 보내서 비어 있는 것
    • 동부교는 어제(10/30)와 올해 7월 자료는 정상 → 사고일만 기록이 없거나 설치가 그 뒤일 가능성. 언제부터 있는지는 미확인
  • 기준값 정리
    • 상류 강수 기준(X): 서곡초교 사고일 값으로 1차 설정 가능
    • 하류 수위 기준(Y): 사고일 자료가 없어서 다른 강우일 기록이나 관측소 공식 기준 수위로 정해야 함 → 컨설팅 1회차 질문

D. 위치정보 법적 절차

  • 기준은 서버가 개인위치정보를 받느냐
    • 개인위치정보: 특정 사람이 어디 있는지 알 수 있는 위치 정보
    • 개인위치정보를 다루는 위치기반서비스는 신고 필요 (담당: 방송미디어통신위원회, 예전 방송통신위원회)
    • 개인위치정보를 다루지 않으면 신고 의무 폐지. 보호조치·누설 금지 등 일부 규정은 그대로 적용
  • 여울목 기능별 판단
기능 서버가 사람 위치를 받나 판단
앱 근처 계곡(GPS) 폰 안에서만 계산하면 안 받음 부담 적음
앱 계곡 구독 알림 계곡 이름만 받음 부담 적음
웹 실시간 사용자 수 받음 신고·약관·동의 필요 가능성 높음
웹 공무원 직접 알림 받음 신고·약관·동의 필요 가능성 높음
  • 결정 방향: GPS는 폰 안에서만 쓰고 서버로 보내지 않음. 웹의 실시간 사용자 수·공무원 알림은 후순위
  • 근거 기사가 2015년이라 이후 개정 여부는 컨설팅 때 확인
  • 참고: 비즈한국 기사

트러블슈팅

1. 관측소 전체 목록 API 응답이 중간에 잘림

  • 증상 : waterlevel/info.json, rainfall/info.json을 받아 파이썬으로 읽으면 JSONDecodeError
  • 확인한 것 : 받은 파일 끝이 문장 중간에서 끊김. 헤더는 200, Transfer-Encoding: chunked. 압축·HTTP/1.0으로 다시 받아도 해결 안 됨
  • 원인 : 서버가 큰 목록을 끝까지 보내지 않음 (우리 쪽 문제 아님)
  • 해결 : 원주 관측소는 홈페이지 실시간 수문자료에서 찾고, 팝업 주소의 obscd로 번호 확인. 운영은 번호를 지정해서 부르므로 응답이 작아 영향 없음
  • 재발 방지 : 관측소 목록은 전체 API에 의존하지 않고, 쓸 관측소 번호를 DB에 고정해 둔다

2. 1시간 자료 조회에서 값이 전부 비어 나옴

  • 증상 : 동부교 1시간 자료를 여러 날짜로 조회했는데 값이 전부 빈칸이거나 에러
  • 확인한 것 : 날짜를 12자리(분 포함)로 넣었음. 10자리로 다시 조회하니 최근 값은 정상
  • 원인 : 1시간 자료는 날짜를 10자리(yyyymmddhh)로 넣어야 함
  • 해결 : 10자리로 다시 조회. 그래도 2025-07-19는 결측이라 실제로 기록이 없는 것으로 확인
  • 재발 방지 : 10분은 12자리, 1시간은 10자리. 빈 결과가 나오면 형식부터 확인

남은 작업

  • 한강홍수통제소 강수량·수위 API 호출 확인
  • 원주 대상 계곡 2곳과 관측소 매칭
  • 사고일(2025-07-19) 과거 데이터 확인
  • 동부교 수위 기록이 언제부터 있는지 확인
  • 하류 수위 기준(Y) 정할 다른 강우일 찾기
  • 서곡리 하류 수위 관측소 찾기 → 쓸 만한 곳 없음, 강수 경보만 (회의에서 확정)
  • 위치정보 관련 법적 절차 1차 확인 (이후 개정 여부는 컨설팅 때)
  • DB 설계와 수집 코드

배운 점

직접 작성

A. 데이터 API 호출 확인

set -a; source ~/secrets/yeoulmok.env; set +a                                    # API 키를 환경변수로 불러옴
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/waterlevel/list/10M/1006664.json"     # 동부교 최신 수위 (10분 단위)
curl -s "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/list/1H/10064070/2025071900/2025071923.json"  # 서곡초교 사고일 강수 (1시간 단위)
{ "wlobscd": "1006664", "ymdhm": "202610311200", "wl": "0.08", "fw": " " }
  • 목적 : 코드 짜기 전 정부 API가 진짜 데이터를 주는지 확인
  • 설명
    • 사용하는 API
      • 한강홍수통제소 —> 수위 (물높이) + 강수 (2개의 API)
      • 기상청 —> 관측 강수랑 강수 예보
    • 주소 읽는 법 —> 틀리면 404 에러
      • waterlevel (수위)
      • list : 값 목록
      • 10M : 10분 단위
      • 1006664 : 관측 번호
    • 날짜 자릿수가 다름 —> 틀리면 빈칸으로 나옴
      • 10분 : 12자리 (202610311200) : 분까지
      • 1시간 : 10자리 (2025071923) : 시까지
    • 값이 약간 늦게 들어옴
      • 한강홍수통제소 : 약 10분
      • 기상청 : 약 4분
      • 그래서 수집할 때 지금시간에서 10분 여유를 둬야 함
    • 빈칸이 0이 아님
      • "fw": "" 처럼 빈칸이거나 기상청 -99.9는 관측 못함의 의미
      • 0으로 처리하면 비 안 오는 거로 착각해서 위험한데도 안전하다고 판단할 수 있음 → 판정 불가로 처리
    • 관측소마다 공식 기준 수위가 존재
      • 관심 → 주의 → 경보 → 심각
    • curl : 터미널에서 주소에 접속해 응답 받아오는 명령어
    • wl / fw / rf : 수위 (m) , 유량 (m³/s , 1초에 흐르는 물의 양) , 강수량 (mm)
    • 결측 : 관측소가 그 시각 값을 못 보내 비어 있는 것

B. 원주 관측소 찾기

curl -s -o rf_info.json "http://api.hrfco.go.kr/$HRFCO_KEY/rainfall/info.json"  # 강수 관측소 전체 목록을 파일로 저장
grep -B2 -A4 "obsnm.*원주" rf_info.json                                          # 이름에 '원주'가 들어간 것만 앞뒤 줄과 함께 출력
  • 목적 : 원주 안에서 우리가 쓸 강수, 수위 관측소 번호 찾기
  • 설명
    • 전체 목록에서 원주만 골라내지 못 함. 중간에 짤라냄
      • 정부 서버에서 큰 목록을 끝까지 보내지 않음
    • 강수 관측소는 운 좋게 잘린 앞부분 원주 8곳 존재
      • grep으로 골라냈고 , 그 중 서곡초교랑 신촌리 유의
        • grep : 파일에서 특정 글자가 들어간 줄만 찾는 명령
          • -B2 -A4 : 앞 2줄 뒤 4줄 같이
    • 수위 관측소는 잘린 부분에 있어서 홈페이지에서 직접 찾음
      • 실시간 수문 자료 → 수위에서 원주 11곳 찾음
      • obscd = 1006664 같은 숫자로 번호를 알아냄
        • obscd : 관측소 번호
    • 번호 하나만 찍어서 부르면 잘리지 않음
      • 응답이 작아서 잘리지 않음
      • 실제 서버는 우리 관측소 몇 개만 번호로 부르니 운영에 문제 X

C. 대상 계곡과 사고일 데이터

계곡 상류 강수 하류 수위
금대리 신촌리 (10064075) 동부교 (1006664)
서곡리 서곡초교 (10064070) X
  • 목적 : 경보를 낼 계곡 정하고 각 계곡에 어느 관측소 값 쓸지 짝 지음
  • 설명
    • 경보는 두 가지 데이터로 낸다.
      • 상류에 비가 많이 몰려오면 곧 물이 불어나니깐 미리 알림 (강수)
      • 하류 물이 실제로 빨리 차오르면 바로 알리기 (수위)
      • 그래서 계곡마다 위쪽 강수 관측소 + 아래쪽 수위 관측소 짝이 필요
    • 금대리는 짝이 맞지만 서곡리는 수위 짝이 없음
      • 서곡리 물 (서곡천) 은 원주 시내를 지나지 않고 서쪽 (흥업→호저)로 빠짐
        • 그래도 넣은 이유 : 실제 사고가 (2025.07.19)에 난 곳
          • 강수기록도 남아있음
        • 그래서 서곡리는 강수 경보만 하자고 제안
    • 사고일 기록 : 서곡초교 강수는 새벽 4~5시에 시간당 12,11mm (하루 약 56mm)
      • 근데 신촌리 강수량이랑 동부교 수위는 그 날 기록이 통째로 비어있음
        • 그래서 기준값은 반만 정할 수 있음
          • 강수기준 X 는 사고일 값으로 1차로 잡을 수 있다
            • 기준값 X : 상류 1시간 강수 기준
          • 수위 기준 Y는 다른 비 온 날 기록이나 관측소 공식 기준으로 정해야
            • 기준값 Y : 하류 30분 수위 상승폭 기준

D. 위치정보 법적 절차

기능 서버가 사람 위치를 받나 부담
앱 근처 계곡 안 받음 (폰에서 계산) 적음
앱 구독 알림 계곡 이름만 받음 적음
웹 실시간 사용자 수 받음 신고·동의 필요
웹 공무원 직접 알림 받음 신고·동의 필요
  • 목적 : 위치를 다루는 기능 중 법적 절차 필요한 걸 미리 확인
  • 설명
    • 기준은 하나임
      • 이 사람이 지금 어디에 있는지
        • 받으면 위치기반 서비스 신고 (방송미디어통신위원회)랑 약관, 동의 필요
    • 근처 계곡은 폰에서 계산해서 피함
      • 서버에서 계곡 위치만 주고 폰이 자기 위치랑 비교
        • 기능은 같은데 위치가 서버로 안 가니 신고 대상이 아님
    • 웹 두 기능은 위치로 받아야 함
      • 지금 계곡에 몇 명 있나를 알리려면 사람들 위치를 모아야함
    • 근거 : 2015년 기사라 추후 법 바뀌었는지 확인 필요