개발자에게 '반복 작업'은 가장 큰 적입니다. 매주 토요일 저녁 8시 45분마다 동행복권 사이트에 들어가 당첨 번호를 확인하고, 내 사이트의 DB를 업데이트하는 일. 처음 한두 번은 할만하지만, 이걸 매주 해야 한다면? 바로 자동화가 필요한 순간입니다.
이번 포스팅에서는 저희 사이트의 핵심 기능 중 하나인 '로또 번호 자동 수집기'를 개발하면서 겪었던 기술적 이슈들과, 안정적인 크롤링 서버를 구축하기 위해 적용한 파이썬 테크닉들을 상세히 공유합니다.
1. Selenium 대신 Requests를 선택한 이유
크롤링 입문자들은 보통 브라우저를 직접 제어하는 Selenium을 선호합니다. 직관적이기 때문이죠. 하지만 서버 리소스가 제한적인 클라우드 환경(AWS, GCP 등)에서 매번 크롬 브라우저를 띄우는 것은 엄청난 메모리 낭비입니다.
로또 번호는 자바스크립트로 렌더링 되는 데이터가 아니라, HTML 원본에 박혀 있는 정적 데이터입니다. 따라서 저는 무거운 Selenium 대신, 가볍고 빠른 Requests와 BeautifulSoup4 라이브러리 조합을 선택했습니다. 결과적으로 스크립트 실행 속도를 3초에서 0.5초 미만으로 단축하고, CPU 점유율을 획기적으로 낮출 수 있었습니다.
2. 403 Forbidden 에러와 User-Agent 위장
코드를 짜고 첫 요청을 보냈을 때 마주친 건 데이터가 아닌 403 Forbidden 에러였습니다. 동행복권 서버가 봇(Bot)의 접근을 차단한 것입니다. 파이썬의 기본 requests 모듈은 헤더 정보 없이 요청을 보내기 때문에 서버 입장에선 수상한 접근으로 보일 수밖에 없습니다.
해결책은 간단하지만 중요했습니다. HTTP 헤더에 User-Agent 값을 추가하여 마치 일반 웹 브라우저(Chrome)가 접속한 것처럼 위장하는 것입니다. headers = {'User-Agent': 'Mozilla/5.0...'} 한 줄을 추가하자 굳게 닫혀있던 서버의 문이 열렸습니다. 크롤링의 기본은 '서버에 대한 예의'를 지키는 것임을 다시 한번 깨달았습니다.
3. HTML 구조 변경에 대비한 방어적 코딩
웹 사이트의 구조는 예고 없이 바뀝니다. div.win_result > h4 같은 CSS Selector에만 의존했다가는, 사이트 리뉴얼 시 크롤러가 바로 뻗어버립니다. 이를 방지하기 위해 정규표현식(Regular Expression)을 도입했습니다.
단순히 태그 위치만 믿는 것이 아니라, 텍스트 내에서 '000회'라는 패턴과 날짜 패턴을 찾아내 검증하는 로직을 추가했습니다. 또한, try-except 블록으로 네트워크 에러나 파싱 에러를 감지하고, 실패 시 관리자에게 즉시 알림을 보내거나 캐시(Cache)된 이전 데이터를 보여주도록 설계하여 서비스의 가용성(Availability)을 확보했습니다.
📌 Key Takeaway
크롤링은 데이터를 가져오는 것보다 '어떻게 안정적으로 유지할 것인가'가 더 중요합니다. 예외 처리 없는 크롤러는 시한폭탄과 같습니다. 항상 '실패할 수 있음'을 가정하고 코드를 작성하세요.
이 기술로 만든 실시간 로또 명당 지도를 확인해보세요!
🗺️ 로또 명당 지도 & 생성기 보기