🖥️ IT, 컴퓨터/🐍 Python

[Python] 중앙선거관리위원회 선거통계시스템 크롤링해서 엑셀 저장하기

김 홍시 2025. 6. 7.
반응형

 

문제상황

 

 

https://kimhongsi.tistory.com/entry/%EA%B3%B5%EA%B0%84%EC%9E%90%EB%A3%8C-%EC%A0%9C21%EB%8C%80-%EB%8C%80%ED%86%B5%EB%A0%B9%EC%84%A0%EA%B1%B0-%EA%B0%9C%ED%91%9C%EB%8B%A8%EC%9C%84%EB%B3%84-%EA%B0%9C%ED%91%9C%EA%B2%B0%EA%B3%BC

 

[공간자료] 제21대 대통령선거 개표단위별 개표결과

http://info.nec.go.kr/main/main_load.xhtml 중앙선거관리위원회 선거통계시스템선거통계시스템 점검 안내 위원회 선거정보통신망의 안정적 운영을 위한 시스템 점검에 따라 서비스 접속이 원활하지 않을

kimhongsi.tistory.com

위의 사이트에서 지역별 대선 결과를 얻을 수 있다. 

 

그러나 엑셀을 다운받아도, 하나의 구에 대해서만 받을 수 있다는 단점이 있다. 

 

 

해결방법

그러므로 아래처럼 조회한 내용을 엑셀로 저장하면 됨 

 

 

필요사항

- 라이브러리 버전 확인

- save_dir에서 경로 수정 필요

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
import pandas as pd
import os
import time

# ▒▒ 사용자 설정: 저장 경로 변경 가능 ▒▒
save_dir = r"C:\_당신의경로로바꾸세요\대선"
os.makedirs(save_dir, exist_ok=True)

# ▒▒ Selenium 크롬 드라이버 설정 ▒▒
options = webdriver.ChromeOptions()
# options.add_argument('--headless')  # 브라우저 안 띄우려면 주석 해제
driver = webdriver.Chrome(executable_path=ChromeDriverManager().install(), chrome_options=options)

# 실패 로그
fail_log = []

try:
    # 선거 정보 사이트 접속
    url = "http://info.nec.go.kr/main/showDocument.xhtml?electionId=0020250603&topMenuId=VC&secondMenuId=VCCP08"
    driver.get(url)
    wait = WebDriverWait(driver, 10)

    # '대통령선거' 버튼 클릭
    wait.until(EC.element_to_be_clickable((By.ID, "electionId1"))).click()
    time.sleep(0.25)

    # 시도 목록 가져오기 (첫 번째 '선택' 제외)
    wait.until(EC.presence_of_element_located((By.ID, "cityCode")))
    sido_select = Select(driver.find_element(By.ID, "cityCode"))
    sido_options = [option.text for option in sido_select.options if option.get_attribute("value") and option.text != "▽ 선 택"]

    for sido_name in sido_options:
        print(f"\n===== [{sido_name}] 시작 =====")

        # 시도 선택
        sido_select = Select(driver.find_element(By.ID, "cityCode"))
        sido_select.select_by_visible_text(sido_name)
        time.sleep(0.5)

        # 구/군 리스트 가져오기
        wait.until(EC.presence_of_element_located((By.ID, "townCode")))
        gugun_select = Select(driver.find_element(By.ID, "townCode"))
        gugun_options = [option.text for option in gugun_select.options if option.get_attribute("value") and option.text != "▽ 선 택"]

        for gugun_name in gugun_options:
            try:
                # 구 선택
                gugun_select = Select(driver.find_element(By.ID, "townCode"))
                gugun_select.select_by_visible_text(gugun_name)
                time.sleep(0.25)

                # '검색' 버튼 클릭
                search_btn = driver.find_element(By.CSS_SELECTOR, '#spanSubmit input[type="image"]')
                driver.execute_script("arguments[0].click();", search_btn)
                print(f"[✔] {sido_name} {gugun_name} 검색 완료")
                time.sleep(1)

                # 테이블 추출
                html = driver.page_source
                soup = BeautifulSoup(html, 'html.parser')
                table = soup.find('table', {'id': 'table01'})

                if table:
                    df = pd.read_html(str(table), header=[0, 1])[0]
                    df.columns = [' '.join(col).strip() for col in df.columns.values]
                    filename = os.path.join(save_dir, f"{sido_name}_{gugun_name}_개표결과.xlsx")
                    df.to_excel(filename, index=False)
                    print(f"[📁] 저장 완료: {filename}")
                else:
                    print(f"[❌] {sido_name} {gugun_name} 테이블 없음")
                    fail_log.append(f"{sido_name} {gugun_name} - 테이블 없음")

            except Exception as e:
                print(f"[⚠️] 오류 발생: {sido_name} {gugun_name} → {e}")
                fail_log.append(f"{sido_name} {gugun_name} - {e}")

        time.sleep(0.5)

finally:
    driver.quit()

    # 실패 로그 저장
    if fail_log:
        log_path = os.path.join(save_dir, "fail_log.txt")
        with open(log_path, "w", encoding="utf-8") as f:
            f.write("\n".join(fail_log))
        print(f"\n[📄] 실패한 지역 로그 저장 완료: {log_path}")
    else:
        print("\n✅ 모든 지역 성공적으로 저장 완료!")

 

반응형

댓글