Crawl
전체 웹사이트를 크롤링해 LLM에 맞는 구조화 데이터로 변환합니다.
소개
AnyCrawl 크롤 API는 시드 URL에서 여러 페이지를 발견·처리하며, 페이지마다 /v1/scrape과 동일한 추출 파이프라인을 적용합니다. 비동기입니다: 즉시 job_id를 받은 뒤 상태를 폴링하고 결과를 페이지 단위로 가져옵니다.
핵심 기능
- 비동기 작업: 크롤을 큐에 넣고 나중에 결과 수신
- 다중 엔진:
auto(기본),cheerio,playwright,puppeteer - 유연한 범위 제어:
strategy,max_depth,include_paths,exclude_paths - 페이지별 옵션:
scrape_options아래에서/v1/scrape옵션 재사용 - 페이지네이션:
skip으로 결과를 나눠 페이로드 크기 제어
API 엔드포인트
POST https://api.anycrawl.dev/v1/crawl
GET https://api.anycrawl.dev/v1/crawl/{jobId}/status
GET https://api.anycrawl.dev/v1/crawl/{jobId}?skip=0
DELETE https://api.anycrawl.dev/v1/crawl/{jobId}사용 예
크롤 작업 생성
curl -X POST "https://api.anycrawl.dev/v1/crawl" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://anycrawl.dev",
"engine": "cheerio",
"strategy": "same-domain",
"max_depth": 5,
"limit": 100,
"exclude_paths": ["/blog/*"],
"scrape_options": {
"formats": ["markdown"],
"timeout": 60000
}
}'scrape_paths로 선택적 스크래핑
scrape_paths로 링크 발견만 할 페이지를 방문하고 본문 추출은 생략할 수 있습니다. 비용과 저장 공간을 줄입니다.
curl -X POST "https://api.anycrawl.dev/v1/crawl" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com",
"engine": "cheerio",
"strategy": "same-domain",
"max_depth": 5,
"limit": 200,
"include_paths": ["/*"],
"scrape_paths": ["/products/*/details", "/products/*/reviews"],
"scrape_options": {
"formats": ["markdown", "json"]
}
}'이 예에서는:
/*에 맞는 모든 페이지는 링크 발견을 위해 방문됩니다./products/*/details또는/products/*/reviews에 맞는 페이지만 본문 추출·저장됩니다.- 카테고리·네비게이션 페이지는 크롤되지만 스크래핑되지 않아 크레딧과 저장을 절약합니다.
const start = await fetch("https://api.anycrawl.dev/v1/crawl", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://anycrawl.dev",
engine: "cheerio",
strategy: "same-domain",
max_depth: 5,
limit: 100,
exclude_paths: ["/blog/*"],
scrape_options: { formats: ["markdown"], timeout: 60000 },
}),
});
const startResult = await start.json();
const jobId = startResult.data.job_id;상태 폴링
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
"https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396/status"결과 가져오기(페이지네이션)
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
"https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396?skip=0"작업 취소
curl -X DELETE -H "Authorization: Bearer <YOUR_API_KEY>" \
"https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396"요청 파라미터
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
url | string | 예 | - | 크롤을 시작할 시드 URL |
template_id | string | 아니오 | - | 이번 크롤에 사용할 템플릿 ID |
variables | object | 아니오 | - | 템플릿 변수(template_id가 있을 때만 사용) |
engine | enum | 아니오 | auto | 페이지별 스크래핑 엔진: auto, cheerio, playwright, puppeteer |
exclude_paths | array of string | 아니오 | - | 제외할 경로 규칙(glob 유사), 예: /blog/* |
include_paths | array of string | 아니오 | - | 크롤에 포함할 경로 규칙(제외 이후 적용) |
scrape_paths | array of string | 아니오 | - | 본문 추출 경로 규칙. 일치하는 URL만 내용이 저장됩니다. 미설정 시 포함된 URL은 모두 스크래핑 |
max_depth | number | 아니오 | 10 | 시드 URL 기준 최대 깊이 |
strategy | enum | 아니오 | same-domain | 크롤 범위: all, same-domain, same-hostname, same-origin |
limit | number | 아니오 | 100 | 크롤할 최대 페이지 수 |
max_age | number | 아니오 | - | 캐시 최대 수명(ms). 0이면 캐시 읽기 생략, 생략 시 서버 기본값 |
store_in_cache | boolean | 아니오 | true | 페이지별 스크래핑에 페이지 캐시를 쓸지 여부 |
retry | boolean | 아니오 | false | 실패 시 재시도 여부 |
proxy | string (URI) | 아니오 | - | 선택 프록시 URL |
formats | array of enum | 아니오 | ["markdown"] | 페이지별 스크래핑 출력 형식 |
timeout | number | 아니오 | 60000 | 요청당 타임아웃(ms) |
wait_for | number | 아니오 | - | 추출 전 지연(ms), 브라우저 엔진만 |
wait_until | enum | 아니오 | - | 브라우저 탐색 대기: load, domcontentloaded, networkidle, commit |
wait_for_selector | string, object, or array | 아니오 | - | 하나 이상의 선택자 대기(브라우저 엔진만). wait_for보다 우선. |
include_tags | array of string | 아니오 | - | CSS 선택자에 맞는 요소만 포함 |
exclude_tags | array of string | 아니오 | - | CSS 선택자에 맞는 요소 제외 |
only_main_content | boolean | 아니오 | true | 본문만 추출(헤더·푸터·내비 등 제거) |
json_options | object | 아니오 | - | 구조화 JSON 추출 옵션(schema, user_prompt, schema_name, schema_description) |
extract_source | enum | 아니오 | markdown | JSON 추출 소스: markdown(기본) 또는 html |
ocr_options | boolean | 아니오 | false | 마크다운 이미지에만 OCR 강화. 마크다운 생성에만 영향, html/rawHtml는 아님. |
scrape_options | object | 아니오 | - | 페이지별 스크래프 옵션(최상위 url/engine 제외하고 /v1/scrape과 동일) |
scrape_options 필드
| Field | Type | Default | Notes |
| ------------------- | ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| formats | array of enum | ["markdown"] | 출력 형식: markdown, html, text, screenshot, screenshot@fullPage, rawHtml, json, summary, links |
| timeout | number | 60000 | 요청당 타임아웃(ms) |
| wait_for | number | - | 추출 전 지연(ms), 브라우저만, wait_for_selector보다 낮은 우선순위 |
| wait_for_selector | string, object, or array | - | 브라우저에서만. CSS 문자열, 객체 { selector: string, state?: "attached" \| "visible" \| "hidden" \| "detached", timeout?: number }, 또는 혼합 배열. 순차 대기. wait_for보다 우선. |
| include_tags | array of string | - | CSS 선택자에 맞는 요소만 포함 |
| exclude_tags | array of string | - | CSS 선택자에 맞는 요소 제외 |
| only_main_content | boolean | true | 본문만 추출 |
| proxy | string (URI) | - | 선택 프록시 URL |
| json_options | object | - | 구조화 JSON 추출 옵션 |
| extract_source | enum | markdown | JSON 추출 소스: markdown(기본) 또는 html |
| ocr_options | boolean | false | 마크다운 이미지 OCR만. 마크다운 생성에만 영향. |
| max_age | number | - | 캐시 최대 수명(ms). 0이면 캐시 읽기 생략 |
| store_in_cache | boolean | true | 페이지별 스크래핑에 페이지 캐시 쓰기 여부 |
캐시 동작
- 크롤은 현재 전체 크롤 요청에 대해 페이지 캐시를 읽지 않지만, 쓰기는 할 수 있습니다.
scrape_options를 넘기면 그 안에서 캐시를 제어하세요.
응답 형식
1) 생성(HTTP 200)
{
"success": true,
"data": {
"job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396",
"status": "created",
"message": "Crawl job has been queued for processing"
}
}가능한 오류
- 400 유효성 검사 오류
{
"success": false,
"error": "Validation error",
"message": "Invalid enum value...",
"data": {
"type": "validation_error",
"issues": [
{ "field": "engine", "message": "Invalid enum value", "code": "invalid_enum_value" }
],
"status": "failed"
}
}- 401 인증 오류
{ "success": false, "error": "Invalid API key" }2) 상태(HTTP 200)
{
"success": true,
"message": "Job status retrieved successfully",
"data": {
"job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396",
"status": "completed",
"start_time": "2025-05-25T07:56:44.162Z",
"expires_at": "2025-05-26T07:56:44.162Z",
"credits_used": 0,
"total": 120,
"completed": 30,
"failed": 2
}
}3) 결과 페이지(HTTP 200)
{
"success": true,
"status": "pending",
"total": 120,
"completed": 30,
"credits_used": 12,
"next": "https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396?skip=100",
"data": [
{
"url": "https://anycrawl.dev/",
"title": "AnyCrawl",
"markdown": "# AnyCrawl...",
"timestamp": "2025-05-25T07:56:44.162Z"
}
]
}가능한 오류
- 400 잘못된 작업 ID / 없음
{ "success": false, "error": "Invalid job ID", "message": "Job ID must be a valid UUID" }4) 취소(HTTP 200)
{
"success": true,
"message": "Job cancelled successfully",
"data": { "job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396", "status": "cancelled" }
}가능한 오류
- 404 없음
- 409 이미 종료된 작업
{
"success": false,
"error": "Job already finished",
"message": "Finished jobs cannot be cancelled"
}모범 사례
- 단일 페이지는 비용 절감을 위해
/v1/scrape, 사이트 전체 데이터는/v1/crawl. strategy,max_depth, 경로 규칙으로 범위와 비용 조절.scrape_paths로 비용 절감: 네비·카테고리는 링크만, 본문 페이지만 스크래핑.- 실제로 필요한 만큼만
formats로 출력 크기 제한. skip으로 페이지네이션해 과도하게 큰 응답 방지.
scrape_paths로 비용 최적화
scrape_paths 없음(기본):
- 포함된 모든 페이지 → 방문 + 본문 추출 + 저장
scrape_paths 있음:
include_paths에는 있으나scrape_paths에는 없음 → 방문만(링크 발견)include_paths와scrape_paths모두에 해당 → 방문 + 본문 추출 + 저장
예:
- 이커머스: 모든 카테고리는 크롤하되 상품 상세만 스크래핑
- 문서: 모든 네비는 방문, 본문은 글 페이지만 추출
- 뉴스: 모든 섹션 탐색, 전체 기사 페이지만 저장
오류 처리 예
async function fetchAllResults(jobId) {
let skip = 0;
while (true) {
const res = await fetch(`https://api.anycrawl.dev/v1/crawl/${jobId}?skip=${skip}`);
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err.message || `HTTP ${res.status}`);
}
const page = await res.json();
// page.data 처리
if (!page.next) break;
const next = new URL(page.next);
skip = Number(next.searchParams.get("skip") || 0);
}
}높은 동시성 사용
크롤 큐는 동시 작업을 지원합니다. 여러 크롤 작업을 제출하고 각각 독립적으로 폴링하세요.
const seeds = ["https://site-a.com", "https://site-b.com", "https://site-c.com"];
const jobs = await Promise.all(
seeds.map((url) =>
fetch("https://api.anycrawl.dev/v1/crawl", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url, engine: "cheerio" }),
}).then((r) => r.json())
)
);자주 묻는 질문
/v1/crawl과 /v1/scrape의 차이는?
/v1/scrape은 단일 URL을 동기로 가져와 즉시 콘텐츠를 반환합니다. /v1/crawl은 시드에서 여러 페이지를 발견하며 비동기로 실행됩니다.
크롤 범위와 비용을 어떻게 제한하나요?
strategy, max_depth, limit, 경로 규칙(include_paths, exclude_paths, scrape_paths)을 사용하세요.
include_paths와 scrape_paths의 차이는?
include_paths: 어떤 URL을 방문할지(링크 발견)scrape_paths: 어떤 URL에서 본문을 추출·저장할지
scrape_paths가 없으면 포함된 URL은 모두 스크래핑됩니다(이전과 동일).
크롤 비용을 더 줄이려면?
scrape_paths로 네비·카테고리는 링크 발견만 하고 내용은 저장하지 않습니다. scrape_paths 패턴에 맞는 페이지만 추출·저장하세요.
결과를 어떻게 페이지네이션하나요?
skip 쿼리 파라미터를 사용합니다. 응답에 next가 있으면 따라가 다음 페이지를 가져옵니다.
일부 작업에 html/markdown이 없는 이유는?
scrape_options.formats에 원하는 형식이 포함되어 있고, 선택한 엔진이 지원하는지 확인하세요.
상태 값
작업 status는 작업 모델에 정의된 값을 따릅니다.
| Status | 의미 |
|---|---|
pending | 큐에 있거나 진행 중(아직 끝나지 않음) |
completed | 성공적으로 완료 |
failed | 오류로 종료 |
cancelled | 취소됨, 더 이상 처리 없음 |
OpenAPI(자동 생성)
자동 생성 문서는 API 레퍼런스를 참고하세요.
POST /v1/crawlGET /v1/crawl/{jobId}/statusGET /v1/crawl/{jobId}DELETE /v1/crawl/{jobId}