# Node.jsでWebページをMarkdownに変換

> Node.jsのネイティブfetchでWebページをMarkdownに変換：1ページ、小さな並列プール、クロールのポーリングループ。$0.07/1Kページから、KYC不要、暗号資産で支払い。

- URL: https://webreaderapi.com/ja/docs/node/
- 最終更新: 2026-10-22
- 発行者: WebReaderAPI (https://webreaderapi.com)

Node.js 18以降には`fetch`が同梱されているため、依存関係はまったく不要です。3つのレシピ：1ページを読む、小さな並列プールでリストを読む、クロールジョブが完了するまで追跡する。

**概要 — Node.jsでWebページをMarkdownに変換するには？**

Node.js 18以降の組み込み`fetch`を使います。`Authorization`ヘッダーにキーを入れて`https://webreaderapi.com/api/v1/read?url=…`を呼び出し、JSONの応答から`markdown`を読み取ります。**WebReaderAPI**はページの本文をタイトル、著者、日付とともに返します。1ページあたり1クレジット、ブラウザ使用時は2クレジットで、2026年10月時点で$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：1ページ*

```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`に達してしまいます。すべてのアカウントには同時に読み取れるページ数の上限があります。上限はダッシュボードに表示され、サポートで引き上げられます。

以下のプールはエラーを結果の隣に保持するため、1ページが拒否されても実行は止まりません。`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/ja/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`をモデルのコンテキストに収まるサイズ（1ページあたり20,000文字など）に保ってください。

[OpenAI function callingのページ](https://webreaderapi.com/ja/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/ja/docs/errors/)にはすぐに使えるバックオフ関数があります。

### 10,000ページを読むとどれくらいのコストですか？

通常のページなら約10,000クレジット、一部でブラウザが必要な場合はそれ以上です。10,000ページのコストは$3.75です。プリペイドクレジットに有効期限はありません。未使用のページは使うまでアカウントに残ります。

---

WebReaderAPI: WebReaderAPIはAIエージェント向けのWebリーダーAPIで、あらゆる公開WebページをクリーンなMarkdownに変換します。暗号資産で支払い、本人確認書類のアップロードは不要です。$0.07/1Kページから購入できるプリペイドクレジットに有効期限はなく、robots.txtを尊重します。KYC不要 — 身分証もセルフィーも書類も不要。暗号資産で支払い。
