Summary#
ililtoon 같은 사이트별 episode collector에서 episode identity를 URL 문자열이나 표시 제목만으로 정하면, title alias, season/part reset, 회차 번호 재시작, slug 변경, redirect/moved URL, lazy-loaded 목록 누락 때문에 같은 에피소드가 중복 저장되거나 서로 다른 에피소드가 하나로 병합될 수 있다.
안전한 설계는 “현재 관측 URL”을 canonical key로 직접 쓰지 않고, 별도 identity layer를 둔다. 권장되는 기본 키 모델은 다음과 같다.
series_key = site_scope + normalized_series_identity
episode_key = series_key + season_or_part_scope + normalized_episode_ordinal + stable_episode_fingerprint
observed_url = crawl 시점에 발견한 원본 URL
effective_url = redirect 후 최종 URL 또는 사이트 규칙상 대표 URL
alias_table = title/slug/URL/redirect/canonical 후보를 series_key 또는 episode_key에 매핑
핵심은 URL 정규화, redirect 추적, HTML rel=canonical 또는 canonical 후보의 별도 저장, title alias 관리, season/part boundary 감지, episode ordinal reset 처리, 콘텐츠/메타데이터 fingerprint를 조합하되 어느 하나도 절대 진실로 취급하지 않는 것이다.
Key Points#
- URL 문자열은 episode identity가 아니라 observation이다.
- RFC 3986 수준의 URI 정규화, 예: scheme/host lowercase, percent-encoding 처리, dot-segment 제거, fragment 제거, default port 제거는 필요하다.
- 그러나 query parameter는 사이트별 의미가 다르다.
id,episode,no,page,season같은 값은 episode identity일 수 있으므로 전역 제거하면 위험하다. -
따라서
observed_url,normalized_url,redirect_final_url,declared_canonical_url,collector_episode_key를 분리 저장한다. -
title alias는 series_key와 episode_key 양쪽에서 실패를 만든다.
- 같은 작품이 한글명, 영문명, 약칭, 띄어쓰기 차이, 특수문자 제거 slug, 이전 제목/개정 제목으로 나타날 수 있다.
- 표시 제목을 그대로
series_key로 쓰면 같은 작품이 여러 series로 갈라진다. - 반대로 aggressive normalization으로 제목을 과하게 접으면 서로 다른 작품이 충돌할 수 있다.
- 권장 구조:
text series_alias(alias_text, alias_type, source_url, first_seen_at, series_key, confidence) -
alias는 자동 병합보다 candidate cluster로 저장하고, URL 패턴·작가/작품 메타·episode 목록 overlap·thumbnail hash 등 보조 신호로 승격한다.
-
season reset과 part reset은 “회차 번호 = episode identity” 가정을 깨뜨린다.
1화,2화가 시즌 1과 시즌 2에서 반복될 수 있다.외전 1화,시즌2 1화,프롤로그,0화,후기,특별편은 단순 숫자 ordinal에 들어맞지 않는다.- 안전한 episode key는 최소한 다음 필드를 분리해야 한다.
text series_key arc_scope: main | season_2 | side_story | special | unknown ordinal_kind: numeric | prologue | epilogue | special | unknown ordinal_value display_title published_or_list_order -
season/part boundary가 불확실하면
season_unknown으로 보존하고, 나중에 재분류 가능한 migration path를 둔다. -
moved URL과 redirect는 중복 수집의 주요 원인이다.
- HTTP redirect는 리소스 이동 또는 대표 URL 변경 신호가 될 수 있지만, 항상 identity 동일성을 보장하지는 않는다.
- collector는 redirect chain을 저장해야 한다.
text observed_url -> redirect_1 -> redirect_final_url -
기존 episode가 새 URL에서 발견되면 즉시 새 row를 만들기보다:
- normalized URL match
- redirect final URL match
- declared canonical URL match
- series alias match
- episode ordinal/season match
- title similarity
- image/content fingerprint similarity
순으로 candidate를 좁히는 편이 안전하다.
-
HTML
rel=canonical은 강한 힌트지만 collector key 자체가 되면 안 된다. - 검색엔진 문서에서 canonical URL은 중복 URL 통합 신호로 설명되지만, 사이트 구현이 항상 정확하다는 뜻은 아니다.
- 일부 사이트는 모든 episode에 series landing page를 canonical로 넣거나, 잘못된 canonical을 재사용할 수 있다.
-
따라서
declared_canonical_url은 저장하되effective_collector_key와 분리한다. -
lazy-loaded episode list는 “목록 누락 → identity drift”로 이어진다.
- Playwright 기반 수집에서 초기 DOM만 읽으면 일부 episode가 누락될 수 있다.
- infinite scroll, pagination, “더보기”, client-side rendering이 섞인 경우 list order와 episode count가 crawl마다 달라질 수 있다.
- episode list extraction은 다음 불변조건을 검사해야 한다.
text count_increased_until_stable no_duplicate_observed_url_in_page list_order_monotonic_or_explainable same_series_key_across_pages crawl_snapshot_id stored -
lazy load 안정화 없이 upsert하면, 이후 재수집 시 누락 episode가 새 episode로 끼어들어 season/order 계산이 흔들릴 수 있다.
-
권장 canonical key는 단일 필드가 아니라 confidence가 있는 composite identity이다.
- 예시:
text episode_identity_candidate = { site: "ililtoon", series_key, season_scope, ordinal_kind, ordinal_value, normalized_episode_title, effective_url, declared_canonical_url, content_fingerprint, confidence } -
DB unique constraint는 너무 이른 단계에서 강하게 걸기보다, raw observation table과 resolved identity table을 분리하는 편이 안전하다.
text raw_episode_observation(id, crawl_id, observed_url, extracted_title, list_index, html_hash) resolved_episode(id, episode_key, series_key, season_scope, ordinal, status) episode_observation_link(observation_id, episode_id, confidence, resolver_version) -
실패 모드 요약
- 같은 episode가 title alias 때문에 다른 series에 중복 저장됨.
- 시즌 2의
1화가 시즌 1의1화를 overwrite함. - moved URL이 새 episode로 저장되어 duplicate row가 생김.
- canonical URL이 series landing page를 가리켜 여러 episode가 하나로 collapse됨.
- lazy load 누락으로 list order가 흔들려 ordinal-based key가 바뀜.
- query parameter 제거 규칙이 과해 실제 episode id가 사라짐.
- query parameter 보존 규칙이 약해 tracking URL마다 duplicate가 생김.
- 표시 제목 normalization이 과해 서로 다른 특별편/후기가 병합됨.
Cautions#
- 현재 대화 환경에는 사용자가 명시한
WebSearch/WebFetch도구가 제공되지 않았다. 따라서 아래 초안은 실시간 검색 결과를 직접 검증한 것이 아니라, 공개 표준 문서와 일반 crawler/canonicalization 원칙에 기반한 private capsule 초안이다. - 특정
ililtoonURL 패턴, 실제 HTML 구조, redirect 동작, canonical 태그 사용 여부는 확인하지 않았다. 사이트별 selector나 URL 규칙은 별도 검증 전까지 확정하면 안 된다. ililtoon이 저작권 침해 콘텐츠를 포함할 수 있는 사이트라면, 수집·저장·재배포는 법적·윤리적 위험이 있다. 이 capsule은 episode identity normalization 설계 관점의 메타데이터/collector 안정성 논의로 한정해야 한다.rel=canonical, redirect final URL, title alias, episode number, content hash 중 어느 하나도 단독 canonical key로 쓰기에는 위험하다.- Playwright lazy-load 처리 방식은 대상 사이트의 프론트엔드 구현에 따라 달라진다. 스크롤 안정화, 네트워크 idle, “더보기” 버튼, pagination API 관측은 사이트별로 다시 검증해야 한다.
- 콘텐츠 fingerprint는 이미지 재압축, 광고/워터마크, 서버 변환, crop 변경, 번역/수정 업로드 때문에 false positive와 false negative가 모두 가능하다.
Sources#
- https://www.rfc-editor.org/rfc/rfc3986
- https://www.rfc-editor.org/rfc/rfc9110
- https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls
- https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel
- https://developer.mozilla.org/en-US/docs/Web/API/URL
- https://playwright.dev/docs/locators
- https://playwright.dev/docs/actionability
- https://playwright.dev/docs/navigations
Related#
- Collector Pipeline Failure Modes: Recrawl Scheduling, Deduplication, and Zero-Yield Extraction
- Feed Collector Canonical URL Normalization and Idempotent Upsert Failure Modes
- Collector Incremental Ingestion: Cursor Watermarks, Idempotency Keys, and Duplicate Suppression Failure Modes
Sagwan Revalidation 2026-06-03T18:18:13Z#
- verdict:
ok - note: URL 정규화와 별도 identity layer 권장은 현재 practice와도 부합함
Sagwan Revalidation 2026-06-04T18:31:08Z#
- verdict:
ok - note: URL/별칭/시즌 경계 분리 원칙은 현재도 유효한 일반 설계다.