이 프로그램은 안전신문고 교통위반 신고내역 을 크롤링하여 DB로 저장하고 엑셀파일(xlsx) 및 구글 스프레드시트로 만들어 사용자가 자신의 신고내역을 편하게 관리할 수 있도록 하는 목적으로 제작되었습니다. 윈도우용 앱과 도커 이미지로 배포하고 있으며, 윈도우용 앱 다운로드는 Github에서 가능합니다.

[다운로드]

Pyinstaller를 이용해 단일파일로 컴파일하는 특성상 바이러스로 오탐당하지만, 실제로는 바이러스가 아니니 안심하고 사용하셔도 됩니다.

소스코드는 Github에 모두 공개되어 있습니다.

Selenium Hub와 도커 이미지를 이용한 구동도 가능합니다. 모두 아래 단락에서 설명하겠습니다.

윈도우용 사용설명서

요구사항

윈도우용 안전신문고 크롤러를 사용하기 위해선 윈도우 환경 및 구글 크롬이 필요합니다.

이 프로그램은 텔레그램 봇과 구글 스프레드 시트 연동을 추가적으로 지원하며, 이를 사용하기 위해선 텔레그램 봇 작동에 필요한 tokenchat id, 구글 스프레드 시트 연동에 필요한 auth용 JSON 키파일과 권한설정이 완료된 스프레드시트의 URL주소가 필요합니다.

UI

깃허브를 통해 다운로드 받은 mysafetyreport파일을 실행하면 아래와 같은 창이 나타납니다.

깃허브에서 내려받은 크롤러 실행 파일과 초기 설정이 담긴 데이터 폴더의 디렉토리 구조 안전신문고 계정 정보 및 추가 기능 옵션을 입력할 수 있는 크롤러 프로그램의 메인 화면

동시에 해당 폴더 하위에 data폴더를 생성하고 필요한 것들을 이곳에 저장합니다.

계정 정보가 암호화되어 로컬 파일 시스템에 저장된 구성 파일 위치

기본적인 기능 및 사용법은 아래와 같습니다.

  • 아이디 / 비밀번호 : 안전신문고에 사용되는 ID와 PW를 그대로 입력하면 됩니다. 입력한 정보는 ./data/config.ini에 암호화되어 저장됩니다.
  • 크롤링 시작 : 입력된 계정을 통해 안전신문고에 로그인 후 마이페이지 → 나의 안전신고현황을 크롤링하는 작업을 시작합니다. 기본적으로 ‘30개씩 보기’를 선택하도록 되어 있습니다.
    작동 방식에 대한 내용은 아래 기본 동작 단락을 읽어주세요.
  • 작업 중지 : 크롤링 작업을 강제로 중지합니다. 저장되지 않은 데이터는 유실됩니다.
  • 엑셀만 저장 : 크롬을 띄우고 크롤링하는 과정 없이 현재까지 저장된 DB를 다시 엑셀 및 스프레드시트로 추출만 합니다.
  • 일반 탐색 : 입력된 계정정보를 활용하여 안전신문고에 접속 후, 신고내역을 탐색하여 DB로 저장합니다.
  • 조건부 탐색 : ‘나의 안전신고현황’ 페이지에서 ‘진행’상태인 신고건이 한 개도 없는 페이지를 ‘입력한 숫자’만큼 만나면 탐색을 종료합니다. 신고건수가 너무 많을 경우 불필요한 과거 신고건을 탐색하는 것을 막아줍니다.
  • 페이지 지정 : 30개씩 정렬된 신고내역의 특정 페이지에 해당하는 신고건만을 크롤링합니다. 6:8이라고 적을 경우 6~8페이지, 7,9라고 적을 경우 7페이지와 9페이지를 크롤링합니다.
  • 전체 갱신 : 답변완료된 건을 포함, 모든 신고내역을 처음부터 크롤링합니다.
  • 강제 초기화 : DB오류 등이 발생했을 때 DB 전체를 지우고 처음부터 크롤링합니다.

기본 동작

기본적인 동작은 간단하게 계정입력 후 크롤링 시작을 클릭해서 작동합니다.

자동으로 시크릿 크롬 창을 띄워 안전신문고 웹사이트 로그인을 수행하는 과정

입력받은 아이디와 비밀번호를 이용해 자동으로 시크릿 창을 열어 로그인을 시도합니다.

절.대.로. 작동중인 크롬 위에 마우스 커서를 올리거나 크롬을 직접 조작하지 마세요.

아이디 또는 비밀번호 오류로 인해 안전신문고 로그인이 실패했음을 알리는 알림 창

물론, 틀릴 경우 로그인에 실패합니다.

로그인 후 전체 신고 리스트를 차례대로 순회하며 개별 처리 내역을 수집하는 로그 화면

로그인에 성공한 뒤에는 아래처럼 신고내역 리스트 전체를 순회하며 목록을 작성한 후,

수집된 리스트를 바탕으로 담당자의 답변 내용과 교통위반 세부 정보를 파싱하는 크롤링 단계

작성된 목록을 기반으로 개별 신고건을 모두 순회하며 신고내용과 담당자 답변내용 등을 긁어 교통위반 내역을 파싱합니다.

최초 실행 시엔 모든 신고건을 순회하겠지만, 최초DB가 작성된 이후엔 답변완료된 건이나 취하 건 등은 더 이상 접근하지 않습니다(변경내역이 없으므로).

크롤링 완료 후 수집된 전체 데이터가 기록된 로컬 SQLite 데이터베이스 파일의 위치

모든 신고내역 순회가 끝나고 DB로 저장된 후에는 ./data폴더 하위에 data.db로 저장되며

DBeaver와 같은 서드파티 툴을 사용하여 저장된 데이터베이스 내부 스키마를 확인하는 화면

쿼리를 조금 건드릴 수 있으신 분은 DBeaver나 DB Browser for SQLite를 통해 직접 들여다보고 편집할 수 있습니다.

크롤러 작업 후 자동으로 생성되어 신고 진행 상태와 과태료 여부를 요약한 엑셀 파일 출력 결과

기본적으로 매 작업마다 ./data/results폴더 하위에 엑셀파일을 만들어 줍니다.

엑셀 파일에 기록된 데이터를 기반으로 담당자별 처리 통계를 내거나 분석하는 작업 환경

각 신고건들의 신고번호, 진행상태, 차량번호, 위반법규명, 담당자, 과태료 등의 컬럼으로 내용이 정리되어 있어 익숙한 엑셀함수로 자신의 신고내역을 지역별, 담당자별, 위반법규별로 통계처리 및 분석할 수 있습니다.

구글 API 콘솔에서 스프레드시트 권한을 공유받을 서비스 계정을 설정하는 외부 블로그 참고 자료

추가 동작

스프레드 시트 연동

본 프로그램은 구글 스프레드시트 연동을 지원합니다. 이를 위해선 먼저 이 블로그에서 상세히 설명하는대로 Google Sheets API 사용 설정 및 JSON 키파일을 발급하고, 빈 스프레드시트 문서를 생성 후 서비스 계정에게 권한을 할당해야 합니다.

아래 사진처럼 링크된 블로그의 “2. 파이썬으로 구글 스프레드 시트 가져오기 - 1. 구글 스프레드 시트 권한 공유” 부분까지 진행하시면 됩니다.

데이터를 업로드할 구글 스프레드시트의 주소 표시줄에서 문서 고유 ID를 복사하는 과정
이 부분까지 진행하세요

이후 주소창에서 docs.google.com/spreadsheets/d/ 이후의 부분을 복사한 뒤,

크롤러 프로그램 추가 기능 탭의 구글 시트 주소 입력란에 복사한 고유 ID를 붙여넣은 화면

크롤러의 옵션 - 추가기능을 선택해

구글 클라우드에서 다운로드한 서비스 계정 인증용 JSON 키 파일을 찾아보기 버튼으로 지정하는 모습

구글 시트 주소 란에 복사한 부분을 붙여 넣습니다. 예시글의 경우 1Gn3Yy9upbxGTIXmYBgopQANQRqPHC6vnej7lgPbGsC0가 되겠네요.

유효성 검증을 거치지 않은 임의의 JSON 파일을 등록하더라도 정상이라고 표시되는 상태

그리고 스프레드시트 준비 과정에서 다운로드 받은 JSON키파일을 찾아보기버튼을 클릭해 넣어줍니다(파일명은 다릅니다).

지정한 JSON 키 파일이 내부 데이터 폴더로 자동 복사되어 연동 준비가 완료된 모습

JSON파일의 형식을 검증하진 않기 때문에 아무 JSON파일을 지정만 해줘도 아래처럼 정상이라고 표시되긴 하나

연동 성공 후 구글 스프레드시트에 새 시트가 생성되며 크롤링 데이터와 첨부 이미지가 업로드된 화면

실제로 유효한 JSON파일이 아니라면 작동 시 오류가 나게 되므로 제대로 된 JSON파일을 지정해주세요.

이렇게 지정된 JSON파일은 ./data/auth/gspread.json이라는 경로로 복사됩니다.

스프레드시트 내장 함수를 활용해 특정 차량 번호의 과거 신고 이력을 실시간으로 검색하는 대시보드

연동에 성공하면 지정한 스프레드시트문서에 data라는 시트를 만들고 엑셀과 동일한 내용을 업로드합니다.

엑셀과 차이점이 있다면, 엑셀파일은 시행할때마다 새로운 파일이 생성되는 것에 반해, 스프레드 시트는 data시트의 내용을 계속해서 업데이트합니다.

또한, 아래처럼 첨부파일 중 이미지(지도 포함)를 바로 표시해 준다는 장점이 있습니다.

스프레드시트 데이터를 바탕으로 관할 기관 및 담당 공무원별 과태료 부과 비율을 시각화한 차트

같은 문서가 매번 업데이트 되므로, 여기서 다양한 함수를 통해 즉각 업데이트 되는 대시보드를 만들 수도 있습니다.

예를 들어, 아래처럼 스프레드시트의 함수를 사용해 문자열 일부에 해당하는 차량번호를 검색할 수도 있습니다. 신고 시 동일 위반 내역이 많다거나, 까방권은 이미 충분히 찢었음을 증명할 때 유용하게 사용할 수 있습니다.

텔레그램 봇을 작동시키기 위해 봇 토큰과 채팅 아이디를 프로그램 설정 창에 기입하는 모습

혹은, 아래처럼 처리기관과 담당자별 처리건수와 처분건수를 비중으로 나누어 살펴볼 수도 있습니다.

크롤러가 텔레그램 봇을 통해 새롭게 변경된 신고 내역 요약을 전송한 메시지 화면

지나친 소극행정 혹은 업무태만자들은 이런 통계에서 쉽게 발견됩니다.

텔레그램 채팅방에서 명령어 메뉴를 호출하여 차량 번호나 신고 번호를 직접 검색하는 기능

텔레그램 봇

옵션 중 텔레그램 봇에 필요한 값 2가지(Token, Chat_id)를 사용해 간단하게 텔레그램 봇을 작동시킬 수 있습니다.

차량 검색 명령어 사용 후 해당 차량의 과거 신고 내역 리스트를 텔레그램으로 반환받은 결과

텔레그램 봇을 만드는 방법은 인터넷 검색을 통해 쉽게 얻을 수 있으므로 패스합니다.

활성화시킬 경우 매 동작시마다 새롭게 추가된 신고번호를 알려주고, 새로 답변이 달린 건이 있을 경우 이에 대한 summary도 제공합니다.

윈도우 데스크톱 환경 대신 백그라운드 서버 환경에 맞춰 원격으로 크롤링을 시작하는 옵션 버튼

또한, /h를 입력하면 봇 메뉴를 호출할 수 있고, 여기서 차량 번호나 신고 번호 검색 등 간단한 검색을 수행할 수 있습니다.

크롬 브라우저 창을 띄우지 않고 백그라운드 모드로 가볍게 실행하는 Headless 체크박스

차량검색을 클릭 후 문자열 일부를 넣으면 해당하는 모든 차량번호의 신고건을 나열해 줍니다.

크롤러 동작 중 발생하는 모든 진행 상황 및 오류가 기록되는 로그 폴더 경로

크롤링 시작은 말 그대로 원격에서 크롤링 작업을 지시할 수 있는 기능입니다.

단, 윈도우에 프로그램이 작동중이어야 합니다.

이 원격 크롤링 지시 기능은 윈도우보단 하단에서 설명할 도커 환경을 염두에 둔 기능입니다.

엑셀만 저장하기의 경우 프로그램 상의 엑셀만 저장과 동일한 기능으로, 현재 시점까지의 data.db파일의 내용을 다시 한 번 엑셀로 만들어 줍니다.

스프레드 시트가 연동되어 있다면, 스프레드 시트의 내용도 다시 업데이트 해 줍니다.

Headless옵션 & Selenium Hub

옵션 창 하단에는 아래와 같은 옵션이 있습니다.

디버그 로그 활성화 옵션을 켰을 때 과도하게 생성된 대용량 로그 파일 크기를 보여주는 화면

Headless의 경우 크롬창을 숨긴 상태로 작동하는 옵션입니다. 최초 몇 번 사용하며 안정적으로 작동하는 것을 확인한 후엔 Headless를 클릭해 크롬창을 숨겨 덜 불편하게 사용할 수 있습니다.

로컬 환경에 크롬을 설치하기 싫거나, 사용하기 어려운 상황이라면 Selenium Hub를 대신하여 사용할 수 있습니다. Selenium Hub의 주소를 입력하고 크롤링을 시작하면 로컬 크롬 대신 Selenium Hub를 사용해서 작업을 시작합니다.

그러나, 이 옵션을 사용할 경우 아래에 후술할 리눅스 도커 환경을 더 추천합니다.

로그 확인

./data/logs폴더 하위에 동작 로그가 기록됩니다.

다른 파이썬 라이브러리 동작 내역까지 세세하게 남아있는 디버그 전용 로그 파일 텍스트

로그에는 매 작동 단계에 대한 정보가 기록되어 있어, 혹시 오류가 발생해 중단되면 어느 부분이 문제였는지 파악할 수 있습니다.

디버그 모드에서 계정 암호가 평문으로 노출되는 것을 경고하며 로그 공유 시 주의를 주는 부분

디버그 로그 활성화기능을 체크한 상태로 작동시키면 어마무시한 용량의 로그가 생성됩니다. 제 신고건 기준으로 로그파일 한 개가 10메가 정도 합니다.

리눅스 및 도커 환경에서 크롤러를 구동하기 위해 작성된 docker-compose 설정 파일 내용

이 경우 다른 파이썬 라이브러리의 동작 내역까지 모조리 기록되므로, 트러블 슈팅을 위한 로그 공유는 이쪽이 좋습니다.

크롤러 도커 컨테이너에서 환경 변수를 불러오기 위해 구성된 env 파일의 세부 설정값

디버그 로그의 경우 로그인과정에서 입력할 문자열, 즉 아이디와 비밀번호도 평문으로 나오기 때문에, 공유 전 이 부분을 확인해 지워주셔야 합니다.

디버그 로그 파일에 안전신문고 계정 아이디와 비밀번호가 평문으로 노출된 부분

도커 사용설명서

설치 및 설정

이 프로그램은 원래 저 혼자 리눅스에서 도커화 하여 사용하던 프로그램이었습니다. docker compose로 간단하게 설치할 수 있으며, 리눅스 CLI환경을 염두에 두고 있기 때문에 Selenium Hub를 이용하도록 설계되어 있습니다.

services:
  mysafetyreport:
    container_name: safetyreport
    image: fentanest/safetyreport:latest
    env_file:
      - .env 
    volumes:
      - ./data:/app/data
    restart: always

환경 설정값은 .env파일을 사용합니다.

[SELENIUM]
remotepath = http://localhost:4444

[LOGIN]
username = your_username
password = your_password

[TELEGRAM]
telegram_token = your_token
chat_id = your_chat_id

[SETTINGS]
interval = 60
max_retry = 10
max_empty_pages = 3
log_level = INFO
TZ = Asia/Seoul

[GOOGLESHEET]
sheet_key = your_sheet_key
  • remotepath : Selenium Hub 주소
  • username : 안전신문고 ID
  • password : 안전신문고 PW
  • telegram_token : 텔레그램 봇 토큰
  • chat_id : 텔레그램 봇 사용할 계정 chat_id
  • interval : 장애 시 다시 시도할 간격(초)
  • max_retry : 장애 시 최대 시도할 횟수
  • max_empty_pages : 윈도우 앱의 ‘조건부 탐색’ 기능. 신고내역에서 ‘진행’상태의 신고건이 한개도 없는 페이지를 설정한 숫자만큼 만날 경우 신고건 탐색 종료.
  • log_level = DEBUG 설정 시 상세한 로그 기록
  • TZ = Asia/Seoul (다른 시간대 사용할 이유가 없잖아요)
  • sheet_key = 구글 스프레드 시트 연동 시 연동할 스프레드 시트의 주소

구글 스프레드 시트 사용에 필요한 JSON키파일은 ./data/auth/gspread.json 경로 생성 후 직접 넣어주시면 됩니다.

실행 옵션 (start.py)

start.py 스크립트 실행 시 다음과 같은 인자를 사용하여 동작을 제어할 수 있습니다. Docker 환경에서는 docker exec -it <컨테이너_이름> python start.py [옵션] 형태로 사용할 수 있습니다.

  • --force: 이미 처리된 신고 건을 포함하여 모든 상세 내역을 다시 크롤링합니다.
  • --reset: 기존 데이터베이스 파일을 모두 삭제하고 처음부터 다시 시작합니다. (주의: 모든 데이터가 사라집니다.)
  • --min: ‘진행’ 상태의 신고가 max_empty_pages 설정값에 지정된 페이지 수만큼 연속으로 나오지 않으면 크롤링을 조기 종료합니다.
  • --p <페이지>: 지정된 페이지만 크롤링합니다.
    • 예시: python start.py --p 5 (5페이지 한 페이지만 크롤링)
  • --p <시작페이지>-<끝페이지>: 지정된 페이지 범위만 크롤링합니다.
    • 예시: python start.py --p 5-10 (5페이지부터 10페이지까지 크롤링)
  • --p <페이지1>,<페이지2>,...: 쉼표로 구분된 특정 페이지만 크롤링합니다.
    • 예시: python start.py --p 5,7,9 (5, 7, 9 페이지를 크롤링)
  • 모든 페이지는 30개씩 보기 상태에서 계산됩니다.

Crontab 사용

crontab에 /usr/bin/docker exec safetyreport python /app/start.py를 입력하여 주기적으로 실행할 수 있습니다.

텔레그램 봇과 연동 시, 주기적으로 신고내역을 긁어와 신규답변내용을 알람받을 수 있습니다.

0 9,12,18 * * * /usr/bin/docker exec safetyreport python /app/start.py

텔레그램 봇

.env값에 텔레그램 봇 토큰과 ID 를 제대로 넣었다면 윗 단락의 윈도우 설명과 동일한 기능의 봇이 작동합니다.

crontab을 활용하여 주기적으로 자동 크롤링을 지시하면 거의 최신화되어있는 DB에서 편하게 검색 등을 수행하고 야외환경에서도 상습위반차를 식별해낼 수 있습니다.

변경 이력

2024/05 ~ 2025/09 - v1.0.x

  • Github Repository 생성 및 습작 업로드
  • 로깅 모듈 추가
  • 텔레그램 봇 기능 추가

2025/09/10 - 윈도우용으로 레포 추가

2025/11/11 - v1.1

  • import 구문 오류 수정

2026/01/02 - v1.2

  • 텔레그램 봇 정보 미입력(비활성화) 시에도 봇을 실행해서 app.py 오류 메세지 띄우던 현상 수정
  • 불법주정차 시 ‘수용’여부 판단 기준 추가, 버스전용차로 메뉴 추출 로직 수정

2026/01/30 - v1.2.1

  • 구글 시트 업로드 시 3회까지 재시도하도록 수정, 500행 단위로 chunk 업로드 기능 추가

2026/02/25 - v1.2.2

  • 안전신문고 신고내역 첨부파일 이미지 추출로직 수정