검색/웹 페이지에서 본문을 뽑아내는 도구를 만들고, 사라진 본문의 원인을 찾는다

웹 페이지에서 본문을 뽑아내는 도구를 만들고, 사라진 본문의 원인을 찾는다

브라우저, 서버, 명령줄, 엣지 환경에서 웹 페이지 본문을 뽑아내는 도구를 만들거나 고칠 때 쓴다. 정리 단계의 순서를 지키고, 제거한 것을 모두 기록하며, 페이지 HTML을 통한 스크립트 주입을 막고, 먼저 실패하는 작은 테스트로 수정을 증명한다.

이 AI 규칙을 사용하려면
## 지원하는 모든 환경에서 도구가 똑같이 동작하게 한다 특정 브라우저 구현이 아니라 안정적인 문서 인터페이스를 중심으로 추출기를 설계한다. 공유 파싱 동작을 변경하기 전에 지원하는 모든 환경과 제약 조건을 나열한다. - 브라우저 빌드는 기본 DOM을 사용할 수 있다. - 서버 빌드는 서로 다른 DOM 구현으로 생성된 문서를 받을 수 있으며 비동기 API를 제공할 수 있다. - 명령줄 빌드는 동일한 추출 의미를 유지하면서 기계 판독 모드와 텍스트 중심 모드를 제공해야 한다. - 엣지 런타임은 가장 제약이 큰 문서 구현을 제공할 수 있으므로 호환성의 최저 기준을 정해야 한다. - 패키지 진입점은 모듈 형식이 다르더라도 동일한 공개 동작을 제공해야 한다. 환경 어댑터는 얇게 유지한다. 런타임 제약 때문에 명시적인 예외가 필요한 경우를 제외하고 파싱, 점수화, 정규화, 무해화, 요소별 동작을 공유 계층에 둔다. ## 정리 단계의 순서를 지키고, 한 사이트를 위해 바꾸지 않는다 추출 파이프라인을 서로 바꿀 수 있는 정리 함수의 모음이 아니라 순서가 정해진 알고리즘으로 취급한다. 각 단계는 이후 단계가 사용하는 전제를 만들 수 있다. 기본적으로 다음 순서를 사용한다. 1. 캡슐화된 문서 트리를 평탄화한다. 2. 스트리밍되거나 지연된 콘텐츠를 해석한다. 3. 기본 콘텐츠를 자동으로 찾거나 명시적 선택자로 지정한다. 4. 제거 규칙이 숨기거나 버릴 수 있는 구조를 먼저 정규화한다. 5. 인식된 콜아웃을 안정적인 의미 표현으로 변환한다. 6. 너무 작은 미디어와 숨겨진 요소를 제거한다. 7. 점수가 낮은 블록을 제거한다. 8. 불필요한 요소에 정확 일치 및 부분 일치 선택자를 적용한다. 9. 반복되는 상용구와 기타 콘텐츠 패턴을 제거한다. 10. 남은 문서를 정규화한다. 11. 상대 링크와 리소스 위치를 해석한다. 단계 간 의존성이 분명하지 않다면 한 단계가 다른 단계보다 먼저 와야 하는 이유를 문서화한다. 특정 사이트 하나를 수정하려고 공유 단계의 순서를 바꾸기 전에, 새 순서가 필요한 모든 중간 표현을 보존한다는 사실을 범위가 명확한 테스트로 입증해야 한다. ## 제거 기록으로 본문이 사라진 단계를 찾는다 선택된 콘텐츠 루트와 각 제거 작업의 단계, 선택자, 이유, 대표 텍스트를 보고하는 디버그 모드를 제공한다. 디버그 모드는 진단 속성을 보존하고 증거를 없애는 구조 평탄화 작업을 건너뛸 수 있다. 예상한 콘텐츠가 사라지면 다음을 수행한다. 1. 제거 로그에서 누락된 콘텐츠를 찾는다. 2. 한 번에 한 단계씩 비활성화하여 손실을 일으키는 최초 단계를 식별한다. 3. 선택자가 원인이라면 정확 일치 선택자와 부분 일치 선택자를 구분한다. 4. 잘못된 루트가 선택되었다면 명시적 선택자로 자동 감지를 우회한다. 5. 보호된 코드 영역이나 서식이 유지된 영역이 일반 제거 대상에서 제외되는지 확인한다. 6. 수정 사항을 수용하기 전에 관련 없는 단계를 모두 다시 활성화한다. 최종 문서를 바탕으로 추측하기보다 가장 먼저 잘못된 전환에서 얻은 증거를 우선한다. 범위가 좁은 선택자, 순서 또는 요소 규칙으로 결함을 해결할 수 있다면 광범위한 정리 동작을 영구적으로 비활성화해서는 안 된다. ## 페이지 HTML을 적대적 입력으로 보고 스크립트 주입을 막는다 스크립트를 실행하거나 리소스를 불러오지 않는 안전한 문서 생성 도우미를 통해 마크업을 파싱한다. 신뢰할 수 없는 마크업을 브라우저 파싱 지점에 직접 할당해서는 안 된다. - 링크 및 미디어 속성에서 스크립트를 실행할 수 있는 URL 스킴을 제거한다. - 프레임에서 삽입 문서의 소스 콘텐츠를 제거한다. - 이벤트 처리기 속성을 제거한다. - 페이지에서 가져온 모든 값을 생성된 마크업에 삽입하기 전에 이스케이프한다. - 이스케이프 요구 사항이 명확해진다면 노드 생성과 속성 설정을 우선한다. - 완성된 결과의 무해화는 마지막 방어 수단으로 사용하고 안전한 생성 절차를 대신하게 해서는 안 된다. 미디어 URL, 대체 텍스트, 메타데이터 이미지, 설명에 있는 공격자 제어 따옴표가 속성을 끝내고 다른 속성을 주입할 수 있다고 가정한다. 마크업을 생성하는 모든 추출기에는 적대적인 속성 주입 테스트가 있어야 한다. ## 먼저 실패하는 작은 테스트 페이지로 수정을 증명한다 추출 결함이 있으면 실패를 계속 재현하는 가장 작은 문서 픽스처를 만들고 정확한 예상 결과와 연결한다. 픽스처는 결정적으로 유지하고 개인 식별자나 출처에 고유한 식별자를 포함하지 않는다. - 실제 이름, 이메일 주소, URL, 계정 식별자, 식별 가능한 텍스트를 일반적인 자리표시자로 바꾼다. - 실패한 파이프라인 단계를 실행하는 데 필요한 구조만 포함한다. - 보안 수정에는 오염된 속성이나 그에 준하는 적대적 페이로드를 포함한다. - 수정 사항을 적용하기 전에 픽스처가 실패하는지 확인한다. - 픽스처를 통과시키는 가장 작은 동작 변경을 적용한다. - 지원하는 모든 환경에서 대상 픽스처와 공유 추출 테스트 모음을 실행한다. 구현 변경 전후에 모두 통과하는 픽스처는 회귀 문제가 수정되었음을 입증하지 못한다. 수정 사항을 되돌리기 어렵다면 예상 결과나 제어 가능한 전환 기능을 구성하여 이전 동작이 실패한다는 사실을 계속 보여 준다. ## 환경마다 DOM과 번들 차이를 테스트한다 공유 알고리즘이 바뀌지 않더라도 문서 구현과 패키지 형식이 달라지는 경계 동작을 테스트한다. - 문서를 변경하기 전에 동적 요소 컬렉션을 정적 배열로 변환한다. - 패키지가 기본 내보내기만 노출하더라도 이름이 지정된 유틸리티에 계속 접근할 수 있는지 확인한다. - 비동기 서버 어댑터를 동기 브라우저 어댑터와 별도로 테스트한다. - 브라우저와 동일하다고 가정하지 말고 실제 요청 경계를 통해 엣지 런타임 동작을 테스트한다. - 동일한 픽스처 모음으로 명령줄의 텍스트 모드와 구조화 모드를 검증한다. - 환경별 우회책을 어댑터 내부로 제한하고 각 우회책을 범위가 명확한 호환성 테스트로 검증한다. 환경별 수정이 공유 결과를 변경한다면 이를 환경 간 동작 변경으로 취급하고 지원하는 모든 어댑터를 검증한다. 패키징 우회책이 추출기의 공개 계약을 조용히 재정의하도록 허용해서는 안 된다.