[Data & AI]Selenium으로 구현한 파일 자동 다운로드 크롤러

티스토리 블로그 : https://datasrep.tistory.com/49

안녕하세요!

혹시 이런 경험 있으신가요?

 매번 같은 사이트에서 게시글을 하나씩 클릭해서 첨부파일을 받고,
다시 목록으로 돌아가서 다음 게시글을 클릭하고,
또 저장하고… 또 클릭하고… 

 하루 이틀도 아니고, 반복될수록 너무 지겹죠.
 그래서 저는 이 지겨운 루틴을 벗어나기 위해 Selenium으로 웹 자동화 크롤러를 만들어봤습니다.
 한 번의 실행만으로 검색 → 다운로드 → 폴더 정리까지 자동으로 해주는 Selenium 기반 크롤러입니다. 


💡여기서 크롤링(Crawling)이란?

간단히 말하면, 사람이 웹사이트를 누비며 정보를 확인하고 저장하던 일을 컴퓨터가 대신 해주는 것입니다.
예를 들어 뉴스 기사, 쇼핑몰 상품 정보, 공공 데이터 등 웹에 공개된 대부분의 정보는 크롤링을 통해 자동으로 수집할 수 있어요.

크롤링은 방식에 따라 크게 두 가지로 나뉘는데요:

📌 1. 정적 크롤링 (Static Crawling)

HTML 소스만으로도 정보가 보이는 사이트

이런 사이트는 requests와 BeautifulSoup만으로도 충분합니다.
빠르고 가볍죠.
하지만 요즘 대부분의 사이트는 이 방법만으론 부족합니다.

 📌  2. 동적 크롤링 (Dynamic Crawling)

버튼을 눌러야 목록이 뜨거나, 스크롤을 내려야 계속 로딩되는 사이트

이럴 땐 실제 사람이 마우스와 키보드로 조작하듯 동작해야 해서 Selenium이라는 도구를 사용합니다.

💡Selenium은 웹 브라우저를 자동으로 조작할 수 있게 해주는 Python 라이브러리입니다.
로그인, 검색, 스크롤, 파일 다운로드처럼 사람이 하던 동작을 코드로 대신 수행할 수 있어요.

Selenium은 Chrome뿐 아니라 Firefox, Edge, Safari 등 다양한 브라우저를 지원하지만,
설정이 가장 간단하고 안정적인 Chrome이 실무에서 가장 널리 사용됩니다.
저도 이번 프로젝트에서 Chrome을 사용했습니다.

💡 한 가지 더! Selenium이 브라우저를 직접 조작하는 건 아니에요.
브라우저와 코드를 연결해주는 중간다리, 바로 크롬 드라이버(Chromedriver)가 필요합니다.

저는 매번 드라이버를 수동 설치하지 않기 위해
webdriver-manager를 사용해 자동 설치되도록 설정했습니다:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

이렇게 설정해두면 내 크롬 버전에 맞는 드라이버가 자동으로 설치되고,
실행 시 호환성 문제도 줄어들어 훨씬 편리해요!


✨ 제가 만든 크롤러는 이런 흐름으로 동작합니다!

    (1) 사이트 진입 및 목록 로딩
    (2) 특정 키워드가 포함된 게시글 제목만 수집
    (3) 각 게시글 제목으로 검색
    (4) 검색 결과 클릭 → 첨부 파일 다운로드
    (5) 파일명을 기준으로 폴더별 정리

위 흐름을 실제로 구현하면서 Selenium의 다양한 기능을 활용했는데요.
그 중 몇 가지만 정리하여 소개해드리겠습니다.

1. 브라우저 다운로드 경로 지정

from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--start-maximized")
options.add_experimental_option("prefs", {
    "download.default_directory": str(download_dir),
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "safebrowsing.enabled": True
})

→ 매번 저장 경로 묻지 않고, 자동 지정 폴더로 저장됩니다!

2. 검색어 입력 + 버튼 클릭 자동화

# target_text는 검색할 text

search_input.clear()
search_input.send_keys(target_text)
search_button.click()

→ 사람이 입력하고 누르던 걸, 코드가 대신 해주는 거죠!

3. 팝업 감지

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

try:
    close_button = WebDriverWait(driver, 3).until(
        EC.presence_of_element_located((By.XPATH, '//button[contains(text(), "닫기")]'))
    )
    if close_button.is_displayed():
        close_button.click()
        time.sleep(1)
        continue
except:
    pass

→ 간혹 첨부파일이 없을 때 뜨는 팝업,
    하나하나 마우스로 닫던 걸 자동으로 감지해서 닫고 다음으로 넘어가도록 했습니다.

4. 자동 스크롤 + 게시글 제목 수집

def collect_titles_stop_after_same_count(driver, scroll_box_selector, pause=0.7, max_same=3, max_steps=100):
    scroll_box = driver.find_element(By.CSS_SELECTOR, scroll_box_selector)
    collected = []
    seen = set()

    initial_divs = driver.find_elements(By.CSS_SELECTOR, "div.slick-link")
    for div in initial_divs:
        try:
            title = div.text.strip()
            if "표준공사코드" in title and title not in seen:
                collected.append(title)
                seen.add(title)
        except StaleElementReferenceException:
            continue

    same_count = 0
    previous_count = len(collected)

    for step in range(1, max_steps + 1):
        driver.execute_script("arguments[0].scrollTop += 500;", scroll_box)
        time.sleep(pause)

        try:
            titles = [
                div.text.strip()
                for div in driver.find_elements(By.CSS_SELECTOR, "div.slick-link")
                if "표준공사코드" in div.text.strip()
            ]
            new_titles = [t for t in titles if t not in seen]

            for title in new_titles:
                collected.append(title)
                seen.add(title)

            current_count = len(collected)

            if current_count == previous_count:
                same_count += 1
            else:
                same_count = 0
                previous_count = current_count

            if same_count &gt= max_same:
                break

        except StaleElementReferenceException:
    return collected

→ 스크롤을 내려야 게시글이 계속 보이는 구조라면?
    자동으로 스크롤이 내려가면서 새로 뜨는 제목을 계속 수집합니다.
    단, 더 이상 새로운 글이 안 나오면 멈춰요.


이 크롤러를 통해 반복되던 수작업을 자동화하고, 파일 정리까지 한 번에 해결할 수 있었습니다.

해당 흐름의 크롤러는 이런 업무들에 활용할 수 있겠죠?

  - 매주 올라오는 자료 정리 (공공 데이터, 입찰 공고 등)
  - 제품 업데이트 수집, 매뉴얼 다운로드
  - 게시판 순회 모니터링

이렇게 실제 업무에서 반복되는 웹 탐색과 다운로드 작업이 있다면, Selenium을 활용해 자동화해보는 것도 추천드립니다!👍

읽어주셔서 감사합니다. ㅇ_<☆

78b3250d89d53.png

데이터스랩(주) 공식 홈페이지 

©2025. DATASREP All rights reserved.

데이터스랩(주) 공식 홈페이지  |  경기도 평택시 고덕여염로 118, SBC비즈니스센터 935호  |  ☎ 031.8094.1146  |  🖷 031.8094.1147  |  🖂 datasrep@datasrep.com
©2025. DATASREP All rights reserved.