# Node.js에서 웹페이지를 Markdown으로 변환

> 네이티브 fetch로 Node.js에서 웹페이지를 Markdown으로 변환하세요. 한 페이지, 작은 동시성 풀, 크롤링 폴링 루프입니다. US$0.07/1K 페이지부터, KYC 없이, 암호화폐 결제.

- URL: https://webreaderapi.com/ko/docs/node/
- 마지막 업데이트: 2026-10-22
- 발행자: WebReaderAPI (https://webreaderapi.com)

Node.js 18 이상에는 `fetch`이 기본 포함되어 의존성이 전혀 필요 없습니다. 세 가지 레시피: 한 페이지 읽기, 작은 동시성 풀로 목록 읽기, 크롤링 작업이 끝날 때까지 따라가기.

**빠른 답변 — Node.js에서 웹페이지를 Markdown으로 변환하려면 어떻게 하나요?**

Node.js 18+의 내장 `fetch`을 사용하세요. `Authorization` 헤더에 키를 넣고 `https://webreaderapi.com/api/v1/read?url=…`를 호출한 뒤, JSON 응답에서 `markdown`을 읽으면 됩니다. **WebReaderAPI**은 페이지의 제목, 작성자, 날짜와 함께 본문을 반환합니다. 한 페이지에 1 크레딧, 헤드리스 브라우저가 필요하면 2 크레딧이며, 2026년 10월 기준 US$0.07/1K 페이지부터입니다. KYC 없이, 암호화폐로 결제합니다.

## 무엇이 필요한가요?

Node.js 18 이상(전역 `fetch` 사용)과 `WEBREADER_API_KEY` 환경 변수에 설정한 API 키가 필요합니다. 예제는 ES 모듈입니다. `.mjs` 확장자로 저장하거나 `package.json`에 `"type": "module"`을 설정해 최상위 `await`이 동작하게 하세요.

JSDoc 주석이 응답 구조를 설명하므로 VS Code 같은 에디터에서 TypeScript 빌드 단계 없이 완성을 제공합니다.

*read.mjs: 한 페이지*

```javascript
/**
 * @typedef {Object} Page
 * @property {string} url
 * @property {string} final_url
 * @property {number} status_code
 * @property {boolean} rendered
 * @property {number} credits_used
 * @property {string} [title]
 * @property {string} [author]
 * @property {string} [published_at]
 * @property {string} [language]
 * @property {string} [markdown]
 * @property {number} word_count
 */

/** @returns {Promise<Page>} */
export async function readPage(url, options = {}) {
  const params = new URLSearchParams({ url, ...options });
  const res = await fetch(`https://webreaderapi.com/api/v1/read?${params}`, {
    headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
    signal: AbortSignal.timeout(75_000),
  });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.error.message), { code: body.error.code });
  return body;
}

const page = await readPage('https://example.com/docs/getting-started', { max_chars: '20000' });
console.log(page.title, page.word_count, 'words,', page.credits_used, 'credit(s)');

```

## 한도를 넘지 않고 URL 목록을 읽으려면 어떻게 하나요?

공유 큐에서 URL을 가져가는 고정된 수의 워커를 실행하세요. 전체 목록에 `Promise.all`을 걸어 모든 요청을 한꺼번에 시작해 `429 concurrency_limit`에 부딪히는 것보다 간단합니다. 모든 계정에는 동시에 읽는 페이지 수에 대한 한도가 있으며, 대시보드에 표시됩니다. 지원팀이 이를 높일 수 있습니다.

아래 풀은 오류를 결과 옆에 두므로, 거부된 페이지 하나가 실행을 멈추지 않습니다. `blocked_by_robots` 같은 거부는 최종적이며 무료입니다. 개수를 세고 넘어가세요.

*pool.mjs: URL 목록, 한 번에 8개*

```javascript
import { readPage } from './read.mjs';

export async function readAll(urls, workers = 8) {
  const queue = [...urls];
  const results = [];
  async function worker() {
    while (queue.length) {
      const url = queue.shift();
      try {
        const page = await readPage(url, { max_chars: '50000' });
        results.push({ url, page });
      } catch (err) {
        results.push({ url, error: err.code ?? err.name });
      }
    }
  }
  await Promise.all(Array.from({ length: workers }, worker));
  return results;
}

const urls = Array.from({ length: 30 }, (_, i) => `https://example.com/blog/post-${i + 1}`);
for (const r of await readAll(urls)) console.log(r.url, '->', r.error ?? r.page.title);

```

## Node.js에서 크롤링 작업을 따라가려면 어떻게 하나요?

`POST https://webreaderapi.com/api/v1/crawl`으로 작업을 시작한 뒤 루프에서 `https://webreaderapi.com/api/v1/jobs/{job_id}`을 읽으세요. `next_cursor`이 반환될 때마다 `cursor`을 전달하고, 커서가 없고 상태가 `done`이면 작업이 끝난 것입니다. 빈 폴링 사이에는 기다리고 최대 30초까지 대기 시간을 두 배로 늘리세요. 사이트의 Crawl-delay를 준수하는 크롤링은 느릴 수 있습니다.

[배치 및 크롤링 페이지](https://webreaderapi.com/ko/docs/crawl/)에서 크롤링이 페이지를 어떻게 고르고 `limit`이 읽는 범위를 어떻게 제한하는지 설명합니다.

*crawl.mjs: 크롤링 시작하고 모든 페이지 수집*

```javascript
const headers = {
  Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`,
  'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const start = await fetch('https://webreaderapi.com/api/v1/crawl', {
  method: 'POST',
  headers,
  body: JSON.stringify({ url: 'https://docs.example.com/', limit: 300, include_paths: ['/docs/*'] }),
});
const { job_id } = await start.json();

const pages = [];
let cursor = '';
let wait = 2000;
for (;;) {
  const url = `https://webreaderapi.com/api/v1/jobs/${job_id}${cursor ? `?cursor=${encodeURIComponent(cursor)}` : ''}`;
  const job = await (await fetch(url, { headers })).json();
  pages.push(...job.results.filter((r) => !r.error));
  if (job.next_cursor) {
    cursor = job.next_cursor;
    wait = 2000;
    continue;
  }
  if (job.status === 'done') break;
  await sleep(wait);
  wait = Math.min(wait * 2, 30000);
}
console.log(pages.length, 'pages read, job', job_id);

```

## 결과를 모델에 어떻게 전달하나요?

전체 JSON이 아니라 Markdown을 보내세요. `markdown` 필드가 모델이 읽어야 할 내용이며, 메타데이터는 인용에 쓰는 편이 좋습니다. 모델이 출처를 밝힐 수 있도록 제목과 `final_url`를 앞에 붙이고, `max_chars`은 모델의 컨텍스트에 들어가는 크기(페이지당 20,000자 등)로 유지하세요.

[OpenAI function calling 페이지](https://webreaderapi.com/ko/docs/openai/)는 Python으로 전체 툴 루프를 보여줍니다. 위의 `readPage` 함수도 Node.js 에이전트의 툴 본문으로 쓸 수 있습니다.

## Node.js: 자주 묻는 질문

### Deno, Bun 또는 브라우저에서 동작하나요?

Deno와 Bun은 같은 `fetch`과 ES 모듈을 지원합니다. 브라우저 페이지에서 API를 호출하지 마세요. 키가 모든 방문자에게 노출됩니다. 대신 서버에서 호출하세요.

### npm 패키지가 있나요?

없습니다. 이 페이지의 함수가 통합의 전부입니다. WebReaderAPI은 순수 HTTPS와 JSON이므로 재시도, 타임아웃, 로깅을 직접 제어할 수 있습니다.

### 429 concurrency_limit은 어떻게 처리하나요?

워커 수를 줄이거나, 짧게 기다렸다가 매번 두 배로 늘려 재시도하세요. 429는 비용이 들지 않으며, [오류 페이지](https://webreaderapi.com/ko/docs/errors/)에 바로 쓸 수 있는 백오프 함수가 있습니다.

### 10,000 페이지를 읽으면 비용이 얼마인가요?

일반 페이지 기준 약 10,000 크레딧이며, 일부가 헤드리스 브라우저를 필요로 하면 더 듭니다. 10,000페이지 비용은 US$3.75입니다. 선불 크레딧은 만료되지 않습니다. 사용하지 않은 페이지는 사용할 때까지 계정에 남아 있습니다.

---

WebReaderAPI: WebReaderAPI는 AI 에이전트를 위한 웹 리더 API로, 모든 공개 웹페이지를 깔끔한 Markdown으로 변환하며 신분증 업로드 없이 암호화폐로 결제합니다. US$0.07/1K 페이지부터 시작하는 선불 크레딧은 만료되지 않으며, robots.txt를 준수합니다. KYC 없음 — 신분증도, 셀피도, 서류도 없습니다. 암호화폐로 결제하세요.
