~/utility/rag-web-crawler
RAG Web Crawler — 웹페이지를 Markdown과 텍스트 청크로
공개 웹페이지를 깔끔한 Markdown, 일반 텍스트, 출처 URL과 문자 위치가 붙은 겹치는 텍스트 청크로 변환합니다. 바로 임베딩해 RAG에 쓸 수 있습니다.
RAG 데이터
TypeScriptMozilla ReadabilityjsdomTurndown
글로벌
카테고리utility / RAG 데이터
언어TypeScript
스택TypeScript, Mozilla Readability, jsdom, Turndown
마켓글로벌
출력클린한 RAG-레디 JSON
주요 기능
페이지마다 깔끔한 Markdown과 일반 텍스트를 출력하며 제목, 목록, 링크, 코드 블록, 간단한 표를 유지합니다
바로 임베딩할 수 있는 청크: 서로 겹치고 가능한 한 문단이나 문장 경계에서 끝나며, 각 청크에 고정된 id, 출처 URL과 제목, 인용용 정확한 문자 위치가 붙습니다
본문 우선: 메뉴, 헤더, 푸터, 사이드바는 제외하고, 지정한 다른 요소도 CSS 선택자로 제거할 수 있습니다
각 사이트 안에서 링크를 최대 5단계까지 따라가며, 각 페이지는 한 번만 가져옵니다
URL 대신 검색: 쿼리의 검색 결과 페이지를 시작 URL처럼 크롤링합니다(Apify 유료 플랜 필요)
기본적으로 robots.txt를 따르고, 같은 사이트로 보내는 요청 사이에 적절한 간격을 둡니다
페이지는 영어, 중국어 등 원래 언어 그대로 유지되며 번역하지 않습니다
페이지마다 상태와 오류 코드를, 실행마다 건수와 중단 사유가 담긴 요약을 남깁니다
활용 사례
- 문서와 도움말 센터 페이지로 RAG 챗봇의 지식 베이스 구축
- AI 에이전트가 인용할 수 있는 최신 웹페이지에 근거해 답하도록 지원
- 기사 목록을 시맨틱 검색용 임베딩으로 변환
- 특정 주제의 검색으로 찾은 페이지를 원래 언어 그대로 수집
- 벡터 저장소를 정기적으로 갱신: 페이지가 바뀌지 않으면 청크 id도 바뀌지 않습니다
- Apify의 MCP 서버를 통해 AI 에이전트에 웹페이지를 Markdown으로 제공
입력 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
startUrls | array | 선택 | 크롤링할 공개 페이지 URL(최대 1,000개) |
query | string | 선택 | 결과 페이지를 크롤링할 검색 쿼리(Apify 유료 플랜 필요) |
queries | array | 선택 | 추가 검색 쿼리, query와 합쳐짐 |
maxResultsPerQuery | number | 선택 | 쿼리마다 크롤링할 검색 결과 수(기본 5, 최대 50) |
maxPages | number | 선택 | 한 번의 실행에서 예약하는 서로 다른 페이지의 최대 수(기본 20, 최대 1,000) |
maxDepth | number | 선택 | 각 사이트 안에서 따라갈 링크 단계 수(기본 0 = 시작 URL만, 최대 5) |
maxConcurrency | number | 선택 | 동시에 처리하는 페이지 수(기본 3) |
maxSearchRequests | number | 선택 | 실행당 검색 요청 수, 재시도 포함(기본 10, 0 = 검색 안 함) |
maxFetchRequests | number | 선택 | 실행당 모든 네트워크 시도, robots.txt와 재시도 포함(기본 100) |
requestTimeoutSecs | number | 선택 | 요청마다의 타임아웃, 초 단위(기본 30) |
maxResponseBytes | number | 선택 | 허용하는 가장 큰 페이지 응답(기본 2 MiB) |
maxContentChars | number | 선택 | 페이지마다 남기는 가장 긴 텍스트, 문자 수(기본 50,000) |
maxOutputBytes | number | 선택 | 실행당 전체 출력량(기본 20 MiB) |
respectRobotsTxt | boolean | 선택 | 먼저 각 사이트의 robots.txt 확인(기본 켜짐) |
onlyMainContent | boolean | 선택 | 페이지 본문만 남김(기본 켜짐) |
removeSelectors | array | 선택 | 추출 전에 제거할 요소의 CSS 선택자 |
chunkSize | number | 선택 | 청크 길이, 토큰이 아닌 문자 수(기본 1,000) |
chunkOverlap | number | 선택 | 이웃한 청크가 공유하는 문자 수(기본 150) |
출력 예시
실제 실행에서 저장된 페이지 하나입니다. 텍스트는 줄였고 다섯 개의 청크 중 하나만 보여 줍니다.
1{
2 "schemaVersion": "1.0",
3 "url": "https://www.w3.org/WAI/tutorials/tables/one-header/",
4 "title": "Tables with One Header",
5 "description": "Accessibility resources free online from the international standards organization: W3C Web Accessibility Initiative (WAI).",
6 "languageCode": "en",
7 "canonicalUrl": "https://www.w3.org/WAI/tutorials/tables/one-header/",
8 "markdown": "# Tables with One Header\n\nin [Tables Tutorial](https://www.w3.org/WAI/tutorials/tables/)\n\n## Overview\n\n…",
9 "text": "Tables with One Header\n\nin Tables Tutorial\n\nOverview\n\nThis page covers tables that have one simple header for rows or one simple header for columns. …",
10 "chunks": [
11 {
12 "id": "495cb4e58e13bbf9b5cdbe922f7ea652973ca4dfda61b952aaa021db045a450c",
13 "index": 0,
14 "text": "Tables with One Header\n\nin Tables Tutorial\n\nOverview\n\nThis page covers tables that have one simple header for rows or one simple header for columns. …",
15 "startChar": 0,
16 "endChar": 988,
17 "sourceUrl": "https://www.w3.org/WAI/tutorials/tables/one-header/",
18 "title": "Tables with One Header"
19 }
20 ],
21 "contentTruncated": false,
22 "sources": [],
23 "crawl": {
24 "depth": 0,
25 "httpStatusCode": 200,
26 "loadedAt": "2026-10-19T07:03:53.643Z",
27 "contentType": "text/html",
28 "renderingMode": "http",
29 "extractionMethod": "main"
30 }
31}
청크 위치는 text의 유니코드 코드 포인트로 셉니다. 실행마다 페이지별 상태와 오류 코드를 담은 REQUESTS와, 건수, 중단 사유, 청구된 이벤트를 담은 실행 요약 OUTPUT도 함께 기록됩니다.
팁
id를 벡터 저장소의 레코드 ID로 쓰세요. 페이지와 청크 설정이 바뀌지 않으면 실행이 달라져도 같으므로, 정기 실행에서id기준으로 청크를 쓰면 복사본이 늘지 않고 교체됩니다.- 적은 페이지부터 시작하세요.
maxPages나maxDepth를 늘리기 전에 대상 페이지의 Markdown을 확인하고, 관련 링크 상자 같은 잔여물은removeSelectors로 제거하세요. REQUESTS도 Dataset과 함께 보세요. 실행이 성공해도 일부 페이지가 건너뛰어지거나 실패했을 수 있으며, 각각 이유가 기록됩니다.
자주 묻는 질문
일반 웹 스크래퍼와 무엇이 다른가요?
선택자가 아니라 URL이나 검색 쿼리만 주면 됩니다. 각 페이지의 본문을 Markdown과 일반 텍스트로 저장하고, 텍스트를 바로 임베딩할 수 있는 청크로 나눕니다. 각 청크에 페이지의 URL, 제목, 정확한 문자 위치가 붙어 있어 답변에 출처를 밝힐 수 있습니다.
API 키가 필요한가요?
크롤링에도 검색에도 외부 API 키는 필요 없습니다. Apify 계정이 필요하며, Apify API로 Actor를 호출할 때는 Apify 토큰을 사용합니다.
JavaScript를 렌더링하나요?
아니요. 페이지를 HTTP로 읽기 때문에, 텍스트를 보여 주려면 JavaScript가 필요한 페이지는 NO_CONTENT로 실패하거나 불완전하게 올 수 있습니다. 먼저 대상 페이지 몇 개로 시험해 보세요.
어떤 페이지를 읽을 수 있나요?
공개된 HTML, Markdown, 일반 텍스트 페이지입니다. 로그인, 쿠키, 페이월, CAPTCHA, 프록시, PDF, 이미지는 대상이 아니며, 사설 네트워크 주소와 인증 정보가 담긴 URL은 거부됩니다.
웹사이트를 크롤링해도 되나요?
공개된 비개인 데이터를 크롤링하는 것은 일반적으로 합법이지만, 페이지 내용은 저작권으로 보호되는 경우가 많고 일부 사이트는 이용 약관으로 크롤링을 제한합니다. 크롤러는 기본적으로 robots.txt를 따릅니다. 수집한 내용을 어떻게 쓰는지는 사용자 책임입니다.