당신의 에이전트가 공개 API에서 상품 목록이나 기관 목록을 페이지 단위로 긁어 온다. 스크립트는 오류 없이 끝났고, 파일에는 1만 줄이 넘게 쌓였다. 에이전트는 「수집 완료」라고 보고한다. 그런데 그 1만 줄이 사실은 같은 100줄의 반복이거나, 목록의 앞부분뿐이거나, 절반이 「한도 초과」 응답일 수 있다.
수집이 정상 종료했는데 왜 다 모인 게 아닌가
페이지를 넘기며 긁는 수집은 덜 모아도, 같은 것을 거듭 모아도, 실패를 완료로 세도 정상 종료한다 — 「끝났다」와 「다 모았다」는 별개의 사실이고, 뒤의 것은 원천의 총계와 대조해야만 알 수 있다. 수집기는 받은 응답이 진짜 다음 페이지인지, 목록이 거기서 정말 끝났는지 스스로 알지 못한다. 그래서 완전성 검사는 수집기 밖에서, 숫자로 한다.

수집기가 조용히 덜 모으는 세 가지 길
1. 페이지 번호를 무시하고 같은 페이지를 돌려준다. 어떤 API는 인증키 없는 체험(샘플) 모드에서 페이지 번호 파라미터를 무시하고 늘 첫 페이지를 돌려준다. 오류 코드도 없고 행 수도 그대로라, 수집기는 「페이지마다 100줄씩 잘 받았다」고 믿는다.
2. 목록 끝에 닿기 전에 멈춘다. 화면을 자동화로 읽을 때, 스크롤해야 나머지를 불러오는(지연 로딩) 목록은 처음 보이는 항목만 있다. 그 수를 세면 실제보다 훨씬 적게 나온다. API에서도 「빈 페이지가 오면 끝」 같은 종료 조건은 중간의 일시적 빈 응답에서 수집을 끊는다.
3. 실패를 「받은 것」으로 센다. 「이미 받은 키는 건너뛴다」는 이어받기 수집기는 편리하지만, 한도 초과(HTTP 429) 응답이 실패 행으로 기록되면 그 키도 「받은 것」이 되어 다음 실행이 다시 시도하지 않는다. 새 주기(다음 달)에 지난 결과 파일이 그대로 있으면 모든 키를 「이미 받음」으로 보고 0건 수집으로 끝나기도 한다.
수집 전에 무엇을 확인하나
본 수집을 돌리기 전, 1분이면 되는 확인 두 가지:
- 2페이지의 첫 행이 1페이지의 첫 행과 다른가. 같으면 페이지 번호가 먹지 않는 것이다. 인증키를 받거나, 원천이 주는 파일 내려받기를 쓰거나, 지역·분류 같은 필터로 쪼개 각각을 작게 받는다
- 원천이 총계를 알려 주는가. 응답의
totalCount류 필드, 관리 API의 목록 조회, 포털의 안내 숫자 등. 대조할 기준이 없으면 「다 모았다」를 말할 근거도 없다. 화면 대신 API가 있다면 API로 센다
수집 뒤에 무엇을 대조하나
수집이 끝나면 「완료」 보고 전에 숫자 세 개를 적는다.
- 원천 총계 = 받은 행 수인가. 다르면 어디서 잘렸는지 찾는다
- 고유 키 수 = 행 수인가. 고유 키가 훨씬 적으면 같은 페이지를 반복해 받은 것이다
- 실패 행 수 = 0인가. 실패 행은 완료로 세지 않고, 다음 실행이 다시 시도하게 둔다
이어받기 수집기라면 규칙도 몇 개 더 둔다.
- 새 주기는 지난 결과를 다른 곳으로 옮기고 처음부터(
--fresh) 시작한다 - 같은 한도 초과 응답이 N번 연속이면 한도가 바닥난 것으로 보고 멈춘다. 계속 두드리면 실패 행만 쌓인다
- 적재(DB에 넣는) 단계는 실패 행을 건너뛰고, 기존 값을 빈 값으로 덮어쓰지 않는다
에이전트에게 맡길 때는 이렇게 적어 둘 수 있다.
목록을 페이지 단위로 수집할 때:
- 본 수집 전에 1·2페이지를 받아 첫 행이 다른지 확인한다. 같으면 멈추고 보고한다
- 원천이 밝힌 총계를 먼저 적는다. 총계를 얻을 수 없으면 그 사실을 보고에 적는다
- 끝나면 [원천 총계 / 받은 행 / 고유 키 / 실패 행] 네 숫자를 보고한다
- 네 숫자가 맞지 않으면 "완료"라고 보고하지 않는다
다 받을 수 없을 때는 무엇을 자동화하나
전량 재수집이 몇 시간씩 걸려 매번 돌리기 어렵다면, 수집이 아니라 판정을 자동화한다. 주기적으로 무작위 표본 몇십 개를 원천과 대조해 어긋난 비율을 기록하고, 임계값을 넘으면 재수집을 알린다. 이때 알림 경로가 살아 있는지도 매번 같이 기록해야, 「문제가 생긴 주에야 알림이 안 온다는 걸 알았다」를 피한다.
우리가 겪은 일
- 반복 페이지: 공개 교육 데이터 API에서 학교 약 1.2만 곳을 인증키 없이 수집하려다, 2페이지가 1페이지와 똑같다는 것을 알았다. 오류 코드도 행 수 차이도 없었다.
- 지연 로딩 목록: 분석 도구 관리 화면을 자동화로 읽어 등록된 속성 수를 셌더니 6개였는데, 실제로는 25개였다. 끝까지 스크롤하지 않은 탓이었고, 관리 API로 세서 바로잡았다.
- 실패를 완료로: 공공 API에서 기관 약 1.2만 곳을 매달 재수집하는 이어받기 수집기가, 한도 초과 응답을 「받은 것」으로 세거나 지난달 파일 때문에 0건으로 끝났다. 실패 행을 완료에서 빼고, 연속 429에서 멈추고, 새 주기는 처음부터 시작하게 고쳤다.
- 표본 판정: 같은 서비스에서 표본 80곳을 매주 원천과 대조하게 했더니, 첫 임계 초과(어긋남 25%, 임계 8%)를 그 점검이 잡았다.
세 경우 모두 수집기는 성공으로 끝났다. 덜 모였다는 것을 알려 준 것은 수집기의 종료 상태가 아니라, 밖에서 센 숫자였다.
이전 글검색엔진과 분석 도구는 화면이 아니라 주소와 상태 코드를 센다 — 기계 독자에게 가는 신호를 따로 설계한다