YouTube 댓글 수집에서 답글이 누락되는 이유: 2단계 페이지네이션과 완전성 검증
YouTube commentThreads에 항상 모든 답글이 포함되는 것은 아닙니다. 이 가이드는 공식 문서를 바탕으로 comments.list, parentId, 2단계 페이지네이션, 중복 제거, 댓글 수 불일치를 설명하고, 재현 가능한 수집 결과 검수 방법을 제시합니다.
YouTube 댓글 수집에서 답글이 누락된다면, 먼저 commentThreads만 읽었는지 확인하세요. 스레드 목록에 포함된 답글이 완전하다는 보장은 없습니다. 동영상의 스레드는 페이지네이션으로 가져와야 하고, 각 최상위 댓글 아래의 답글도 별도로 페이지네이션해야 할 수 있습니다. 첫 번째 단계의 끝에 도달했다고 해서 모든 답글을 가져온 것은 아닙니다.
이는 새로운 문제가 아닙니다. Baskaya는 Stack Overflow의 과거 토론에서 답글 수와 반환된 내용이 일치하지 않는다고 지적했습니다. 오래된 답변에는 Google+ 연동 시절의 추측이 담겨 있어 오늘날의 문제를 설명하지 못합니다. 지금도 유용한 것은 이 토론이 던지는 질문입니다. 지금 세고 있는 것이 스레드입니까, 댓글입니까, 아니면 API 응답에 첨부된 일부 답글입니까?
이 글은 2026년 9월 5일 기준 공식 문서를 바탕으로 이 차이를 설명하고 수집 결과를 검증하는 방법을 정리합니다. 공식 YouTube API 규칙을 다루는 글이며, EveryInfra의 테스트 보고서가 아니고 접근할 수 없는 콘텐츠를 복구해 준다고 약속하지도 않습니다.
commentThreads의 답글이 불완전한 이유
YouTube 리소스 문서에 따르면 commentThread는 최상위 댓글 하나와, 경우에 따라 첨부된 답글로 구성됩니다. 최상위 댓글은 snippet.topLevelComment에, 답글 목록은 replies.comments에 있으며, 후자는 일부만 담고 있을 수 있습니다. snippet.totalReplyCount는 해당 최상위 댓글의 답글 수이므로 전체 스레드 목록의 길이와 직접 비교할 수 없습니다. EveryInfra의 YouTube 댓글 API는 각 댓글의 reply_count를 반환합니다. 내보낸 뒤에는 이 값으로 실제로 확보한 답글 수를 확인하세요.
예를 들어 가상의 스레드에는 답글이 12개로 표시되지만 현재 객체에는 5개만 첨부되어 있다고 가정해 보겠습니다. 여기서 5는 스크래퍼가 수집 완료를 선언할 수 있는 답글 수도 아니고, 반환 배열을 12개 요소로 채워야 할 근거도 아닙니다. 같은 스레드 객체를 반복 요청하며 다음에는 더 많이 나오기를 기대할 것이 아니라, 해당 상위 댓글의 답글 엔드포인트를 계속 조회해야 합니다.
놓치기 쉬운 또 다른 차이는 스레드 ID와 최상위 댓글 ID입니다. 두 ID는 각각의 리소스에서 따로 읽고 기록해야 합니다. 한 샘플에서 두 문자열이 우연히 같았다고 해서 프로그램이 둘을 항상 바꿔 써도 된다고 가정해서는 안 됩니다. 데이터 모델에서 같아 보인다고 해서 API 정의상 용도가 같은 것은 아닙니다.
최상위 댓글과 답글의 페이지네이션 진행 상황을 따로 관리하기
공식 commentThreads.list는 videoId로 스레드를 읽고 응답의 nextPageToken으로 다음 페이지를 가져오는 방식을 지원합니다. maxResults의 상한은 페이지당 최대 100개 항목입니다. 이는 한 번의 요청으로 동영상의 모든 댓글을 받을 수 있다는 뜻도, 한 스레드에 답글이 최대 100개뿐이라는 뜻도 아닙니다.
특정 최상위 댓글의 답글을 가져오려면 comments.list 규칙에 따라 해당 댓글 ID를 parentId에 전달하고, 해당 답글 쿼리의 nextPageToken을 별도로 처리해야 합니다. 이 페이지네이션 토큰은 답글 쿼리에 속하므로 동영상 스레드 쿼리에 다시 넣을 수 없으며, 다른 부모 댓글의 토큰을 재사용할 수도 없습니다.
구현은 두 개의 작업 계층으로 나눌 수 있습니다. 동영상 작업은 최상위 댓글을 찾고, 부모 댓글 작업은 추가 답글을 가져옵니다. 각 부모 댓글은 자체적으로 수집을 이어갈 위치와 종료 사유를 유지합니다. 이렇게 하면 답글이 유난히 많은 토론 하나 때문에 이미 완료된 다른 스레드까지 처음부터 다시 수집하는 일이 생기지 않습니다.
진행 상황과 함께 요청 조건도 저장해야 합니다. searchTerms 사용 여부, 선택한 정렬 방식, 대상 동영상 등이 여기에 해당합니다. 처음부터 키워드로 범위를 제한했다면 이후의 완전성 선언도 해당 쿼리 범위에만 적용됩니다. 내보낸 파일에서 필터 조건을 빼서 “이 동영상의 전체 댓글”처럼 읽히게 해서는 안 됩니다.
완료 조건은 로그뿐 아니라 결과에도 기록하기
댓글 콘텐츠와 수집 진행 상황은 분리하는 것이 좋습니다. 콘텐츠는 플랫폼과 댓글 ID 기준으로 중복을 제거하고 동영상, 부모 댓글과의 연결, 관측 시각을 보존해야 합니다. 진행 상황은 현재 작업이 어디까지 진행되었는지를 나타냅니다. 이는 애플리케이션 측 설계 제안이며, 아래 필드는 YouTube나 EveryInfra가 그대로 반환하는 필드가 아닙니다.
최소한의 진행 레코드로도 다음 질문에 답할 수 있습니다. 스레드 목록이 마지막 페이지에 도달했는지, 어떤 부모 댓글이 답글 끝까지 도달했는지, 어떤 부모 댓글이 요청 실패나 작업 예산 때문에 중단되었는지, 마지막 확인 시각은 언제인지입니다. success: true만으로는 “최상위는 끝났지만 부모 댓글 하나에 아직 가져오지 못한 페이지가 2개 남아 있다”는 상태를 표현할 수 없습니다.
중복 제거는 콘텐츠를 저장할 때 이루어져야 합니다. 프로세스가 한 페이지를 쓴 직후 종료되면 복구 과정에서 같은 페이지를 다시 가져올 수 있습니다. 댓글 텍스트로 중복을 판단하기보다 ID 기준으로 이미 본 레코드를 업데이트하는 편이 더 믿을 만합니다. 두 사람이 똑같은 짧은 문구를 남겼다면 여전히 댓글 2개이며, 댓글 하나의 텍스트를 수정했다고 해서 곧바로 서로 독립된 사용자 의견 2개가 되어서는 안 됩니다.
진행 상황은 콘텐츠를 성공적으로 저장한 뒤에만 갱신해야 합니다. 현재 페이지를 저장하기 전에 다음 페이지를 기록하면 중간에 실패했을 때 데이터를 건너뛸 위험이 있습니다. 일반적으로 중복 제거를 전제로 다시 읽기를 허용하는 쪽이 페이지를 소리 없이 건너뛰는 쪽보다 검증하기 쉽습니다. 커서가 중복되거나 오랫동안 새 ID가 나타나지 않으면 실행을 멈추고 이상 상황으로 표시해야 합니다. 같은 페이지를 반복해서 재시도하는 것을 유효한 진행으로 취급해서는 절대 안 됩니다.
바로잡을 수 없는 댓글 수 불일치
먼저 객체 계층, 필터 조건, 2단계 페이지네이션을 확인한 다음 오류 유형을 살펴봅니다. 공식 스레드 목록 문서는 commentsDisabled, 권한 부족, 동영상이 없는 경우를 구분합니다. 어느 경우도 “현재 이 동영상에는 댓글이 없음”으로 처리해서는 안 됩니다. 쿼리가 성공해서 나온 빈 배열과 클라이언트가 예외를 삼켜서 반환한 빈 배열은 동일한 근거가 아닙니다.
수량 불일치가 있을 때는 관측 시점도 기록해야 합니다. 페이지에 표시된 수, 스레드 메타데이터, 페이지네이션 결과는 정확히 같은 순간에 가져온 것이 아닐 수 있습니다. 개수 차이만으로는 어떤 콘텐츠가 빠졌는지 확인할 수 없으며, 빠진 콘텐츠의 본문을 만들어 내는 것은 더더욱 안 됩니다. 읽을 수 있는 텍스트를 분석할 때는 실제로 수집되어 소속을 확인할 수 있는 댓글을 표본으로 사용하고, 불완전한 범위는 공개적으로 밝힙니다.
상태 확인 문구는 검증 가능한 표현으로 작성할 것을 권장합니다. 예를 들어 “이 쿼리의 스레드 페이지는 끝났고, 부모 댓글 안의 답글 작업 2개가 아직 완료되지 않았다”처럼 씁니다. 이는 “완전성 98%”보다 정직합니다. 후자에는 같은 정의로 산출한 신뢰할 수 있는 전체 분모가 필요하기 때문입니다. 분모가 없다면 정확해 보이는 백분율을 만들어 내서는 안 됩니다.
일반적인 HTTP 또는 파라미터 문제는 문서의 API 오류 처리를 참고하십시오. 재시도로 일부 일시적 실패는 처리할 수 있지만, 권한을 확대하거나 불완전한 답글 객체를 완전한 데이터셋으로 바꿀 수는 없습니다.
작은 샘플 4개로 스크래퍼 점검하기
처음부터 많은 동영상을 한꺼번에 돌리기보다, 접근 가능한 테스트 대상이나 합성 픽스처에서 네 가지 시나리오를 확인하면 오류를 분리하기가 더 쉽습니다.
- 스레드에 포함된 답글이 선언된 수량보다 적은 경우: 프로그램은 곧바로 완료를 선언하지 말고 답글 작업을 생성해야 합니다.
- 답글 목록에 다음 페이지가 있는 경우: 프로그램은 동영상 스레드 목록만 페이지네이션하지 말고 해당 부모 댓글도 계속 처리해야 합니다.
- 같은 페이지를 두 번 읽은 경우: 최종 고유 댓글 수가 두 배가 되어서는 안 되며, 부모-자식 관계도 일관되게 유지되어야 합니다.
- 부모 댓글 요청이 실패한 경우: 다른 결과는 유지할 수 있지만, 내보내기 결과에 일부가 불완전하다는 사실을 표시해야 하며 빈 답글로 기존의 유효한 결과를 덮어써서는 안 됩니다.
인수 테스트에서는 출력이 실제로 쓸모 있는지도 확인해야 합니다. 주제 분류를 할 때 “이건 틀렸다” 같은 답글은 부모 댓글과 분리되면 거의 해석할 수 없게 됩니다. 부모 댓글과의 연결을 보존하면 사람이나 모델이 토론 맥락으로 돌아갈 수 있습니다. Douyin 댓글과 답글 관계 문서에서도 이 모델링 문제를 다루지만, 플랫폼마다 요청 파라미터가 다르므로 서로 그대로 옮겨 쓸 수는 없습니다.
위 내용은 제안된 테스트이며, 이 글에서 실제 동영상을 대상으로 수행한 실험이 아닙니다. 이미 API에서 내보낸 JSON이 있다면 데이터를 재수집할 권한이 필요한지 판단하기 전에 이러한 구조와 상태를 오프라인으로 검증할 수 있습니다.
범위를 명시한 댓글 샘플 전달하기
“몇 개 항목을 수집했는가”는 결과의 일부일 뿐입니다. 분석에 적합한 내보내기 파일은 대상, 필터, 수집 시각, 부모-자식 관계, 중복 제거 방식, 미완료 항목까지 설명해야 합니다. 분석 보고서도 이 경계를 그대로 이어받아야 하며, 요약 단계에 들어갔다는 이유로 앞 단계에서 이미 알려진 누락을 빼서는 안 됩니다.
래핑된 데이터 API를 선택할 때는 통합 데이터 API 시작하기의 디렉터리 검증 방법으로 실제 제공되는 필드와 페이지네이션 기능을 항목별로 확인하십시오. 이 글의 공식 파라미터를 다른 API에 그대로 적용하거나, “댓글 지원”이 모든 계층과 과거 콘텐츠를 포괄한다고 가정해서는 안 됩니다.
YouTube 댓글 수집의 핵심은 페이지당 한도를 계속 늘리는 것이 아니라, 각 답글의 소속, 각 페이지네이션 작업의 진행 상황, 각 종료 사유를 설명할 수 있게 유지하는 것입니다. 그래야 수집 결과가 무엇을 놓쳤는지 설명하지 못하는 파일에 그치지 않고 분석의 근거가 될 수 있습니다.
참고 BL-04