# แปลงหน้าเว็บเป็น Markdown ใน Node.js

> แปลงหน้าเว็บเป็น Markdown ใน Node.js ด้วย fetch แบบ native: หนึ่งหน้า, concurrency pool เล็ก และลูป poll crawl จาก US$0.07/1K หน้า ไม่ต้อง KYC จ่ายด้วยคริปโต

- URL: https://webreaderapi.com/th/docs/node/
- อัปเดตล่าสุด: 2026-10-22
- ผู้เผยแพร่: WebReaderAPI (https://webreaderapi.com)

Node.js 18 ขึ้นไปมี `fetch` มาให้ จึงไม่ต้องใช้ dependency ใดเลย สูตรสามแบบ: อ่านหนึ่งหน้า, อ่านรายการด้วย concurrency pool ขนาดเล็ก และติดตาม crawl job จนเสร็จ

**คำตอบสั้น — แปลงหน้าเว็บเป็น Markdown ใน Node.js ได้อย่างไร?**

ใช้ `fetch` ที่มีมาใน Node.js 18+: เรียก `https://webreaderapi.com/api/v1/read?url=…` พร้อมคีย์ของคุณใน header `Authorization` แล้วอ่าน `markdown` จากคำตอบ JSON **WebReaderAPI** คืนเนื้อหาหลักของหน้าพร้อมชื่อเรื่อง ผู้เขียน และวันที่ หนึ่งหน้าใช้ 1 เครดิต 2 เครดิตเมื่อใช้เบราว์เซอร์ จาก US$0.07/1K หน้า ณ ตุลาคม 2026 ไม่ต้อง KYC จ่ายด้วยคริปโต

## ต้องเตรียมอะไรบ้าง?

Node.js 18 ขึ้นไป สำหรับ `fetch` แบบ global และ API key ใน environment variable `WEBREADER_API_KEY` ตัวอย่างเป็น ES modules: บันทึกด้วยนามสกุล `.mjs` หรือตั้ง `"type": "module"` ใน `package.json` เพื่อให้ `await` ระดับบนสุดทำงานได้

คอมเมนต์ JSDoc อธิบายโครงสร้าง response ดังนั้น editor อย่าง VS Code จะให้ completion โดยไม่ต้องมีขั้นตอน build 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 โดยไม่ชน limit ได้อย่างไร?

รัน worker จำนวนคงที่ที่ดึง URL จาก queue ที่ใช้ร่วมกัน วิธีนี้เรียบง่ายกว่า `Promise.all` ทั้งรายการ ซึ่งจะเริ่มทุก request พร้อมกันและชน `429 concurrency_limit` ทุกบัญชีมีขีดจำกัดจำนวนหน้าที่อ่านพร้อมกัน แดชบอร์ดแสดงให้เห็น และฝ่ายสนับสนุนสามารถเพิ่มให้ได้

pool ด้านล่างเก็บ error ไว้ข้างผลลัพธ์ หน้าหนึ่งที่ถูกปฏิเสธจึงไม่หยุดการทำงาน การปฏิเสธเช่น `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);

```

## ติดตาม crawl job ใน Node.js ได้อย่างไร?

เริ่ม job ด้วย `POST https://webreaderapi.com/api/v1/crawl` แล้วอ่าน `https://webreaderapi.com/api/v1/jobs/{job_id}` ในลูป ส่ง `cursor` ทุกครั้งที่ `next_cursor` กลับมา เมื่อไม่มี cursor และสถานะเป็น `done` แสดงว่า job เสร็จแล้ว รอระหว่างการ poll ที่ว่างเปล่าและเพิ่มเวลารอเป็นสองเท่าจนถึง 30 วินาที เพราะ crawl ที่เคารพ Crawl-delay ของไซต์อาจช้าได้

[หน้า batch และ crawl](https://webreaderapi.com/th/docs/crawl/) อธิบายวิธีที่ crawl เลือกหน้าและวิธีที่ `limit` จำกัดสิ่งที่อ่าน

*crawl.mjs: เริ่ม crawl และเก็บทุกหน้า*

```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);

```

## ส่งผลลัพธ์ให้โมเดลได้อย่างไร?

ส่ง Markdown ไม่ใช่ JSON ทั้งก้อน ฟิลด์ `markdown` คือสิ่งที่โมเดลควรอ่าน ส่วน metadata เหมาะเก็บไว้สำหรับการอ้างอิง ใส่ชื่อเรื่องและ `final_url` นำหน้า เพื่อให้โมเดลระบุแหล่งที่มาได้ และเก็บ `max_chars` ให้มีขนาดที่ context ของโมเดลรับได้ เช่น 20,000 ตัวอักษรต่อหน้า

[หน้า OpenAI function calling](https://webreaderapi.com/th/docs/openai/) แสดง tool loop ทั้งหมดใน Python; ฟังก์ชัน `readPage` เดียวกันด้านบนใช้เป็น tool body ใน agent Node.js ได้

## Node.js: คำถามที่พบบ่อย

### ใช้ได้กับ Deno, Bun หรือเบราว์เซอร์ไหม?

Deno และ Bun รองรับ `fetch` และ ES modules แบบเดียวกัน อย่าเรียก API จากหน้าเบราว์เซอร์ เพราะคีย์จะถูกมองเห็นโดยผู้เข้าชมทุกคน ให้เรียกจากเซิร์ฟเวอร์ของคุณแทน

### มีแพ็กเกจ npm ไหม?

ไม่มี ฟังก์ชันในหน้านี้คือการเชื่อมต่อทั้งหมด WebReaderAPI เป็น HTTPS และ JSON ธรรมดา คุณจึงควบคุม retries, timeouts และ logging ได้เอง

### จัดการ 429 concurrency_limit อย่างไร?

ลดจำนวน worker หรือ retry หลังจากรอสั้น ๆ ที่เพิ่มเป็นสองเท่าในแต่ละครั้ง 429 ไม่มีค่าใช้จ่าย และ [หน้า errors](https://webreaderapi.com/th/docs/errors/) มีฟังก์ชัน backoff พร้อมใช้

### อ่าน 10,000 หน้าเสียค่าใช้จ่ายเท่าไร?

ประมาณ 10,000 เครดิตสำหรับหน้าเว็บทั่วไป มากขึ้นหากบางหน้าต้องใช้เบราว์เซอร์ 10,000 หน้า มีค่าใช้จ่าย US$3.75; เครดิตแบบเติมเงินไม่มีวันหมดอายุ: หน้าที่ไม่ได้ใช้จะยังคงอยู่ในบัญชีของคุณจนกว่าคุณจะใช้

---

WebReaderAPI: WebReaderAPI คือ API อ่านหน้าเว็บสำหรับ AI agent ที่แปลงหน้าเว็บสาธารณะใด ๆ เป็น Markdown สะอาด จ่ายด้วยคริปโตโดยไม่ต้องอัปโหลดบัตรประชาชน เครดิตแบบเติมเงินเริ่มต้นที่ US$0.07/1K หน้า ไม่มีวันหมดอายุ และเคารพ robots.txt ไม่ต้อง KYC — ไม่ต้องใช้บัตรประชาชน ไม่ต้องเซลฟี่ ไม่ต้องเอกสาร จ่ายด้วยคริปโต
