안녕하세요! 웹 크롤링 프로젝트를 진행하다 보면, 개발자는 종종 이런 고민에 빠지게 됩니다.
"내 크롤러는 왜 자꾸 한밤중에 죽어있을까?"
"수집한 데이터에 왜 이렇게 잘못된 정보가 많지?"
"이걸 언제까지 매일 손으로 돌려야 하지?"단순히 데이터를 수집하는 크롤러는 웹사이트 구조 변경, IP 차단, 데이터 오염 등 작은 변화에도 쉽게 멈춰버리는 연약한 존재입니다. 개발자의 지속적인 개입 없이는 무용지물이 되기 십상이죠.
그래서 저희 프로젝트에서는 이 문제를 근본적으로 해결하기 위해, 한 단계 더 나아가 스스로를 진단하고, 문제를 해결하며, 24시간 365일 쉬지 않고 동작하는 '무인 운영 자동화 시스템'을 구축했습니다. 더 나아가, "7일 걸리던 작업을 6시간 만에 끝내는" 극적인 성능 최적화 과정과, JavaScript로 렌더링되는 까다로운 웹사이트에서 데이터를 캐내는 비법까지, 저희 크롤러에 '잠들지 않는 심장'을 달아준 그 모든 여정을 이 글에 상세히 공유하고자 합니다.
모든 자동화의 시작은 '스케줄링'과 '지능적인 자기 관리'입니다. 저희는 파이썬의 schedule
라이브러리를 활용해 크롤러의 모든 작업을 지휘하는 중앙 통제 시스템을 만들었습니다. 이 시스템은 단순히 정해진 시간에 작업을 실행하는 것을 넘어, 각 시스템의 상태를 종합적으로 관리하는 두뇌 역할을 합니다.
주요 자동화 스케줄:
이 모든 작업은 하나의 클래스(AutomatedOperations
)에 의해 유기적으로 연결되어, 마치 하나의 생명체처럼 스스로를 돌보며 동작합니다.
잘못된 데이터는 서비스의 신뢰도를 떨어뜨리는 가장 큰 적입니다. 우리는 데이터가 DB에 저장되는 과정에서 스스로를 정제하고 치유하는 강력한 면역 시스템을 구축했습니다.
1. ML 기반 중복 데이터 자동 탐지:
"강남 돼지상회"와 "돼지상회 강남점"은 같은 가게일까요? 사람은 쉽게 판단하지만 기계는 어렵습니다. 우리는 이 문제를 머신러닝으로 해결했습니다.
2. 데이터 유효성 검증 및 자동 수정:
수집된 데이터에 포함될 수 있는 논리적 오류를 자동으로 찾아내고 수정합니다.
크롤러 운영의 가장 큰 스트레스는 예기치 않은 '돌발 상황'입니다. 우리는 크롤러가 스스로 위험을 감지하고 회피하는 반사 신경을 심어주었습니다.
열심히 수집한 가게가 다음 날 폐업한다면, 이 데이터는 더 이상 유용하지 않습니다. 우리는 가게의 '생사'를 주기적으로 확인하는 건강 관리 시스템을 도입했습니다.
아무리 시스템이 똑똑해도, 무슨 일이 벌어지는지 알 수 없다면 소용없겠죠. 우리는 크롤러가 자신의 상태를 개발자에게 꾸준히 '보고'하도록 만들었습니다.
"서울 시내 무한리필 가게 정보 전체 수집, 예상 소요 시간: 7일"
프로젝트가 특정 단계에 도달했을 때 마주한 암담한 현실이었습니다. 서울 25개 구, 수많은 키워드를 하나의 프로세스로 순차 처리하니 속도가 너무 느렸고, 이대로는 데이터를 최신 상태로 유지하는 것이 불가능했습니다. 그래서 우리는 '압도적인 성능 최적화'를 다음 목표로 잡았습니다.
어떻게 7일짜리 작업을 단 6시간으로 단축시켰을까요? 그 비결은 세 가지 핵심 기술에 있었습니다.
multiprocessing
)가장 먼저 해결해야 할 문제는 '느린 속도'였습니다. 하나의 일꾼(프로세스)이 서울 전역을 돌아다니는 대신, 여러 명의 일꾼이 각자 구역을 맡아 동시에 일하게 만들면 어떨까요? 바로 병렬 처리(Parallel Processing)의 시작이었습니다.
multiprocessing
의 ProcessPoolExecutor
를 활용했습니다.이 방식 하나만으로도 이론적으로 CPU 코어 수만큼의 성능 향상을 기대할 수 있었습니다.
크롤링을 하다 보면 어제 검색했던 키워드를 오늘도 검색하고, 이미 방문했던 가게 상세 페이지를 또 방문하는 일이 비일비재합니다. 이는 엄청난 네트워크 자원 낭비이자, IP 차단 위험을 높이는 주범입니다.
COPY
명령어)수만 개의 데이터를 데이터베이스에 저장할 때, INSERT
구문을 하나씩 반복 실행하는 것은 대표적인 성능 병목 구간입니다.
COPY
명령어를 활용하여 데이터를 대량으로, 그리고 매우 빠르게 적재하는 방식을 채택했습니다.io.StringIO
를 사용해 수집된 데이터 목록을 메모리 상에서 마치 하나의 거대한 CSV 파일처럼 만듭니다.COPY
: cursor.copy_from()
메서드를 호출하여 메모리에 있던 모든 데이터를 단 한 번의 명령으로 DB 테이블에 쏟아붓습니다.ON CONFLICT
구문을 사용하여 중복 데이터는 업데이트하거나 무시하도록 처리합니다.이 방법을 통해 개별 INSERT
대비 20배 이상의 놀라운 데이터베이스 쓰기 성능을 확보할 수 있었습니다.
결과: 30배 빨라진 크롤러의 탄생!
병렬 처리로 시간을 나누고, 캐싱으로 불필요한 과정을 생략하며, 고성능 DB 처리로 병목을 제거한 결과, 7일 걸리던 작업은 단 6~12시간 만에 끝낼 수 있게 되었습니다.
"분명히 눈에는 보이는데, 왜 크롤러는 데이터를 못 가져올까요?"
최신 웹사이트들은 React, Vue.js 같은 JavaScript 프레임워크를 사용해 동적으로 데이터를 화면에 그려줍니다. 이 때문에 초기 HTML 소스는 텅 비어있고, 우리가 원하는 정보는 브라우저가 JavaScript를 모두 실행한 뒤에야 나타나죠.
저희 프로젝트 역시 특정 동적 사이트에서 GPS 좌표와 같은 핵심 정보를 수집해야 하는 큰 숙제를 안고 있었습니다. HTML 어디에서도 찾을 수 없는 이 데이터를 어떻게 추출했을까요?
개발자 도구(F12)는 우리의 가장 친한 친구입니다. Network 탭, HTML 구조, JavaScript 소스 코드를 샅샅이 뒤진 결과, window
객체의 특정 전역 변수(예: window.PLACE_INFO
, window.poi
) 안에 우리가 찾던 위도, 경도 값이 고스란히 담겨 있는 결정적 단서를 발견했습니다!
BeautifulSoup은 렌더링된 HTML을 파싱할 뿐, JavaScript를 실행할 수는 없습니다. 바로 이 지점에서 Selenium이 진가를 발휘합니다.
Selenium의 driver.execute_script()
메서드는 브라우저의 콘솔에서 JavaScript 명령어를 직접 실행하고 그 결과를 파이썬으로 반환받을 수 있게 해줍니다. 우리는 이 기능을 활용해 HTML을 파싱하는 대신, JavaScript 변수 값을 직접 빼내는 전략을 선택했습니다.
# src/core/crawler.py 의 핵심 로직 예시
def _extract_coordinate_info(self) -> Dict:
try:
# JavaScript 실행으로 좌표 정보가 담긴 전역 변수 값을 직접 가져옴
lat_script = "return window.latitude || (window.PLACE_INFO && window.PLACE_INFO.lat);"
lng_script = "return window.longitude || (window.PLACE_INFO && window.PLACE_INFO.lng);"
lat = self.driver.execute_script(lat_script)
lng = self.driver.execute_script(lng_script)
if lat and lng:
return {'lat': float(lat), 'lng': float(lng)}
except Exception as e:
logger.error(f"JavaScript 좌표 추출 오류: {e}")
return {}
이 방법은 웹사이트의 디자인(CSS 클래스명 등)이 바뀌어도 JavaScript 변수명은 상대적으로 잘 바뀌지 않기 때문에, HTML 파싱보다 훨씬 안정적이고 정확합니다.
'영업시간' 정보처럼, '더보기' 버튼을 클릭해야만 나타나는 데이터도 있었습니다. 이 문제는 다음과 같이 사용자 행동을 시뮬레이션하여 해결했습니다.
button.click()
)합니다.time.sleep()
이나 WebDriverWait
를 사용하여 새로운 정보가 렌더링될 시간을 확보합니다.하나의 방법만 고집하는 것은 위험합니다. 우리는 어떤 상황에서도 데이터를 놓치지 않기 위해 다음과 같은 다층적 추출 전략을 설계했습니다.
<script>
태그 내에 숨겨진 JSON 데이터 파싱 (차선책)이 프로젝트는 웹에서 데이터를 긁어오는 단순한 작업을 넘어, 데이터의 품질과 최신성을 스스로 유지하고, 자신의 문제를 해결하며, 운영 비용을 최소화하는 자동화된 데이터 파이프라인을 구축하는 여정이었습니다.
이러한 자동화 시스템 덕분에 개발자는 더 이상 매일 크롤러 로그를 들여다보거나, 오류 때문에 새벽에 깨는 일 없이, 서비스의 핵심 가치를 개발하는 데 더 집중할 수 있게 되었습니다.
여러분도 혹시 밤마다 크롤러의 안녕을 걱정하고 계신가요? 그렇다면, 오늘 소개해 드린 자동화 시스템 구축과 성능 최적화, 그리고 지능형 데이터 추출 경험이 여러분의 크롤러에게도 '잠들지 않는 심장'을 달아주는 데 작은 영감이 되기를 바랍니다.