여러 사이트를 긁는 크롤러를 만들면 처음에는 사이트 하나에 코드 하나씩 붙이게 됩니다. 사이트가 셋을 넘어가면 그 방식은 금방 무너집니다. 사이트마다 데이터를 내주는 방식이 다른데 각 크롤러가 저장까지 제 방식대로 처리하면, 새 사이트를 붙일 때마다 전체 흐름을 다시 이해해야 하기 때문입니다. 법률 상담 게시판을 통합 수집하는 이 프로젝트에서도 같은 문제를 마주했고 접근 방식의 차이를 인터페이스 하나 뒤로 숨기는 방향으로 풀었습니다.
접근 방식이 게시판마다 다르다
수집 대상이 된 게시판들은 데이터를 내주는 방식이 서로 완전히 달랐습니다. 어떤 게시판은 검색 결과가 그대로 HTML 안에 담겨 있어 페이지를 읽어 필요한 조각만 파싱하면 됩니다. 어떤 게시판은 깔끔한 REST API를 열어 두어 JSON을 커서 방식으로 넘겨 가며 받으면 됩니다. 또 어떤 게시판은 목록 페이지 자체가 사라져, 개별 질문 페이지가 서버에서 미리 그려 내려보내는 공개 데이터를 읽어야 했습니다.
이 세 방식은 코드 모양이 전혀 다릅니다. HTML 파싱은 화면 구조에 맞춘 선택자가 필요하고 REST API는 페이지네이션 규칙을 따라야 하며 렌더링 데이터 방식은 유효한 글을 찾아 거슬러 올라가는 탐색이 필요합니다. 세 방식을 한 덩어리 코드에 섞으면 어느 게시판 하나만 바뀌어도 전체를 건드리게 됩니다.
결과물의 모양을 먼저 정한다
해법의 출발점은 "무엇을 돌려줄지"를 먼저 못 박는 것이었습니다. 게시판이 어떤 방식으로 데이터를 내주든, 수집기는 질문의 제목과 링크, 그리고 어느 게시판에서 왔는지를 담은 같은 형태의 목록을 돌려주기로 했습니다. 이렇게 결과물의 규격을 고정하면, 바깥에서는 게시판마다 무엇이 다른지 알 필요가 없어집니다.
그 위에 공통 인터페이스를 하나 두었습니다. 모든 수집기는 분야 목록을 받아 질문 목록을 돌려주는 같은 약속을 지키고 각자 안에서만 자기 게시판에 맞는 방식으로 데이터를 가져옵니다. HTML 게시판 수집기, REST 게시판 수집기, 렌더링 데이터 게시판 수집기가 겉모습은 똑같고 속만 다른 셈입니다. 이 약속 하나로 수집기들은 서로를 몰라도 되고 위에서는 모두 똑같이 다뤄집니다.
오케스트레이터는 목록을 순회할 뿐이다
인터페이스를 정해 두면 전체 흐름은 놀랄 만큼 단순해집니다. 매일 도는 오케스트레이터는 수집기 목록을 하나씩 꺼내 질문을 달라고 요청하고 돌려받은 목록을 정규화해 저장한 뒤 AI 분류로 넘길 뿐입니다. 오케스트레이터 코드 어디에도 특정 게시판의 이름이나 화면 구조가 등장하지 않습니다.
덕분에 새 게시판을 붙이는 일이 가벼워집니다. 새 게시판의 접근 방식이 무엇이든, 약속된 규격에 맞는 수집기 하나를 만들어 목록에 더하면 됩니다. 바깥의 정규화, 저장, AI 분류, 스케줄 흐름은 손대지 않습니다. 수집 대상을 넓히는 작업이 매번 처음부터 만드는 일이 아니라, 규격에 맞춰 끼워 넣는 일이 됩니다.
실패도 인터페이스 단위로 다룬다
같은 인터페이스를 쓰면 실패 처리도 일관됩니다. 오케스트레이터는 수집기를 하나씩 독립적으로 실행하고 한 수집기가 예외를 던지면 그 게시판만 실패로 기록한 뒤 다음 수집기로 넘어갑니다. 한 게시판의 화면이 바뀌어 파싱이 깨져도 나머지 수집은 그대로 이어집니다. 이 격리 덕분에 통합 수집이 "모 아니면 도"가 되지 않습니다. 실패 격리를 어떻게 기록으로 남기는지는 크롤러 실패 격리와 감사 로그에서 이어집니다.
자주 묻는 질문
사이트마다 다른 크롤링을 왜 인터페이스로 묶나요?
사이트가 늘수록 각 크롤러가 저장과 후처리까지 제 방식대로 하면 전체 흐름이 얽혀 유지보수가 어려워집니다. "무엇을 돌려줄지"를 규격으로 고정하고 "어떻게 가져올지"만 사이트별로 다르게 두면, 바깥 흐름은 사이트 수와 무관하게 일정하게 유지됩니다.
새 게시판을 추가하는 데 얼마나 손이 가나요?
바깥 흐름은 건드리지 않고 규격에 맞는 수집기 하나만 새로 만들면 됩니다. 그 게시판이 HTML이든 API든 렌더링 데이터든, 제목과 링크, 출처를 같은 형태로 돌려주게만 하면 정규화, 저장, AI 분류는 기존 코드가 그대로 처리합니다.
공통 인터페이스가 오히려 제약이 되지는 않나요?
수집기 안에서는 자기 게시판에 맞는 어떤 방식이든 자유롭게 쓸 수 있으므로, 인터페이스는 결과물의 모양만 약속할 뿐 방법을 제약하지 않습니다. 화면 파싱이 필요하면 파싱을, API가 있으면 API를 쓰되 밖으로 내보내는 형태만 맞추면 됩니다.
이 크롤러가 속한 전체 시스템은 법률 상담 게시판 통합 수집 자동화에서 볼 수 있습니다.