750 lines
29 KiB
Markdown
750 lines
29 KiB
Markdown
# 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 발견 로직은 원형에 가깝게 유지하는 편이 안정적이다.
|