Files
AI/오픈소스분석자료/Trafilatura_분석_및_기능명세.md

750 lines
29 KiB
Markdown
Raw Permalink Normal View History

2026-05-13 19:57:34 +09:00
# Trafilatura 분석 및 기능 명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\trafilatura-master`
분석일: 2026-05-13
대상 버전: `trafilatura.__version__ = 2.0.0`
라이선스: Apache-2.0
## 1. 결론 요약
Trafilatura는 웹 문서에서 본문, 댓글, 메타데이터, 링크 후보를 추출하기 위한 Python 라이브러리이자 CLI 도구다. 범용 온톨로지 구축 플랫폼에서는 “웹 원천 데이터 수집 및 정제 계층”의 기본 소스로 거의 그대로 사용하기에 적합하다.
가장 가치가 큰 기능은 다음이다.
- 웹 페이지 다운로드: `fetch_url()`, `fetch_response()`
- HTML 본문 추출: `extract()`, `bare_extraction()`
- 구조 보존 추출: XML/HTML/Markdown/JSON/TEI 출력
- 메타데이터 추출: 제목, 저자, 날짜, canonical URL, 사이트명, 설명, 태그, 라이선스, 대표 이미지
- 링크 발견: RSS/Atom/JSON Feed, sitemap, robots.txt sitemap, focused crawler
- 중복 제거: 본문 세그먼트 LRU 중복 검사, 문서 fingerprint용 SimHash
- 설정 객체: `Extractor`, 결과 객체: `Document`
플랫폼 통합 권장 방식은 `bare_extraction(output_format="python", with_metadata=True)`를 기본으로 삼는 것이다. 이 방식은 문자열 출력으로 손실되기 전의 `Document` 객체, `body` XML tree, `commentsbody`, 정규화 텍스트, 메타데이터를 받을 수 있어 온톨로지 구축 전처리 단계와 연결하기 쉽다.
주의할 점은 전역 상태다. 다운로드 pool, 중복 LRU cache, crawler URL store가 모듈 전역에 존재한다. 단일 작업에서는 편하지만, 멀티 프로젝트/멀티 테넌트 플랫폼에서는 작업 단위 격리, cache reset, 도메인별 crawl 상태 저장을 별도 래퍼에서 관리해야 한다.
## 2. 프로젝트 구조
주요 디렉터리와 파일:
| 경로 | 역할 |
|---|---|
| `trafilatura/__init__.py` | 공개 API re-export |
| `trafilatura/core.py` | 추출 파이프라인 진입점 |
| `trafilatura/main_extractor.py` | Trafilatura 기본 본문/댓글 추출 알고리즘 |
| `trafilatura/htmlprocessing.py` | HTML 정리, 태그 변환, 링크 밀도 제거 |
| `trafilatura/metadata.py` | 메타 태그, JSON-LD, OpenGraph, 날짜/저자/URL 추출 |
| `trafilatura/json_metadata.py` | JSON-LD/schema.org 메타데이터 파싱 |
| `trafilatura/downloads.py` | HTTP 다운로드, Response 객체, 병렬 다운로드 |
| `trafilatura/feeds.py` | RSS/Atom/JSON feed 발견 및 URL 추출 |
| `trafilatura/sitemaps.py` | sitemap/robots.txt 기반 URL 발견 |
| `trafilatura/spider.py` | focused crawler |
| `trafilatura/deduplication.py` | LRU segment dedup, SimHash fingerprint |
| `trafilatura/xml.py` | JSON/CSV/XML/TEI/TXT 변환 |
| `trafilatura/settings.py` | `Extractor`, `Document`, 전역 상수 |
| `trafilatura/settings.cfg` | 사용자 조정 가능한 기본 설정 |
| `docs/` | 사용법/설정/다운로드/크롤링/중복제거 문서 |
| `tests/` | 단위 테스트, 실제 웹 페이지 평가 데이터 |
## 3. 외부 의존성
`pyproject.toml` 기준 필수 의존성:
- `certifi`: TLS 인증서
- `charset_normalizer >= 3.4.0`: 인코딩 탐지
- `courlan >= 1.3.2`: URL 정규화, 필터링, URL store, 링크 추출
- `htmldate >= 1.9.2`: 날짜 추출
- `justext >= 3.0.1`: fallback 본문 추출
- `lxml`: HTML/XML 파싱 및 XPath
- `urllib3 >= 1.26, < 3`: HTTP client
선택 의존성 `trafilatura[all]`:
- `brotli`, `zstandard`: 압축 응답 처리 강화
- `py3langid`: 언어 판별
- `pycurl`: 빠른 HTTP backend
- `urllib3[socks]`: SOCKS proxy
- `htmldate[speed]`: 날짜 추출 속도 개선
## 4. 핵심 데이터 모델
### 4.1 `Extractor`
파일: `trafilatura/settings.py`
추출 옵션을 담는 설정 객체다. 함수 인자가 많기 때문에 플랫폼에서는 개별 인자보다 `Extractor` 객체를 만들어 넘기는 방식을 권장한다.
주요 속성:
| 속성 | 의미 | 기본값 |
|---|---|---|
| `format` | 출력 형식 | `txt` |
| `fast` | fallback 알고리즘 생략 | `False` |
| `focus` | `balanced`, `precision`, `recall` | `balanced` |
| `comments` | 댓글 추출 | `True` |
| `formatting` | 굵게/기울임 등 구조 보존 | `False`, Markdown이면 자동 True |
| `links` | 링크 target 보존 | `False` |
| `images` | 이미지 정보 보존 | `False` |
| `tables` | table 추출 | `True` |
| `dedup` | 중복 세그먼트 제거 | `False` |
| `lang` | 목표 언어 필터 | `None` |
| `url` | 원문 URL | `None` |
| `with_metadata` | 메타데이터 추출/출력 포함 | `False` |
| `only_with_metadata` | 핵심 메타데이터 없으면 폐기 | `False` |
| `tei_validation` | TEI 출력 검증 | `False` |
| `date_params` | `htmldate` 날짜 추출 옵션 | 현재 날짜 max_date |
| `author_blacklist` | 제외할 저자명 집합 | 빈 set |
| `url_blacklist` | 제외할 URL 집합 | 빈 set |
### 4.2 `Document`
파일: `trafilatura/settings.py`
추출 결과와 메타데이터를 담는 객체다.
필드:
| 필드 | 설명 |
|---|---|
| `title` | 제목 |
| `author` | 저자 |
| `url` | canonical URL 또는 입력 URL |
| `hostname` | 호스트명 |
| `description` | 설명/요약 메타 |
| `sitename` | 사이트명/매체명 |
| `date` | 발행일 |
| `categories` | 카테고리 목록 |
| `tags` | 태그 목록 |
| `fingerprint` | SimHash 기반 문서 fingerprint |
| `id` | 호출자가 넘긴 record id |
| `license` | 라이선스 정보 |
| `body` | 본문 XML tree |
| `comments` | 댓글 텍스트 |
| `commentsbody` | 댓글 XML tree |
| `raw_text` | 내부 추출 텍스트 |
| `text` | 최종 출력 문자열 또는 python 모드 텍스트 |
| `language` | 감지 언어 |
| `image` | 대표 이미지 |
| `pagetype` | OpenGraph page type |
| `filedate` | 파일 날짜 |
`Document.as_dict()`로 dict 변환이 가능하다.
## 5. 본문 추출 파이프라인
핵심 진입점:
- `extract(filecontent, ...) -> Optional[str]`
- `extract_with_metadata(filecontent, ...) -> Optional[Document]`
- `bare_extraction(filecontent, ...) -> Optional[Document]`
권장 기본 호출:
```python
from trafilatura import bare_extraction
doc = bare_extraction(
html,
url=url,
output_format="python",
with_metadata=True,
include_comments=False,
include_tables=True,
include_formatting=True,
include_links=True,
deduplicate=True,
)
```
처리 순서:
1. `load_html()`로 문자열/bytes/LXML 입력을 HTML tree로 변환한다.
2. `target_language`가 있고 fast mode이거나 언어 판별 모듈이 없으면 HTML lang 속성을 먼저 검사한다.
3. `with_metadata=True`이면 `extract_metadata()`로 메타데이터를 추출한다.
4. `only_with_metadata=True`이면 `date`, `title`, `url`이 모두 없을 때 문서를 폐기한다.
5. 사용자가 지정한 `prune_xpath`를 tree에서 제거한다.
6. `tree_cleaning()`으로 불필요 태그와 섹션을 제거한다.
7. `convert_tags()`로 HTML 태그를 내부 구조 태그로 변환한다.
8. `include_comments=True`이면 댓글 영역을 먼저 추출하고 본문 tree에서 분리한다.
9. `extract_content()`로 Trafilatura 기본 본문 추출을 수행한다.
10. `fast=False`이면 readability/jusText 계열 fallback과 비교하여 더 나은 결과를 선택한다.
11. 본문 길이가 너무 짧고 precision 모드가 아니면 `baseline()` fallback을 수행한다.
12. `deduplicate=True`이면 LRU cache 기반 중복 본문을 폐기한다.
13. `target_language`가 있으면 최종 텍스트 언어를 검사한다.
14. 요청 형식에 따라 TXT/Markdown/JSON/CSV/HTML/XML/TEI로 변환한다.
## 6. 출력 형식
지원 형식:
| 형식 | 함수 인자 | 용도 |
|---|---|---|
| Python object | `bare_extraction(output_format="python")` | 온톨로지 파이프라인 권장 |
| Plain text | `output_format="txt"` | 단순 텍스트 저장 |
| Markdown | `output_format="markdown"` | 구조 일부 보존, LLM 입력에 유용 |
| JSON | `output_format="json"` | API 저장/교환 |
| CSV | `output_format="csv"` | 배치 처리 결과 |
| HTML | `output_format="html"` | 정제된 HTML preview |
| XML | `output_format="xml"` | 구조 보존 |
| XML-TEI | `output_format="xmltei"` | 인문학/말뭉치 표준 |
온톨로지 구축 플랫폼에서는 다음 전략이 적합하다.
- 원천 보존: raw HTML 별도 저장
- 추출 본문: `Document.text`
- 구조 본문: `Document.body`
- 메타데이터: `Document.as_dict()` 중 primitive 필드
- LLM/IE 입력: Markdown 또는 XML 변환본
- 장기 말뭉치 교환: XML-TEI 선택 가능
## 7. 메타데이터 추출 기능
파일: `trafilatura/metadata.py`, `trafilatura/json_metadata.py`
추출 출처:
- OpenGraph: `og:title`, `og:description`, `og:site_name`, `og:image`, `og:type`, `og:url`
- Twitter cards: `twitter:title`, `twitter:description`, `twitter:image`, `twitter:site`, `twitter:url`
- 표준 meta name: `author`, `description`, `keywords`, `publisher`, `dc.*`, `dcterms.*`, `citation_*`
- JSON-LD/schema.org: `application/ld+json`
- HTML heading: `h1`, `h2`
- canonical/base/alternate link
- `htmldate.find_date()` 기반 날짜 추출
- Creative Commons license URL/text 패턴
기능 명세:
| 기능명 | 입력 | 출력 | 실패 조건 |
|---|---|---|---|
| `extract_metadata` | HTML tree/string, URL, date params | `Document` | HTML 파싱 실패 시 빈/부분 Document |
| `extract_meta_json` | HTML tree, Document | JSON-LD 반영 Document | JSON 파싱 실패 시 fallback parser 사용 |
| `extract_opengraph` | HTML tree | dict | 해당 meta 없으면 None 값 |
| `extract_title` | HTML tree | str 또는 None | 제목 후보 없음 |
| `extract_author` | HTML tree | str 또는 None | 저자 후보 없음 |
| `extract_url` | HTML tree, default URL | str 또는 None | URL 후보 없음/invalid |
| `extract_license` | HTML tree | str 또는 None | license 후보 없음 |
플랫폼 적용:
- `title`, `author`, `date`, `sitename`, `url`, `description`, `tags`, `categories``SourceDocument` 메타로 저장한다.
- `url``date`는 provenance 및 temporal ontology 축의 핵심 속성으로 사용한다.
- `tags/categories`는 초기 후보 개념(seed concept)으로 사용할 수 있으나, 사이트별 노이즈가 많으므로 confidence를 낮게 둔다.
## 8. 다운로드 기능
파일: `trafilatura/downloads.py`
주요 API:
| 기능명 | 설명 |
|---|---|
| `fetch_url(url)` | HTML을 다운로드하고 decode한 문자열 반환 |
| `fetch_response(url, decode=False, with_headers=False)` | `Response` 객체 반환 |
| `buffered_downloads()` | URL buffer 병렬 다운로드 |
| `buffered_response_downloads()` | Response 객체 병렬 다운로드 |
| `is_live_page(url)` | URL 접근 가능성 확인 |
`Response` 필드:
- `data`: bytes
- `headers`: optional dict
- `html`: optional decoded string
- `status`: HTTP status
- `url`: 최종 URL
설정:
| 설정 | 기본값 | 설명 |
|---|---:|---|
| `DOWNLOAD_TIMEOUT` | 30 | 요청 timeout |
| `MAX_FILE_SIZE` | 20000000 | 최대 파일 크기 |
| `MIN_FILE_SIZE` | 10 | 최소 파일 크기 |
| `SLEEP_TIME` | 5.0 | 동일 host 요청 간격 |
| `MAX_REDIRECTS` | 2 | redirect 허용 횟수 |
| `USER_AGENTS` | empty | 사용자 user-agent 후보 |
| `COOKIE` | empty | 요청 cookie |
플랫폼 적용:
- 이미 프로젝트에 크롤러가 있다면 `fetch_url()`을 직접 대체하기보다 HTML 추출 단계에 Trafilatura를 붙이는 것이 안전하다.
- Trafilatura downloader를 쓰는 경우 도메인별 throttling과 robots 정책을 서비스 단에서 명시적으로 기록해야 한다.
- `fetch_response(decode=True, with_headers=True)`는 최종 URL, status, header provenance 저장에 적합하다.
## 9. 링크 발견 기능
### 9.1 Feed 발견
파일: `trafilatura/feeds.py`
주요 API:
```python
from trafilatura.feeds import find_feed_urls
urls = find_feed_urls("https://example.com", target_lang="ko")
```
지원:
- Atom
- RSS/RDF
- JSON Feed
- HTML 내 `<link rel="alternate">`
- HTML 내 feed 후보 `<a href>`
- Google News RSS fallback
- 언어 필터/도메인 유사도 필터
기능 명세:
| 기능명 | 입력 | 출력 | 정책 |
|---|---|---|---|
| `find_feed_urls` | URL, target_lang, external, sleep_time | 정렬/중복 제거 URL 목록 | 기본적으로 유사 도메인만 허용 |
| `determine_feed` | HTML 문자열 | feed URL 목록 | feed MIME/type/URL 패턴 사용 |
| `extract_links` | feed 문자열 | article URL 목록 | feedburner/feedproxy 예외 처리 |
### 9.2 Sitemap 발견
파일: `trafilatura/sitemaps.py`
주요 API:
```python
from trafilatura.sitemaps import sitemap_search
urls = sitemap_search("https://example.com", target_lang="ko")
```
지원:
- `robots.txt`의 Sitemap 항목
- 일반 sitemap guess: `sitemap.xml`, `sitemap.xml.gz`, `sitemap_index.xml`, `sitemap_news.xml`
- XML sitemap
- TXT sitemap
- hreflang 기반 target language
- nested sitemap
- URL filter
- 유사 도메인 필터
기능 명세:
| 기능명 | 입력 | 출력 | 제한 |
|---|---|---|---|
| `sitemap_search` | URL, target_lang, external, sleep_time, max_sitemaps | URL 목록 | 기본 최대 sitemap 10,000개 |
| `find_robots_sitemaps` | base URL | sitemap URL 목록 | robots.txt 10KB 초과 시 폐기 |
| `is_plausible_sitemap` | URL, contents | bool | HTML 응답이면 sitemap 아님 |
### 9.3 Focused crawler
파일: `trafilatura/spider.py`
주요 API:
```python
from trafilatura.spider import focused_crawler
todo, known = focused_crawler(
"https://example.com",
max_seen_urls=10,
max_known_urls=100000,
lang="ko",
)
```
특징:
- 시작 URL 기준 내부 링크 탐색
- robots.txt 파싱 및 `can_fetch("*", link)` 적용
- `Crawl-Delay` 반영
- navigation page 우선 탐색
- `todo`, `known_links`를 외부에서 주입해 단계별 crawl 가능
- 언어 필터 가능
주의:
- `URL_STORE`가 모듈 전역이다. 여러 crawl 작업을 동시에 실행하면 상태 충돌 위험이 있다.
- 플랫폼에서는 Trafilatura crawler를 그대로 병렬 호출하기보다, 작업별 프로세스 격리 또는 `courlan.UrlStore` 래핑이 필요하다.
## 10. 중복 제거와 fingerprint
파일: `trafilatura/deduplication.py`
기능:
- 세그먼트 중복 제거: `duplicate_test(element, options)`
- 문서 fingerprint: `content_fingerprint(content)`
- SimHash 비교: `Simhash.similarity()`
- 도메인 문자열 유사도: `is_similar_domain()`
- token sampling과 BLAKE2b hash
기능 명세:
| 기능명 | 입력 | 출력 | 용도 |
|---|---|---|---|
| `duplicate_test` | LXML element, Extractor/options | bool | 반복 boilerplate 제거 |
| `content_fingerprint` | 문자열 | hex SimHash | 문서 near-duplicate 키 |
| `Simhash.similarity` | 다른 Simhash | 0.0-1.0 | 유사 문서 판정 |
| `generate_bow_hash` | 문자열 | bytes | bag-of-words hash |
설정:
- `MIN_DUPLCHECK_SIZE = 100`
- `MAX_REPETITIONS = 2`
- 전역 LRU cache 크기: `LRU_SIZE = 4096`
플랫폼 적용:
- 추출 중 `deduplicate=True`는 페이지 내부 반복 요소 제거에 유용하다.
- 문서 단위 중복 제거는 `content_fingerprint(title + raw_text)`를 저장하고, 플랫폼 DB에서 유사도/중복 정책을 별도로 운영하는 것이 좋다.
- 전역 `LRU_TEST`는 긴 배치 작업에서 도메인 간 영향을 줄 수 있으므로 작업 단위로 `trafilatura.meta.reset_caches()` 호출을 고려한다.
## 11. HTML 처리와 구조 보존
파일: `trafilatura/htmlprocessing.py`, `trafilatura/main_extractor.py`, `trafilatura/xml.py`
보존 가능한 구조:
- 문단: `p`
- 제목: `head`
- 목록: `list`, `item`
- 인용: `quote`
- 코드: `code`
- 줄바꿈: `lb`
- 삭제/변경: `del`
- 강조/서식: `hi`
- 링크: `ref target="..."`
- 이미지: `graphic`
- 표: `table`, `row`, `cell`
온톨로지 플랫폼 관점에서는 `Document.body` XML tree가 중요하다.
활용 예:
- 제목/소제목을 문서 chunk hierarchy로 사용
- 목록 항목을 독립 주장 후보로 분해
- 표를 entity-attribute 후보로 변환
- 링크를 외부 참조 관계로 저장
- 이미지 alt/title을 보조 설명 텍스트로 저장
- 코드 블록은 일반 자연어 추출 대상에서 제외하거나 별도 타입으로 저장
## 12. 설정 명세
파일: `trafilatura/settings.cfg`
플랫폼 기본 권장값:
| 목적 | 설정/인자 | 권장 |
|---|---|---|
| 고품질 본문 추출 | `fast=False` | 기본 |
| 대량 수집 속도 | `fast=True` | 낮은 priority batch |
| 온톨로지 입력 | `output_format="python"` | 기본 |
| 구조 보존 | `include_formatting=True`, `include_links=True` | 권장 |
| 댓글 제외 | `include_comments=False` | 기본 권장 |
| 표 포함 | `include_tables=True` | 권장 |
| 이미지 후보 | `include_images=True` | 필요 시 |
| 언어 필터 | `target_language="ko"` 등 | 소스 도메인별 설정 |
| URL blacklisting | `url_blacklist` | 플랫폼 정책 DB와 연동 |
| 저자 제외 | `author_blacklist` | “편집부”, “관리자” 등 제거 |
| 날짜 strictness | `date_extraction_params` | max_date 고정 |
`settings.cfg`에서 조정할 값:
| 키 | 의미 |
|---|---|
| `DOWNLOAD_TIMEOUT` | 다운로드 제한 시간 |
| `MAX_FILE_SIZE` | 입력 최대 크기 |
| `MIN_FILE_SIZE` | 입력 최소 크기 |
| `SLEEP_TIME` | 동일 도메인 요청 간격 |
| `MAX_REDIRECTS` | redirect 횟수 |
| `MIN_EXTRACTED_SIZE` | fallback 발동 기준 본문 길이 |
| `MIN_OUTPUT_SIZE` | 최종 본문 최소 길이 |
| `EXTRACTION_TIMEOUT` | CLI 추출 timeout |
| `MIN_DUPLCHECK_SIZE` | 중복 검사 최소 길이 |
| `MAX_REPETITIONS` | 허용 반복 횟수 |
| `EXTENSIVE_DATE_SEARCH` | 날짜 탐색 범위 |
| `EXTERNAL_URLS` | feed/sitemap 외부 URL 허용 |
## 13. 범용 온톨로지 구축 플랫폼 통합 설계
### 13.1 권장 파이프라인
```text
Seed URL
-> Feed/Sitemap/Crawler URL discovery
-> URL normalization/dedup
-> Download raw HTML
-> Trafilatura bare_extraction
-> Document metadata/provenance 저장
-> 구조 유지 chunking
-> 언어/품질/중복 필터
-> 엔티티/관계/속성 후보 추출
-> ontology schema mapping
-> graph/vector/document store 적재
```
### 13.2 Trafilatura 채택 범위
거의 그대로 사용 권장:
- `core.py``extract`, `bare_extraction`, `extract_with_metadata`
- `metadata.py`의 메타데이터 추출
- `downloads.py`의 단일 다운로드 및 Response 모델
- `feeds.py`의 feed discovery
- `sitemaps.py`의 sitemap discovery
- `deduplication.py``content_fingerprint`, `Simhash`
- `xml.py`의 출력 변환
- `settings.py``Extractor`, `Document`
래퍼 필요:
- `spider.py`: 전역 `URL_STORE` 때문에 작업별 격리 필요
- `downloads.py`: 전역 HTTP pool과 user-agent/cookie 정책 관리 필요
- `deduplication.py`: 전역 LRU cache 초기화 정책 필요
- CLI 계층: 플랫폼 내부에서는 직접 CLI보다 Python API 사용 권장
수정 또는 확장 후보:
- 한국어/다국어 품질 점수 산정
- ontology chunk id/provenance 부여
- 표를 relation candidate로 변환하는 후처리
- link target을 source graph edge로 변환
- source별 extraction profile 관리
- 실패 사유와 추출 품질 metrics 기록
### 13.3 플랫폼 내 모듈 제안
| 플랫폼 모듈 | Trafilatura 연결 |
|---|---|
| `SourceDiscoveryService` | `find_feed_urls`, `sitemap_search`, `focused_crawler` |
| `PageFetchService` | `fetch_response` |
| `ContentExtractionService` | `bare_extraction` |
| `MetadataNormalizer` | `Document` 필드 정규화 |
| `DocumentChunker` | `Document.body` XML tree 기반 |
| `QualityScorer` | 본문 길이, 언어, 메타 completeness, 중복 여부 |
| `ProvenanceStore` | URL, hostname, date, fingerprint, raw HTML path |
| `OntologyCandidateBuilder` | title/head/list/table/ref/tag 기반 candidate 생성 |
## 14. 정확한 기능 명세
### F-001 웹 페이지 다운로드
- 입력: URL, SSL 옵션, config/options
- 처리: HTTP GET, redirect 제한, timeout, 크기 제한, charset decode
- 출력: HTML 문자열 또는 `Response`
- 예외/실패: non-200, 크기 미달/초과, SSL/네트워크 오류
- 수용 기준: 성공 시 최종 URL과 status를 기록할 수 있어야 한다.
### F-002 HTML 파싱
- 입력: HTML string/bytes/LXML element
- 처리: 압축 파일 처리, encoding detect, faulty HTML repair, LXML tree 생성
- 출력: `HtmlElement`
- 실패: 빈 입력, 파싱 불가
- 수용 기준: 문자열과 이미 파싱된 LXML tree 모두 동일 추출 파이프라인에 들어갈 수 있어야 한다.
### F-003 본문 추출
- 입력: HTML tree, `Extractor`
- 처리: cleanup, tag conversion, main extractor, fallback 비교, baseline rescue
- 출력: `Document.body`, `Document.text`, `Document.raw_text`
- 실패: 본문 최소 길이 미달, 언어 불일치, 중복 폐기
- 수용 기준: `favor_precision`, `favor_recall`, `fast` 옵션에 따라 결과가 조정되어야 한다.
### F-004 댓글 추출
- 입력: HTML tree, `include_comments`
- 처리: 댓글 XPath 후보 추출 후 본문 tree에서 제거
- 출력: `Document.comments`, `Document.commentsbody`
- 실패: 댓글 길이 미달이면 빈 댓글로 처리
- 수용 기준: 댓글 포함 여부를 소스/도메인별로 설정할 수 있어야 한다.
### F-005 표 추출
- 입력: HTML `<table>`, `include_tables`
- 처리: row/cell 구조 변환, header cell role 지정, colspan span 계산
- 출력: XML tree의 `table/row/cell`
- 실패: table 옵션 off이면 제외
- 수용 기준: ontology relation 후보 생성 단계에서 행/열 구조를 읽을 수 있어야 한다.
### F-006 링크/이미지 보존
- 입력: HTML anchor/img, base URL
- 처리: 상대 URL 절대화, 내부 `ref`/`graphic` 태그 변환
- 출력: XML tree 내 `target`, image attribute
- 실패: 옵션 off이면 텍스트만 남거나 제거
- 수용 기준: source graph edge와 media evidence로 저장 가능해야 한다.
### F-007 메타데이터 추출
- 입력: HTML tree, 입력 URL, date params, blacklist
- 처리: OpenGraph, Twitter, meta, JSON-LD, canonical, heading, htmldate
- 출력: `Document` metadata fields
- 실패: 후보 없음 시 None
- 수용 기준: `only_with_metadata=True`에서 `date/title/url` 필수 조건을 적용해야 한다.
### F-008 언어 필터
- 입력: HTML lang 또는 추출 텍스트, target language
- 처리: HTML lang quick check 또는 `py3langid` 판별
- 출력: pass/fail, `Document.language`
- 실패: target 불일치 시 문서 폐기
- 수용 기준: 언어 판별 패키지가 없을 때는 HTML lang 기반 검사로 degrade해야 한다.
### F-009 Feed URL 발견
- 입력: 홈페이지/feed URL, target_lang, external
- 처리: feed 직접 파싱, HTML feed link discovery, Google News fallback
- 출력: 기사 URL 목록
- 실패: 다운로드 실패, feed 없음
- 수용 기준: 중복 제거와 도메인 유사도 필터가 적용되어야 한다.
### F-010 Sitemap URL 발견
- 입력: 홈페이지/sitemap URL, target_lang, external, max_sitemaps
- 처리: robots.txt sitemap, sitemap guess, nested sitemap, XML/TXT parsing, hreflang
- 출력: 페이지 URL 목록
- 실패: base URL unreachable, invalid sitemap
- 수용 기준: sitemap index가 깊어도 `max_sitemaps` 제한을 지켜야 한다.
### F-011 Focused crawling
- 입력: homepage, max_seen_urls, max_known_urls, todo, known_links, lang
- 처리: robots.txt, crawl delay, navigation URL 우선순위, URL store update
- 출력: 다음 방문 URL 목록, 알려진 URL 목록
- 실패: 시작 URL invalid, frontier 고갈
- 수용 기준: 작업 재개를 위해 `todo`, `known_links`를 저장/재주입할 수 있어야 한다.
### F-012 중복 제거
- 입력: XML element 또는 문서 텍스트
- 처리: LRU exact segment count, SimHash fingerprint
- 출력: duplicate bool 또는 fingerprint
- 실패: 짧은 텍스트는 중복 검사 bypass
- 수용 기준: 문서 fingerprint가 DB unique/near-duplicate 정책과 연결되어야 한다.
### F-013 출력 변환
- 입력: `Document`, `Extractor.format`
- 처리: XML cleanup, JSON/CSV/HTML/TXT/Markdown/XML/TEI 변환
- 출력: 문자열
- 실패: unsupported format이면 AttributeError/ValueError
- 수용 기준: 동일 문서에서 최소 TXT, JSON, XML 출력을 생성할 수 있어야 한다.
### F-014 설정 관리
- 입력: `settings.cfg`, `Extractor`, 함수 인자
- 처리: config parse, 옵션 병합
- 출력: 실행 시 옵션 객체
- 실패: config 파일 없음, 필수 key 없음
- 수용 기준: 플랫폼 source profile에서 추출 설정을 생성할 수 있어야 한다.
### F-015 cache reset
- 입력: 없음
- 처리: module-level cache clear
- 출력: 없음
- 실패: 없음
- 수용 기준: 장시간 batch 또는 tenant 전환 시 cache를 초기화할 수 있어야 한다.
## 15. 품질 및 테스트 자산
테스트 구성:
- `tests/unit_tests.py`: 기본 추출/유틸 단위 테스트
- `tests/metadata_tests.py`: 메타데이터 추출
- `tests/json_metadata_tests.py`: JSON-LD 메타
- `tests/downloads_tests.py`: 다운로드
- `tests/feeds_tests.py`: feed
- `tests/sitemaps_tests.py`: sitemap
- `tests/spider_tests.py`: crawler
- `tests/deduplication_tests.py`: 중복 제거
- `tests/xml_tei_tests.py`: XML/TEI
- `tests/eval/`, `tests/cache/`: 실제 웹 페이지 평가 corpus
플랫폼 통합 테스트로 추가해야 할 것:
- 한국어 뉴스/블로그/쇼핑/위키/공공기관 샘플
- JS-heavy 사이트에서 raw HTML 한계 확인
- HTML table -> relation candidate 변환 테스트
- `bare_extraction` 결과의 provenance field completeness 테스트
- 동일 URL/동일 본문/near duplicate 처리 테스트
- source profile별 precision/recall 옵션 비교 테스트
## 16. 위험 요소와 대응
| 위험 | 설명 | 대응 |
|---|---|---|
| JS 렌더링 미지원 | 정적 HTML 기반 추출 | Playwright/Crawl4AI 등으로 렌더링 후 HTML을 Trafilatura에 입력 |
| 전역 상태 | HTTP pool, URL_STORE, LRU cache | 작업 단위 프로세스 격리 또는 reset |
| 사이트별 메타 노이즈 | tags/category/author가 부정확할 수 있음 | confidence와 source별 rule 적용 |
| 언어 판별 선택 의존성 | `py3langid` 없으면 제한적 | optional dependency 설치 또는 별도 언어 판별기 연결 |
| 표/이미지 실험적 옵션 | 모든 출력 형식에서 완전 보존되지 않음 | `output_format="python"` 또는 XML tree 직접 사용 |
| robots/정책 준수 | downloader 직접 사용 시 정책 책임 필요 | 플랫폼 crawler policy layer에서 관리 |
| 날짜 추출 recall/precision | `EXTENSIVE_DATE_SEARCH`에 따라 오탐 가능 | source별 date extraction profile 운영 |
## 17. 구현 권장 래퍼 인터페이스
```python
from dataclasses import dataclass
from typing import Optional
from trafilatura import bare_extraction
from trafilatura.settings import Extractor
@dataclass
class ExtractedWebDocument:
url: str
title: Optional[str]
author: Optional[str]
date: Optional[str]
sitename: Optional[str]
description: Optional[str]
text: str
body_xml: object
metadata: dict
fingerprint: Optional[str]
def extract_for_ontology(html: str, url: str, lang: Optional[str] = None) -> Optional[ExtractedWebDocument]:
options = Extractor(
output_format="python",
url=url,
with_metadata=True,
comments=False,
tables=True,
formatting=True,
links=True,
images=True,
dedup=True,
lang=lang,
)
doc = bare_extraction(html, options=options)
if not doc or not doc.text:
return None
return ExtractedWebDocument(
url=doc.url or url,
title=doc.title,
author=doc.author,
date=doc.date,
sitename=doc.sitename,
description=doc.description,
text=doc.text,
body_xml=doc.body,
metadata=doc.as_dict(),
fingerprint=doc.fingerprint,
)
```
## 18. 채택 우선순위
1. `bare_extraction()` 기반 ContentExtractionService 구현
2. `Document` metadata를 프로젝트 DB schema에 매핑
3. `Document.body` XML tree 기반 chunker 구현
4. `content_fingerprint()` 기반 중복 문서 정책 추가
5. `sitemap_search()``find_feed_urls()`를 source discovery에 연결
6. 필요한 경우 `focused_crawler()`는 전역 상태 격리 후 채택
7. JS rendering 결과 HTML을 Trafilatura에 넣는 hybrid extractor 구성
## 19. 최종 판단
Trafilatura는 범용 온톨로지 구축 플랫폼에서 “웹 문서를 ontology-ready document로 정제하는 핵심 엔진”으로 채택할 가치가 높다. 본문 추출 알고리즘, 메타데이터 추출, 링크 발견, 중복 제거, 구조 출력이 이미 모듈화되어 있으며 Apache-2.0 라이선스라 기본 소스 활용에도 적합하다.
가장 좋은 통합 방향은 원본 코드를 크게 변형하지 않고, 플랫폼 내부에 얇은 adapter layer를 두는 것이다. Adapter layer는 source profile, 작업 격리, provenance 저장, 품질 점수, 온톨로지 후보 생성만 담당하고 Trafilatura의 본문/메타/URL 발견 로직은 원형에 가깝게 유지하는 편이 안정적이다.