ontology
This commit is contained in:
892
오픈소스분석자료/Firecrawl_분석_및_기능명세.md
Normal file
892
오픈소스분석자료/Firecrawl_분석_및_기능명세.md
Normal file
@@ -0,0 +1,892 @@
|
||||
# Firecrawl 프로젝트 분석 및 기능명세
|
||||
|
||||
분석 대상: `C:\Users\lasta\MyProject\AI\참고\firecrawl-main`
|
||||
분석일: 2026-05-13
|
||||
목적: 범용 온톨로지 구축 플랫폼의 웹 수집/정제/구조화 기반 소스로 Firecrawl을 거의 원형에 가깝게 재사용할 수 있는지 판단하고, 향후 구현 기준이 될 기능 명세를 정리한다.
|
||||
|
||||
## 1. 결론 요약
|
||||
|
||||
Firecrawl은 단순 크롤러가 아니라 `검색 -> URL 발견 -> 페이지 수집 -> 동적 브라우저 실행 -> Markdown/HTML/JSON/스크린샷/파일 파싱 -> 비동기 작업 관리 -> SDK 제공`까지 포함하는 웹 데이터 수집 API 플랫폼이다. 현재 프로젝트의 범용 온톨로지 구축 플랫폼에는 다음 영역이 특히 직접 재사용 가치가 높다.
|
||||
|
||||
- `apps/api/src/scraper/scrapeURL`: 단일 URL 수집의 핵심. Fetch, Playwright, PDF, 문서, 인덱스, Fire-engine 계열 엔진을 fallback 방식으로 선택한다.
|
||||
- `apps/api/src/scraper/WebScraper/crawler.ts`: 사이트 내부 URL 탐색, sitemap, robots.txt, include/exclude path, depth, subdomain/external link 제어.
|
||||
- `apps/api/src/controllers/v2/types.ts`: API 입력/출력 스키마. 특히 scrape/crawl/map/search 옵션 체계가 잘 정리되어 있다.
|
||||
- `apps/api/src/controllers/v2/*`: 외부 API 기능 명세의 실제 기준. `scrape`, `crawl`, `map`, `search`, `batch scrape`, `parse`, `monitor`, `browser`, `agent`로 분리되어 있다.
|
||||
- `apps/api/src/services/worker/scrape-worker.ts`, `queue-*`: 대량 수집, 크롤 작업, billing/logging/webhook/상태 관리의 운영 흐름.
|
||||
- `apps/python-sdk`, `apps/js-sdk/firecrawl`: 우리 플랫폼 API 클라이언트 설계 시 참고할 수 있는 SDK 표면.
|
||||
|
||||
다만 Firecrawl은 Node.js/TypeScript 기반의 API 서버, Redis/BullMQ 또는 NuQ/RabbitMQ/Postgres, Playwright microservice, Supabase/Autumn/Stripe/GCS/Sentry 등 SaaS 운영 요소가 섞여 있다. 현재 Python/FastAPI/SQLAlchemy 기반 프로젝트에 그대로 병합하기보다는, Firecrawl을 별도 수집 서비스로 두고 Python 온톨로지 파이프라인이 Firecrawl API를 호출하는 구조가 가장 안전하다.
|
||||
|
||||
## 2. 프로젝트 성격
|
||||
|
||||
Firecrawl의 제품 목표는 웹 페이지를 LLM/RAG/Agent가 바로 사용할 수 있는 깨끗한 데이터로 변환하는 것이다. 제공 기능은 다음 세 가지 축으로 요약된다.
|
||||
|
||||
- 단일 페이지 변환: URL을 Markdown, HTML, raw HTML, link/image 목록, screenshot, structured JSON 등으로 변환한다.
|
||||
- 사이트 단위 수집: seed URL에서 sitemap과 링크 그래프를 따라가며 여러 페이지를 비동기로 수집한다.
|
||||
- 지능형 데이터 추출: JSON Schema, LLM prompt, browser action, search result scraping, file parsing을 결합한다.
|
||||
|
||||
온톨로지 구축 플랫폼 관점에서는 Firecrawl이 `웹 수집 계층`과 `텍스트/문서 정제 계층`을 맡고, 현재 프로젝트의 Python 코드는 `도메인 어댑터`, `엔티티/관계 추출`, `Claim/Evidence 저장`, `추천/검증 UI`를 맡는 분업이 적합하다.
|
||||
|
||||
## 3. 최상위 구조
|
||||
|
||||
```text
|
||||
firecrawl-main/
|
||||
apps/
|
||||
api/ # 핵심 API 서버, 스크래퍼, 크롤러, 큐/워커
|
||||
playwright-service-ts/ # Playwright 브라우저 마이크로서비스
|
||||
python-sdk/ # Python SDK
|
||||
js-sdk/firecrawl/ # JS/TS SDK
|
||||
php-sdk, ruby-sdk,
|
||||
rust-sdk, elixir-sdk # 다언어 SDK
|
||||
ui/ingestion-ui/ # ingestion UI
|
||||
test-suite/ # API/load 테스트
|
||||
test-site/ # 테스트용 사이트
|
||||
go-html-to-md-service/ # HTML -> Markdown 변환 보조 서비스
|
||||
nuq-postgres/ # NuQ 큐용 Postgres 구성
|
||||
examples/ # LLM/agent/추출 예제 다수
|
||||
docker-compose.yaml # self-host 전체 구성
|
||||
SELF_HOST.md # 자체 호스팅 안내
|
||||
README.md # 제품/SDK/API 개요
|
||||
```
|
||||
|
||||
핵심은 `apps/api`이다. 나머지는 SDK, 배포, 예제, 테스트, UI 보조 레이어다.
|
||||
|
||||
## 4. 기술 스택
|
||||
|
||||
- 언어: TypeScript/Node.js, 일부 Rust native package, 일부 Go service
|
||||
- API: Express, express-ws, Zod validation, multer multipart
|
||||
- 브라우저: 별도 `playwright-service-ts`, Fire-engine CDP/TLS client 연동 가능
|
||||
- HTML 처리: Cheerio, JSDOM, Turndown, joplin-turndown-plugin-gfm, Rust 기반 link filtering/extraction
|
||||
- 문서 처리: PDF, DOC/DOCX/ODT/RTF/XLS/XLSX 계열 파일 처리 모듈
|
||||
- 큐/상태: BullMQ, Redis, NuQ, RabbitMQ, Postgres
|
||||
- 검색: Google 기본, SearXNG 대체, DuckDuckGo/v2 검색 코드
|
||||
- LLM: OpenAI, Anthropic, Google, Groq, xAI, OpenRouter, Ollama/OpenAI-compatible
|
||||
- 운영: Docker Compose, Kubernetes/Helm 예제, Sentry, Prometheus, logging, billing
|
||||
|
||||
## 5. 런타임 아키텍처
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Client / SDK / API"] --> B["Express v2 Router"]
|
||||
B --> C["Auth / rate limit / credit / blocklist"]
|
||||
C --> D{"Endpoint"}
|
||||
D --> E["Scrape Controller"]
|
||||
D --> F["Crawl Controller"]
|
||||
D --> G["Map Controller"]
|
||||
D --> H["Search Controller"]
|
||||
E --> I["scrapeURL engine fallback"]
|
||||
F --> J["WebCrawler URL discovery"]
|
||||
J --> K["Queue scrape jobs"]
|
||||
G --> J
|
||||
H --> L["Search provider"]
|
||||
H --> I
|
||||
K --> M["Scrape Worker"]
|
||||
M --> I
|
||||
I --> N["Fetch / Playwright / PDF / Document / Index / Fire-engine"]
|
||||
N --> O["Markdown / metadata / formats / actions"]
|
||||
O --> P["Result / status / webhook / logs"]
|
||||
```
|
||||
|
||||
### 핵심 흐름
|
||||
|
||||
1. API 요청은 `apps/api/src/routes/v2.ts`에서 endpoint별 controller로 라우팅된다.
|
||||
2. Zod 스키마가 URL, 옵션, format, crawler option을 strict하게 검증한다.
|
||||
3. 단일 scrape는 동기적으로 처리하되 내부적으로 semaphore와 worker 공통 함수를 사용한다.
|
||||
4. crawl/batch scrape는 작업 ID를 반환하고 큐에 개별 scrape job을 넣는다.
|
||||
5. worker는 URL별로 `scrapeURL`을 실행하고 성공/실패/robots 차단/비용/로그/웹훅을 기록한다.
|
||||
6. 결과는 status endpoint, websocket, webhook, SDK polling을 통해 조회된다.
|
||||
|
||||
## 6. 핵심 모듈 분석
|
||||
|
||||
### 6.1 API 라우터
|
||||
|
||||
파일: `apps/api/src/routes/v2.ts`
|
||||
|
||||
주요 endpoint:
|
||||
|
||||
- `POST /v2/search`
|
||||
- `POST /v2/parse`
|
||||
- `POST /v2/scrape`
|
||||
- `GET /v2/scrape/:jobId`
|
||||
- `POST /v2/scrape/:jobId/interact`
|
||||
- `DELETE /v2/scrape/:jobId/interact`
|
||||
- `POST /v2/batch/scrape`
|
||||
- `GET /v2/batch/scrape/:jobId`
|
||||
- `DELETE /v2/batch/scrape/:jobId`
|
||||
- `GET /v2/batch/scrape/:jobId/errors`
|
||||
- `POST /v2/map`
|
||||
- `POST /v2/crawl`
|
||||
- `POST /v2/crawl/params-preview`
|
||||
- `GET /v2/crawl/ongoing`
|
||||
- `GET /v2/crawl/:jobId`
|
||||
- `DELETE /v2/crawl/:jobId`
|
||||
- `WS /v2/crawl/:jobId`
|
||||
- `GET /v2/crawl/:jobId/errors`
|
||||
- `POST /v2/extract`
|
||||
- `GET /v2/extract/:jobId`
|
||||
- `POST /v2/agent`
|
||||
- `GET /v2/agent/:jobId`
|
||||
- `DELETE /v2/agent/:jobId`
|
||||
- `POST /v2/monitor`
|
||||
- `GET /v2/monitor`
|
||||
- `GET /v2/monitor/:monitorId`
|
||||
- `PATCH /v2/monitor/:monitorId`
|
||||
- `DELETE /v2/monitor/:monitorId`
|
||||
- `POST /v2/monitor/:monitorId/run`
|
||||
- `GET /v2/monitor/:monitorId/checks`
|
||||
- `GET /v2/monitor/:monitorId/checks/:checkId`
|
||||
- `POST /v2/browser`
|
||||
- `GET /v2/browser`
|
||||
- `POST /v2/browser/:sessionId/execute`
|
||||
- `DELETE /v2/browser/:sessionId`
|
||||
- `GET /v2/team/credit-usage`
|
||||
- `GET /v2/team/token-usage`
|
||||
- `GET /v2/concurrency-check`
|
||||
- `GET /v2/team/queue-status`
|
||||
- `GET /v2/team/activity`
|
||||
|
||||
우리 프로젝트에서 우선 필요한 것은 `scrape`, `crawl`, `map`, `batch scrape`, `parse`, `search`다. `billing`, `credit`, `team`, `x402`, `agent signup`, `support proxy`는 초기에는 제외 가능하다.
|
||||
|
||||
### 6.2 스키마와 옵션 체계
|
||||
|
||||
파일: `apps/api/src/controllers/v2/types.ts`
|
||||
|
||||
Firecrawl은 입력 옵션을 Zod로 strict validation한다. 알 수 없는 key는 거부하는 방식이라 API 안정성이 높다.
|
||||
|
||||
#### 공통 Scrape 옵션
|
||||
|
||||
- `formats`: 기본 `markdown`. 지원 format은 `markdown`, `html`, `rawHtml`, `links`, `images`, `summary`, `json`, `changeTracking`, `screenshot`, `attributes`, `branding`, `question`, `highlights`, `query`, `audio`.
|
||||
- `headers`: 요청 header.
|
||||
- `includeTags`, `excludeTags`: 특정 selector 포함/제외. iframe selector 변환도 처리한다.
|
||||
- `onlyMainContent`: 기본 true. 본문 중심 추출.
|
||||
- `onlyCleanContent`: 기본 false.
|
||||
- `timeout`: 최소 1000ms.
|
||||
- `waitFor`: 기본 0, 최대 60000ms, timeout의 절반 이하.
|
||||
- `mobile`: 모바일 viewport 사용.
|
||||
- `parsers`: PDF/문서 parser 옵션.
|
||||
- `actions`: wait/click/write/press/scroll/scrape/screenshot 등 브라우저 액션.
|
||||
- `location`: country/languages. 기본 country는 `us-generic`.
|
||||
- `skipTlsVerification`: TLS 검증 skip.
|
||||
- `removeBase64Images`: 기본 true.
|
||||
- `fastMode`: 빠른 수집 모드.
|
||||
- `blockAds`: 기본 true.
|
||||
- `proxy`: `basic`, `stealth`, `enhanced`, `auto`. 기본 `auto`.
|
||||
- `maxAge`, `minAge`, `storeInCache`: 캐시 사용 기준.
|
||||
- `lockdown`: 캐시/index 기반 제한 모드.
|
||||
- `profile`: 브라우저 profile 이름과 저장 여부.
|
||||
|
||||
중요 transform:
|
||||
|
||||
- JSON format이 있고 기본 timeout 30000ms이면 60000ms로 늘린다.
|
||||
- stealth/enhanced/auto proxy이며 기본 timeout이면 120000ms로 늘린다.
|
||||
- changeTracking은 markdown format을 요구하고 waitFor/timeout을 늘린다.
|
||||
- actions + waitFor 총 대기 시간은 60초를 넘지 못한다.
|
||||
|
||||
#### Crawler 옵션
|
||||
|
||||
- `includePaths`: 포함할 path regex.
|
||||
- `excludePaths`: 제외할 path regex.
|
||||
- `maxDiscoveryDepth`: 발견 깊이 제한.
|
||||
- `limit`: 기본 10000.
|
||||
- `crawlEntireDomain`: 전체 domain 허용.
|
||||
- `allowExternalLinks`: 기본 false.
|
||||
- `allowSubdomains`: 기본 false.
|
||||
- `ignoreRobotsTxt`: 기본 false.
|
||||
- `robotsUserAgent`: robots.txt 확인 user-agent.
|
||||
- `sitemap`: `skip`, `include`, `only`. 기본 `include`.
|
||||
- `deduplicateSimilarURLs`: 기본 true.
|
||||
- `ignoreQueryParameters`: 기본 false.
|
||||
- `regexOnFullURL`: 기본 false.
|
||||
- `delay`: URL 간 delay.
|
||||
|
||||
#### Map 옵션
|
||||
|
||||
Map은 URL 목록 발견용이다. 기본 `includeSubdomains=true`, `ignoreQueryParameters=true`, `limit=5000`, 최대 `100000`이다. `search`, `sitemap`, `filterByPath`, `useIndex`, `ignoreCache`, `location`, `headers`를 지원한다.
|
||||
|
||||
#### Search 옵션
|
||||
|
||||
- `query`: 검색어.
|
||||
- `limit`: 기본 10, 최대 100.
|
||||
- `sources`: `web`, `images`, `news`.
|
||||
- `categories`: `github`, `research`, `pdf`.
|
||||
- `includeDomains`, `excludeDomains`: 동시에 지정 불가.
|
||||
- `lang`: 기본 en.
|
||||
- `country`/`location`.
|
||||
- `timeout`: 기본 60000ms.
|
||||
- `asyncScraping`: 검색 결과 scraping을 비동기 job으로 반환 가능.
|
||||
- `scrapeOptions`: 검색 결과 페이지를 바로 scrape할 때 사용하는 제한된 scrape 옵션.
|
||||
|
||||
### 6.3 단일 URL 수집 엔진
|
||||
|
||||
파일: `apps/api/src/scraper/scrapeURL/index.ts`, `apps/api/src/scraper/scrapeURL/engines/index.ts`
|
||||
|
||||
Firecrawl의 핵심은 URL과 요청 feature를 보고 엔진 후보를 만든 뒤 fallback 순서로 시도하는 구조다.
|
||||
|
||||
지원 엔진:
|
||||
|
||||
- `index`: 기존 index/cache에서 문서 조회.
|
||||
- `index;documents`: 문서 index 조회.
|
||||
- `fire-engine;chrome-cdp`: 고급 브라우저 엔진.
|
||||
- `fire-engine;chrome-cdp;stealth`: stealth proxy 브라우저 엔진.
|
||||
- `fire-engine;tlsclient`: TLS client 기반 수집.
|
||||
- `fire-engine;tlsclient;stealth`: stealth TLS client.
|
||||
- `playwright`: 자체 Playwright microservice.
|
||||
- `fetch`: HTTP fetch 기반 빠른 수집.
|
||||
- `pdf`: PDF 전용 처리.
|
||||
- `document`: DOCX/ODT/RTF/XLS/XLSX 등 문서 처리.
|
||||
- `wikipedia`: Wikimedia 전용 엔진.
|
||||
- `x-twitter`: X/Twitter 전용 엔진.
|
||||
|
||||
Feature flag:
|
||||
|
||||
- `actions`, `waitFor`, `screenshot`, `screenshot@fullScreen`, `pdf`, `document`, `audio`, `atsv`, `location`, `mobile`, `skipTlsVerification`, `useFastMode`, `stealthProxy`, `branding`, `disableAdblock`.
|
||||
|
||||
선택 방식:
|
||||
|
||||
1. URL 확장자, option, format을 보고 필요한 feature flag를 계산한다.
|
||||
2. 각 엔진이 feature를 지원하는지 확인한다.
|
||||
3. quality와 feature priority를 기준으로 fallback list를 만든다.
|
||||
4. 엔진별 max reasonable time을 계산하고 timeout/abort manager와 함께 실행한다.
|
||||
5. HTML을 Markdown으로 변환하고 metadata, links, images, screenshot, extract 결과 등을 조립한다.
|
||||
6. 실패 시 `NoEnginesLeftError`, `DNSResolutionError`, `SSLError`, `PDFOCRRequiredError`, `ActionError`, `CrawlDenialError` 등 typed error로 전달한다.
|
||||
|
||||
온톨로지 플랫폼에는 이 구조가 매우 유용하다. 특정 쇼핑몰/공식몰/문서/PDF마다 직접 fetcher를 분기하지 않고, Firecrawl이 feature 기반 fallback을 담당하게 할 수 있다.
|
||||
|
||||
### 6.4 URL 발견과 사이트 크롤링
|
||||
|
||||
파일: `apps/api/src/scraper/WebScraper/crawler.ts`
|
||||
|
||||
`WebCrawler`는 seed URL에서 사이트 내부 링크를 발견하고 filtering한다.
|
||||
|
||||
주요 기능:
|
||||
|
||||
- sitemap 로드와 sitemap 링크 제한.
|
||||
- robots.txt 로드와 robots parser.
|
||||
- max depth, max discovery depth 적용.
|
||||
- include/exclude regex path filtering.
|
||||
- backward crawling 차단.
|
||||
- external link/subdomain 허용 여부 판단.
|
||||
- query parameter 무시/중복 제거.
|
||||
- 비웹 프로토콜, social/mailto, section anchor, 비문서 file type 제거.
|
||||
- URL별 denial reason 생성.
|
||||
|
||||
현재 프로젝트의 `crawler_platform.app.core.crawler.discovery`, `site_crawler`, `content_zone`, `fetchers`를 Firecrawl 방식으로 강화할 수 있다. 단, Python 코드에 직접 포팅하기보다는 `POST /v2/map` 또는 `POST /v2/crawl`을 호출해 URL discovery를 위임하는 것이 빠르다.
|
||||
|
||||
### 6.5 Crawl 작업 처리
|
||||
|
||||
파일: `apps/api/src/controllers/v2/crawl.ts`, `apps/api/src/services/worker/scrape-worker.ts`
|
||||
|
||||
Crawl은 단일 요청에서 모든 페이지를 즉시 반환하지 않는다.
|
||||
|
||||
처리 절차:
|
||||
|
||||
1. `crawlRequestSchema`로 URL, crawler option, scrape option 검증.
|
||||
2. 자연어 `prompt`가 있으면 site structure를 일부 map한 뒤 LLM으로 crawler option 생성.
|
||||
3. include/exclude regex 유효성 확인.
|
||||
4. credit 또는 self-host 설정에 따라 limit 조정.
|
||||
5. Redis/queue에 `StoredCrawl` 저장.
|
||||
6. kickoff job을 큐에 넣고 `id`, status URL을 반환.
|
||||
7. worker가 URL을 발견하고 개별 scrape job으로 확장한다.
|
||||
8. `GET /v2/crawl/:jobId` 또는 websocket으로 진행률과 결과를 조회한다.
|
||||
|
||||
응답 status:
|
||||
|
||||
- `scraping`
|
||||
- `completed`
|
||||
- `failed`
|
||||
- `cancelled`
|
||||
|
||||
status 응답은 `completed`, `total`, `creditsUsed`, `expiresAt`, `next`, `data: Document[]`를 포함한다.
|
||||
|
||||
### 6.6 Search
|
||||
|
||||
파일: `apps/api/src/controllers/v2/search.ts`, `apps/api/src/search/*`
|
||||
|
||||
Search는 검색 결과를 반환하고, 옵션에 따라 각 결과 페이지를 scrape해서 markdown까지 포함한다.
|
||||
|
||||
온톨로지 플랫폼 활용:
|
||||
|
||||
- 브랜드/상품/성분/카테고리 후보 URL 발견.
|
||||
- 공식 문서, PDF, research 자료 검색.
|
||||
- seed URL이 부족한 신규 도메인 bootstrap.
|
||||
- `includeDomains`/`excludeDomains`로 신뢰 출처 제한.
|
||||
|
||||
초기 MVP에서는 외부 검색 품질보다 `검색 결과 -> 후보 Source/Page -> 검토 큐` 흐름을 만드는 것이 중요하다.
|
||||
|
||||
### 6.7 Parse
|
||||
|
||||
`POST /v2/parse`는 multipart file upload를 받아 HTML/PDF/document를 scrape-like document로 변환한다. 파일 크기 제한은 50MB다.
|
||||
|
||||
온톨로지 플랫폼 활용:
|
||||
|
||||
- 로컬 PDF catalog, 제품 설명서, 성분표 문서 ingest.
|
||||
- HTML fixture나 저장된 페이지 snapshot ingest.
|
||||
- URL이 아닌 파일 기반 evidence 확보.
|
||||
|
||||
### 6.8 Browser / Interact / Actions
|
||||
|
||||
Firecrawl은 두 종류의 상호작용을 제공한다.
|
||||
|
||||
- scrape request의 `actions`: scrape 전에 wait, click, write, press, scroll, screenshot, scrape 등을 수행한다.
|
||||
- `POST /v2/scrape/:jobId/interact`: scrape job에 연결된 browser session에 code 또는 prompt 기반 조작을 수행한다.
|
||||
|
||||
온톨로지 플랫폼 활용:
|
||||
|
||||
- 쿠키 배너 닫기.
|
||||
- 검색/필터/더보기 버튼 클릭.
|
||||
- pagination 또는 lazy-loaded product list 수집.
|
||||
- 특정 selector 대기 후 수집.
|
||||
|
||||
주의: action 기반 수집은 재현성과 비용이 낮아질 수 있으므로, Source 단위 설정으로 제한하고 audit log를 남기는 것이 좋다.
|
||||
|
||||
### 6.9 Monitor
|
||||
|
||||
Monitor는 특정 URL/옵션을 주기적으로 실행하고 check 결과/diff를 관리하는 기능이다.
|
||||
|
||||
온톨로지 플랫폼 활용:
|
||||
|
||||
- 공식 상품 페이지 변경 감지.
|
||||
- 성분/가격/품절/리뉴얼 페이지 모니터링.
|
||||
- Claim evidence의 stale 여부 판단.
|
||||
|
||||
초기 버전에서는 Firecrawl Monitor 전체를 들여오기보다, 현재 프로젝트의 `scheduler/update_policy.py`에서 Firecrawl scrape를 주기 호출하고 content hash/changeTracking을 저장하는 방식이 단순하다.
|
||||
|
||||
### 6.10 SDK
|
||||
|
||||
Python SDK는 `apps/python-sdk/firecrawl` 아래에 있으며, v2 메서드가 `/v2/scrape`, `/v2/crawl`, `/v2/map`, `/v2/search`, `/v2/batch/scrape`, `/v2/parse`, browser interaction을 감싼다.
|
||||
|
||||
우리 프로젝트가 Firecrawl을 별도 서비스로 사용할 경우 Python SDK를 직접 사용하거나, 현재 FastAPI 서비스 내부에 얇은 adapter를 만드는 방식이 적합하다.
|
||||
|
||||
## 7. 기능명세
|
||||
|
||||
### 7.1 Document 모델
|
||||
|
||||
Firecrawl의 핵심 결과 단위는 `Document`다.
|
||||
|
||||
필드:
|
||||
|
||||
- `title`, `description`, `url`
|
||||
- `markdown`, `html`, `rawHtml`
|
||||
- `links`, `images`
|
||||
- `screenshot`, `audio`
|
||||
- `json`, `extract`, `summary`, `answer`, `highlights`, `branding`
|
||||
- `attributes`: selector/attribute/value 목록
|
||||
- `actions`: action 중 생성된 screenshot/scrape/javascript return/pdf
|
||||
- `changeTracking`: 이전 scrape 대비 상태와 diff
|
||||
- `metadata`: title, description, language, keywords, robots, OpenGraph, favicon, sourceURL, statusCode, scrapeId, contentType, proxyUsed, cacheState, cachedAt, creditsUsed 등
|
||||
- `serpResults`: search result title/description/url
|
||||
|
||||
온톨로지 플랫폼 매핑:
|
||||
|
||||
- `Document.url` -> `Page.url`
|
||||
- `Document.markdown` -> `Page.cleaned_text` 또는 `Page.markdown`
|
||||
- `Document.html/rawHtml` -> 저장 여부 선택. 기본은 저장하지 않고 hash만 저장 권장.
|
||||
- `Document.metadata.sourceURL/statusCode/contentType` -> `Page.fetch_status`, `Page.metadata`
|
||||
- `Document.links/images` -> discovery 후보와 media evidence
|
||||
- `Document.json/extract` -> 도메인 extractor 입력 또는 사전 추출값
|
||||
- `Document.changeTracking` -> claim freshness/update scheduling
|
||||
|
||||
### 7.2 Scrape API 명세
|
||||
|
||||
Endpoint: `POST /v2/scrape`
|
||||
|
||||
목적: 단일 URL을 LLM-ready document로 변환한다.
|
||||
|
||||
필수 입력:
|
||||
|
||||
- `url`: HTTP/HTTPS URL. protocol이 없으면 `http://`를 보정한다.
|
||||
|
||||
선택 입력:
|
||||
|
||||
- 공통 Scrape 옵션 전체.
|
||||
- `origin`: 요청 출처 tag. 기본 `api`.
|
||||
- `integration`: 외부 통합 정보.
|
||||
- `zeroDataRetention`: 데이터 보존 제한.
|
||||
|
||||
정상 응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"markdown": "...",
|
||||
"metadata": {
|
||||
"sourceURL": "https://example.com",
|
||||
"statusCode": 200,
|
||||
"proxyUsed": "basic"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
실패 응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"code": "ERROR_CODE",
|
||||
"error": "message"
|
||||
}
|
||||
```
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- URL 단위 수집의 기본 provider는 Firecrawl scrape로 한다.
|
||||
- 기본 format은 `markdown`, 필요 시 `html`, `links`, `images`, `screenshot`, `json`을 Source config에서 켠다.
|
||||
- extractor는 Firecrawl JSON을 그대로 신뢰하기보다, `markdown + metadata + sourceURL`을 현재 ontology extractor에 넣어 Claim/Evidence를 만든다.
|
||||
|
||||
### 7.3 Crawl API 명세
|
||||
|
||||
Endpoint: `POST /v2/crawl`
|
||||
|
||||
목적: seed URL에서 여러 URL을 발견하고 각 페이지를 scrape한다.
|
||||
|
||||
필수 입력:
|
||||
|
||||
- `url`
|
||||
|
||||
선택 입력:
|
||||
|
||||
- Crawler 옵션: `includePaths`, `excludePaths`, `limit`, `maxDiscoveryDepth`, `allowExternalLinks`, `allowSubdomains`, `ignoreRobotsTxt`, `sitemap`, `delay` 등.
|
||||
- `scrapeOptions`: 각 페이지에 적용할 scrape 옵션.
|
||||
- `webhook`: 상태 통지.
|
||||
- `maxConcurrency`
|
||||
- `prompt`: 자연어로 crawler option 생성.
|
||||
|
||||
정상 응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"id": "job-id",
|
||||
"url": "http://host/v2/crawl/job-id"
|
||||
}
|
||||
```
|
||||
|
||||
Status 조회:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"status": "scraping",
|
||||
"completed": 12,
|
||||
"total": 100,
|
||||
"creditsUsed": 12,
|
||||
"expiresAt": "...",
|
||||
"data": []
|
||||
}
|
||||
```
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- 사이트 전체 수집은 `crawl-site` 내부 구현을 Firecrawl crawl 호출로 대체 또는 선택 가능하게 한다.
|
||||
- 결과 Document[]는 Page 단위로 upsert하고, 각 Page를 ontology extraction queue로 넘긴다.
|
||||
- `includePaths/excludePaths`는 Source config의 `url_patterns`로 매핑한다.
|
||||
|
||||
### 7.4 Map API 명세
|
||||
|
||||
Endpoint: `POST /v2/map`
|
||||
|
||||
목적: scrape 없이 URL 후보 목록만 빠르게 발견한다.
|
||||
|
||||
입력:
|
||||
|
||||
- `url`
|
||||
- `search`: path/title 검색 조건.
|
||||
- `sitemap`: `only`, `include`, `skip`
|
||||
- `limit`: 기본 5000, 최대 100000
|
||||
- `includeSubdomains`, `allowExternalLinks`, `ignoreQueryParameters`, `filterByPath`
|
||||
- `useIndex`, `ignoreCache`
|
||||
|
||||
응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"links": [
|
||||
{ "url": "https://example.com/a", "title": "...", "description": "..." }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- 신규 Source 등록 시 먼저 Map을 실행해 수집 범위 preview를 보여준다.
|
||||
- 사용자가 선택한 URL 패턴을 config로 저장한다.
|
||||
- 대규모 크롤 전에 Map 결과로 예상 page 수와 domain/path 분포를 산출한다.
|
||||
|
||||
### 7.5 Batch Scrape API 명세
|
||||
|
||||
Endpoint: `POST /v2/batch/scrape`
|
||||
|
||||
목적: URL 배열을 비동기 scrape job으로 처리한다.
|
||||
|
||||
입력:
|
||||
|
||||
- `urls`: 1개 이상 URL 배열.
|
||||
- 공통 Scrape 옵션.
|
||||
- `webhook`, `appendToId`, `ignoreInvalidURLs`, `maxConcurrency`, `zeroDataRetention`.
|
||||
|
||||
응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"id": "job-id",
|
||||
"url": "http://host/v2/batch/scrape/job-id",
|
||||
"invalidURLs": []
|
||||
}
|
||||
```
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- Map으로 발견한 URL 중 우선순위가 높은 URL 묶음을 batch scrape로 실행한다.
|
||||
- 실패 URL은 `crawl_errors` 또는 Page status로 저장하고 재시도 정책에 연결한다.
|
||||
|
||||
### 7.6 Search API 명세
|
||||
|
||||
Endpoint: `POST /v2/search`
|
||||
|
||||
목적: query 기반으로 web/news/images 결과를 얻고, 필요하면 결과 페이지 내용까지 scrape한다.
|
||||
|
||||
입력:
|
||||
|
||||
- `query`
|
||||
- `limit`, `sources`, `categories`, `includeDomains`, `excludeDomains`
|
||||
- `lang`, `country`, `location`
|
||||
- `timeout`
|
||||
- `asyncScraping`
|
||||
- `scrapeOptions`
|
||||
|
||||
응답:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"id": "job-id",
|
||||
"creditsUsed": 3,
|
||||
"data": {
|
||||
"web": [
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"title": "Example",
|
||||
"description": "...",
|
||||
"markdown": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- 자동 Source 후보 발굴 기능에 사용한다.
|
||||
- `includeDomains`를 우선 사용해 공식몰/공식 문서/신뢰 출처 탐색을 제한한다.
|
||||
- 검색 결과는 즉시 Claim으로 넣지 않고 Source/Page 후보 검토 큐로 넣는다.
|
||||
|
||||
### 7.7 Parse API 명세
|
||||
|
||||
Endpoint: `POST /v2/parse`
|
||||
|
||||
목적: 업로드 파일을 Document로 변환한다.
|
||||
|
||||
입력:
|
||||
|
||||
- multipart field `file`
|
||||
- 공통 Scrape 옵션.
|
||||
- 파일 최대 50MB.
|
||||
- kind: `html`, `pdf`, `document`.
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- 로컬 catalog/PDF/manual ingest에 사용한다.
|
||||
- parse 결과는 URL source가 없을 수 있으므로 `Source.type=file`, `Page.url=file://...` 또는 별도 `documents` 테이블 정책을 정한다.
|
||||
|
||||
### 7.8 Monitor API 명세
|
||||
|
||||
Endpoint 집합:
|
||||
|
||||
- `POST /v2/monitor`
|
||||
- `GET /v2/monitor`
|
||||
- `GET /v2/monitor/:monitorId`
|
||||
- `PATCH /v2/monitor/:monitorId`
|
||||
- `DELETE /v2/monitor/:monitorId`
|
||||
- `POST /v2/monitor/:monitorId/run`
|
||||
- `GET /v2/monitor/:monitorId/checks`
|
||||
- `GET /v2/monitor/:monitorId/checks/:checkId`
|
||||
|
||||
목적: 특정 수집 대상의 변경을 주기적으로 감시한다.
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- MVP에서는 직접 도입하지 않고, Firecrawl `changeTracking` 또는 주기 scrape 결과의 content hash 비교로 대체한다.
|
||||
- 장기적으로 Claim freshness, 상품 리뉴얼, 가격/품절 변경에 연결한다.
|
||||
|
||||
### 7.9 Browser Session API 명세
|
||||
|
||||
Endpoint:
|
||||
|
||||
- `POST /v2/browser`
|
||||
- `GET /v2/browser`
|
||||
- `POST /v2/browser/:sessionId/execute`
|
||||
- `DELETE /v2/browser/:sessionId`
|
||||
- `POST /v2/scrape/:jobId/interact`
|
||||
- `DELETE /v2/scrape/:jobId/interact`
|
||||
|
||||
목적: 브라우저 세션을 생성하고 code/prompt 기반으로 조작한다.
|
||||
|
||||
우리 플랫폼 수용 기준:
|
||||
|
||||
- Source config에 `actions`를 저장하는 형태를 우선한다.
|
||||
- 자유로운 browser execute는 보안/재현성 위험이 있으므로 관리자 전용 디버깅 기능으로 제한한다.
|
||||
|
||||
## 8. Self-host 구성
|
||||
|
||||
`docker-compose.yaml` 기준 서비스:
|
||||
|
||||
- `api`: Express API와 worker harness.
|
||||
- `playwright-service`: 브라우저 수집 microservice.
|
||||
- `redis`: queue/rate limit/cache.
|
||||
- `rabbitmq`: NuQ worker messaging.
|
||||
- `nuq-postgres`: NuQ 상태 저장.
|
||||
|
||||
필수/주요 환경 변수:
|
||||
|
||||
- `PORT`, `HOST`
|
||||
- `USE_DB_AUTHENTICATION=false`로 self-host API key 없이 사용 가능
|
||||
- `REDIS_URL`, `REDIS_RATE_LIMIT_URL`
|
||||
- `PLAYWRIGHT_MICROSERVICE_URL`
|
||||
- `NUQ_RABBITMQ_URL`
|
||||
- `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_HOST`, `POSTGRES_PORT`
|
||||
- `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `MODEL_NAME`, `OLLAMA_BASE_URL` 등 AI 기능용
|
||||
- `PROXY_SERVER`, `PROXY_USERNAME`, `PROXY_PASSWORD`
|
||||
- `SEARXNG_ENDPOINT`
|
||||
- `BULL_AUTH_KEY`
|
||||
- `MAX_CPU`, `MAX_RAM`
|
||||
- `ALLOW_LOCAL_WEBHOOKS`
|
||||
|
||||
Self-host 제한:
|
||||
|
||||
- Fire-engine 고급 기능은 cloud/internal 의존성이 있어 자체 호스팅에서 제한될 수 있다.
|
||||
- 기본적으로 fetch + Playwright + PDF/document 처리 중심으로 보는 것이 현실적이다.
|
||||
- Supabase/Stripe/Autumn/GCS/Sentry 의존 영역은 자체 플랫폼에서는 제거하거나 stub 처리해야 한다.
|
||||
|
||||
## 9. 현재 프로젝트와의 통합 설계
|
||||
|
||||
현재 프로젝트는 Python/FastAPI 기반이며 핵심 구조는 다음과 같다.
|
||||
|
||||
- `crawler_platform/app/core/crawler`: fetch/discovery/clean/pipeline.
|
||||
- `crawler_platform/app/core/extractor`: rule-based/AI extractor.
|
||||
- `crawler_platform/app/core/ontology`: entity, relation, claim, triple store.
|
||||
- `crawler_platform/app/core/database`: SQLAlchemy 저장소.
|
||||
- `crawler_platform/app/core/research`: graph research loop.
|
||||
- `crawler_platform/app/api/routes.py`: 관리 API.
|
||||
- `configs/perfume_subscription.yaml`: Source/domain config.
|
||||
|
||||
권장 통합 방식:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Crawler Platform FastAPI"] --> B["Firecrawl Adapter"]
|
||||
B --> C["Firecrawl Self-host API"]
|
||||
C --> D["Scrape / Map / Crawl / Search"]
|
||||
D --> E["Document"]
|
||||
E --> F["Page Upsert"]
|
||||
F --> G["Ontology Extractor"]
|
||||
G --> H["Entity / Claim / Evidence"]
|
||||
```
|
||||
|
||||
### 단계별 채택 계획
|
||||
|
||||
1. `FirecrawlClient` adapter 추가
|
||||
- Python SDK 또는 HTTP client 사용.
|
||||
- `scrape_url`, `map_site`, `crawl_site`, `batch_scrape`, `search_sources`, `parse_file` 메서드 제공.
|
||||
|
||||
2. Source config 확장
|
||||
- `fetcher: firecrawl`
|
||||
- `firecrawl.formats`
|
||||
- `firecrawl.actions`
|
||||
- `firecrawl.crawler_options`
|
||||
- `firecrawl.scrape_options`
|
||||
- `firecrawl.search_options`
|
||||
|
||||
3. Page 저장 모델 확장
|
||||
- `markdown`
|
||||
- `raw_html_hash`
|
||||
- `metadata_json`
|
||||
- `scrape_id`
|
||||
- `content_type`
|
||||
- `cache_state`
|
||||
- `change_status`
|
||||
|
||||
4. 기존 extractor 연결
|
||||
- Firecrawl Document의 `markdown`을 표준 입력으로 사용.
|
||||
- `metadata.sourceURL`을 evidence source로 유지.
|
||||
- `links/images`를 다음 discovery 후보 또는 evidence attachment로 저장.
|
||||
|
||||
5. UI 기능 추가
|
||||
- Map preview.
|
||||
- Crawl job status.
|
||||
- Page markdown preview.
|
||||
- 실패 URL과 denial reason 표시.
|
||||
|
||||
## 10. 재사용 우선순위
|
||||
|
||||
### 즉시 재사용 권장
|
||||
|
||||
- v2 API 명세와 옵션 체계.
|
||||
- `scrape`, `map`, `crawl`, `batch scrape`.
|
||||
- Document 결과 모델.
|
||||
- Python SDK 또는 HTTP adapter.
|
||||
- Docker Compose self-host 실행 방식.
|
||||
|
||||
### 부분 재사용 권장
|
||||
|
||||
- `actions`: Source별 필요한 경우에만.
|
||||
- `search`: Source 후보 발굴 단계.
|
||||
- `parse`: 파일 ingest 단계.
|
||||
- `monitor/changeTracking`: 업데이트 감지 단계.
|
||||
- `crawler.ts`의 denial reason/URL filtering 정책: Python config validation에 반영.
|
||||
|
||||
### 초기 제외 권장
|
||||
|
||||
- billing/credit/team/account 기능.
|
||||
- x402 micropayment.
|
||||
- support proxy.
|
||||
- agent signup.
|
||||
- Supabase/Stripe/Autumn/GCS/Sentry SaaS 운영 코드.
|
||||
- Fire-engine cloud 의존 기능.
|
||||
|
||||
## 11. 온톨로지 플랫폼 기능명세 초안
|
||||
|
||||
Firecrawl을 기반 수집기로 사용할 때 범용 온톨로지 구축 플랫폼은 다음 기능을 가져야 한다.
|
||||
|
||||
### 11.1 Source 등록
|
||||
|
||||
입력:
|
||||
|
||||
- source name
|
||||
- base URL 또는 seed URL 목록
|
||||
- source type: official, marketplace, review, document, search
|
||||
- fetcher: `requests`, `playwright`, `firecrawl`
|
||||
- Firecrawl crawler/scrape/search options
|
||||
- 신뢰도 기본값
|
||||
- robots 준수 정책
|
||||
- update schedule
|
||||
|
||||
출력:
|
||||
|
||||
- Source record
|
||||
- Map preview 결과
|
||||
- 예상 page count
|
||||
|
||||
### 11.2 URL 발견
|
||||
|
||||
기능:
|
||||
|
||||
- Firecrawl Map 호출.
|
||||
- sitemap only/include/skip 선택.
|
||||
- include/exclude path regex 적용.
|
||||
- subdomain/external link 정책 적용.
|
||||
- query parameter 무시 여부.
|
||||
- URL 후보를 Page 상태 `discovered`로 저장.
|
||||
|
||||
검증:
|
||||
|
||||
- URL 중복 제거.
|
||||
- domain/path scope 위반 차단.
|
||||
- robots 차단 URL 표시.
|
||||
|
||||
### 11.3 페이지 수집
|
||||
|
||||
기능:
|
||||
|
||||
- 단일 URL scrape.
|
||||
- 다중 URL batch scrape.
|
||||
- site crawl job 실행.
|
||||
- Markdown, metadata, links, images 저장.
|
||||
- HTML 원문 저장 여부 선택.
|
||||
- screenshot 선택 저장.
|
||||
|
||||
상태:
|
||||
|
||||
- discovered
|
||||
- queued
|
||||
- fetching
|
||||
- fetched
|
||||
- failed
|
||||
- blocked_by_robots
|
||||
- skipped
|
||||
|
||||
### 11.4 문서/파일 수집
|
||||
|
||||
기능:
|
||||
|
||||
- PDF/DOCX/HTML 파일 업로드.
|
||||
- Firecrawl Parse 호출.
|
||||
- 문서 metadata와 markdown 저장.
|
||||
- 파일 기반 evidence source 생성.
|
||||
|
||||
### 11.5 구조화 추출
|
||||
|
||||
기능:
|
||||
|
||||
- Firecrawl JSON format 또는 현재 Python extractor 선택.
|
||||
- 기본 경로는 `Document.markdown -> ontology extractor`.
|
||||
- JSON Schema 기반 추출은 도메인별 schema를 사용.
|
||||
- 추출 결과는 바로 확정하지 않고 Claim/Evidence로 저장.
|
||||
|
||||
### 11.6 Claim/Evidence 생성
|
||||
|
||||
기능:
|
||||
|
||||
- Entity 후보 생성.
|
||||
- subject-predicate-object Claim 생성.
|
||||
- Evidence text와 source URL, page id, selector 또는 markdown span 저장.
|
||||
- confidence score 산출.
|
||||
- Source 신뢰도와 추출 방식에 따른 confidence 조정.
|
||||
|
||||
### 11.7 변경 감지
|
||||
|
||||
기능:
|
||||
|
||||
- Page content hash 비교.
|
||||
- Firecrawl changeTracking format 사용 가능.
|
||||
- 변경된 페이지만 재추출.
|
||||
- 삭제/숨김/동일/변경 상태 기록.
|
||||
|
||||
### 11.8 검토 UI
|
||||
|
||||
기능:
|
||||
|
||||
- Source별 Map preview.
|
||||
- Crawl job 진행률.
|
||||
- Page markdown 미리보기.
|
||||
- Claim 목록과 evidence 확인.
|
||||
- confidence 수동 조정.
|
||||
- entity merge.
|
||||
- 실패 URL과 denial reason 확인.
|
||||
|
||||
## 12. 리스크와 주의점
|
||||
|
||||
- 라이선스: Firecrawl root LICENSE는 AGPL 계열로 보인다. 소스 자체를 서비스에 내장/수정 배포할 경우 공개 의무가 발생할 수 있으므로 별도 확인이 필요하다.
|
||||
- 언어/스택 차이: 현재 프로젝트는 Python, Firecrawl 핵심은 TypeScript다. 직접 코드 병합보다 서비스 분리가 적합하다.
|
||||
- 운영 복잡도: Redis, RabbitMQ, Postgres, Playwright service가 필요하다.
|
||||
- Cloud 의존 기능: Fire-engine, 일부 index/search/branding/agent 기능은 self-host에서 제한될 수 있다.
|
||||
- 비용/속도: Playwright/action/screenshot/stealth는 비용이 크다. Source별 정책이 필요하다.
|
||||
- 데이터 보존: raw HTML/screenshot/audio 저장은 개인정보/저작권/용량 이슈가 있으므로 기본 off 권장.
|
||||
- 검색 결과 신뢰도: Search는 후보 발굴용이며 Claim 근거로 바로 쓰면 안 된다.
|
||||
|
||||
## 13. 구현 권장안
|
||||
|
||||
최초 구현은 다음 범위가 좋다.
|
||||
|
||||
1. Firecrawl self-host를 별도 Docker Compose로 실행한다.
|
||||
2. Python 프로젝트에 `FirecrawlAdapter`를 만든다.
|
||||
3. `POST /crawl` 또는 CLI `crawl-url`에 `fetcher=firecrawl` 옵션을 추가한다.
|
||||
4. 단일 URL scrape 결과의 markdown을 기존 extractor로 넘긴다.
|
||||
5. Map preview와 batch scrape는 두 번째 단계에서 붙인다.
|
||||
6. Monitor/changeTracking/search/parse는 세 번째 단계에서 붙인다.
|
||||
|
||||
이 방식이면 Firecrawl의 강한 수집 능력을 거의 변형 없이 사용하면서, 현재 프로젝트의 핵심 가치인 범용 온톨로지/Claim/Evidence/추천 구조는 Python 코드에 유지할 수 있다.
|
||||
|
||||
Reference in New Issue
Block a user