ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 진학사 세특 탐구보고서 크롤링 프로그램 만들기
    크롤링 2026. 4. 2. 01:30

     

    고객 한 분 중에서, 진학사 사이트에 올라와 있는 세특 탐구보고서 데이터를 수천 건 단위로 정리해야 하는 사람이 있었다. 문제는 그 데이터가 한 페이지에 수십 개씩, 수백 페이지에 걸쳐 흩어져 있다는 거다. 학교명, 학부, 주제, 과목, 키워드, 보고서 유형, 업데이트일까지 — 항목마다 일곱 가지 정보를 하나씩 긁어서 엑셀에 옮기는 작업이었다. 한두 페이지야 괜찮겠지만, 수백 페이지를 손으로 넘기면서 복붙한다? 하루종일 매달려도 끝이 안 보이는 종류의 일이었다.

    처음 요청은 단순했다

     

    "진학사에 있는 세특 탐구보고서 목록을 엑셀로 뽑고 싶다"는 게 시작이었다. 단순해 보이지만, 실제로 사이트를 열어보면 이야기가 달라진다. 진학사의 세특 검색 페이지는 단순한 HTML 테이블이 아니었다. 카드 형태로 배열된 항목들이 동적으로 로딩되고, 페이지네이션도 버튼 클릭으로 이동하는 구조였다. 게다가 상단에 스와이퍼 슬라이더로 추천 콘텐츠가 따로 돌아가고 있어서, 데이터를 긁을 때 이 추천 영역과 실제 검색 결과를 구분하는 작업도 필요했다.

    요구사항을 정리하면 이랬다. 학교명과 학부, 탐구 주제, 보고서 유형, 과목, 활동, 키워드, 업데이트일을 한 건도 빠짐없이 뽑을 것. 페이지 수를 지정하거나 전체 페이지를 한 번에 돌릴 수 있을 것. 그리고 결과는 엑셀 파일로 깔끔하게 내보낼 것. 여기까지는 크롤러의 기본 스펙이었는데, 한 가지 조건이 더 붙었다. 사용하는 사람이 개발자가 아니기 때문에, 코드를 직접 만질 필요 없이 프로그램 창에서 설정하고 실행할 수 있어야 한다는 점이었다.

     

    GUI가 필요했던 이유

     

    크롤러를 만들 때 보통은 터미널에서 명령어 한 줄 치면 되는 스크립트로 끝내는 경우가 많다. 그런데 이번 프로젝트는 사용자가 비개발자였다. 페이지 수를 바꾸고 싶을 때마다 코드를 열어 숫자를 고치라고 할 수는 없었다. 대기 시간 조절, 브라우저 숨김 모드 같은 설정도 마찬가지였다. 그래서 프로그램을 켜면 바로 보이는 조작 화면을 만들기로 했다.

    화면 구성은 꽤 직관적으로 잡았다. 상단에 크롤링 설정 영역이 있고, 최대 페이지 수와 페이지 간 대기시간을 입력할 수 있다. 전체 페이지를 돌리고 싶으면 0을 넣으면 된다. 헤드리스 모드 체크박스를 켜면 브라우저 창 없이 백그라운드에서 돌아간다. 가운데에는 진행 상태 바와 수집 건수가 실시간으로 올라가고, 아래쪽 로그 창에는 지금 몇 페이지를 긁고 있는지, 항목이 몇 개 추출됐는지 시간 단위로 찍힌다. 크롤링 도중 멈추고 싶으면 중지 버튼을 누르면 현재 페이지까지 마무리하고 안전하게 멈춘다. 데이터가 쌓이면 Excel 저장 버튼 하나로 바로 파일이 나온다.

    이런 GUI가 있으면 사용자 입장에서는 "프로그램 하나 실행해서 버튼 누르면 끝"이 되는 거다. 코드를 몰라도, 터미널을 몰라도 상관없다.

    데이터 추출의 까다로운 부분

     

    크롤러의 핵심은 결국 "페이지에서 원하는 데이터를 정확히 뽑아내는 것"인데, 진학사 사이트의 구조가 그렇게 친절하지는 않았다. 카드 하나에 학교 정보, 주제, 메타 정보, 날짜가 각각 다른 위치에 다른 방식으로 들어가 있었다. 학교명과 학부는 첫 번째 div 안의 p 태그 두 개에 나뉘어 있었고, 주제는 특정 CSS 클래스가 붙은 div에서 뽑아야 했다. 보고서 유형, 과목, 활동, 키워드는 하나의 메타 영역 안에 파이프(|) 기호로 구분된 span들로 나열돼 있었는데, 이걸 순서대로 정확히 분리하는 로직이 필요했다.

    가장 신경 쓴 부분은 스와이퍼 영역과 실제 검색 결과를 구분하는 것이었다. 사이트 상단에 추천 콘텐츠가 슬라이더로 돌아가는데, 이 안에 있는 카드와 실제 검색 결과 카드의 HTML 구조가 비슷했다. 그래서 XPath를 설계할 때 스와이퍼 컨테이너의 하위 요소는 명시적으로 제외하는 조건을 넣었다. 이 한 줄이 빠지면 같은 데이터가 중복으로 잡히거나, 엉뚱한 추천 콘텐츠가 섞여 들어오는 문제가 생긴다.

    페이지 이동도 단순하지 않았다. 페이지 번호를 클릭하면 되는 것 같지만, 한 번에 보이는 번호 그룹이 제한돼 있어서 11페이지, 21페이지처럼 다음 그룹으로 넘어가야 하는 경우가 있었다. 이때는 "Next page" 버튼을 먼저 눌러서 그룹을 이동시킨 다음, 원하는 번호를 다시 찾아 클릭하는 재귀 로직을 넣었다. 단순히 다음 버튼만 누르는 방식이었으면 페이지 그룹 경계에서 크롤링이 멈춰버렸을 거다.

    그리고 페이지를 이동한 뒤에 데이터가 정말 바뀌었는지 확인하는 과정도 추가했다. 이전 페이지 첫 번째 카드의 URL을 기억해두고, 새 페이지에서 첫 번째 카드 URL이 달라질 때까지 기다리는 방식이었다. 단순히 "2초 기다리기"로 처리하면 네트워크 상태에 따라 아직 데이터가 안 바뀐 상태에서 긁어버리는 일이 생기기 때문이다. 이 대기 로직 덕분에 데이터 누락이나 중복 없이 안정적으로 수집할 수 있었다.

     

     

    결과와 사용 흐름

     

    프로그램을 실행하면 간단한 설정 창이 뜬다. 최대 페이지 수를 넣고, 시작 버튼을 누르면 끝이다. 진행 바가 움직이면서 로그 창에 "페이지 1 크롤링 중… 12개 항목 수집 완료"처럼 실시간 상황이 찍힌다. 100페이지 기준으로 대략 수백에서 수천 건의 데이터가 쌓이고, 크롤링이 끝나면 Excel 저장 버튼을 눌러 바로 파일로 받으면 된다. 파일을 열어보면 학교, 학부, 주제, 과목, 키워드까지 깔끔하게 정리돼 있다.

    사람이 직접 했으면 한 페이지당 복붙에 최소 2~3분은 걸렸을 거다. 100페이지면 3~5시간. 거기에 복붙 과정에서 빠뜨리는 항목이나 셀이 밀리는 실수까지 감안하면, 나중에 검수하는 데 또 시간이 든다. 이 프로그램은 같은 양을 에러 없이 10분 안에 처리한다. 사용자가 직접 건드리는 건 페이지 수 입력과 버튼 두 번 클릭뿐이다.

     

    이 프로젝트에서 얻은 것

     

    교육 관련 데이터 수집 프로젝트를 하면서 느낀 건, 사이트마다 동적 렌더링 방식이 다 다르다는 점이다. 진학사처럼 SPA 구조에 페이지네이션까지 동적으로 처리하는 사이트는, 단순 HTTP 요청으로는 데이터를 가져올 수 없다. 실제 브라우저를 띄워서 사용자가 보는 것과 똑같은 화면에서 데이터를 읽어야 한다. 그 과정에서 "데이터가 진짜 로딩됐는지"를 판단하는 대기 전략이 크롤러의 안정성을 좌우한다는 걸 다시 한번 확인했다.

    그리고 GUI를 붙이는 건 개발 시간이 조금 더 들지만, 비개발자 고객에게는 그게 프로그램의 전부다. 아무리 크롤링 로직이 정교해도, 터미널에서 명령어를 쳐야 하는 순간 사용자 절반은 포기한다. 버튼 하나, 입력 칸 하나가 접근성을 완전히 바꿔놓는다.

    혹시 특정 사이트에서 데이터를 대량으로 수집하거나 정리해야 하는 상황이 있다면, 생각보다 깔끔하게 자동화할 수 있는 경우가 많다. 사이트 구조만 파악되면, 나머지는 프로그램이 알아서 한다.

     

Designed by Tistory.