คำตอบสั้น
แปลงหน้าเว็บเป็น 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
/**
* @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 เป็นขั้นสุดท้ายและไม่มีค่าใช้จ่าย นับแล้วไปต่อ
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 อธิบายวิธีที่ crawl เลือกหน้าและวิธีที่ limit จำกัดสิ่งที่อ่าน
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 แสดง 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 มีฟังก์ชัน backoff พร้อมใช้
อ่าน 10,000 หน้าเสียค่าใช้จ่ายเท่าไร?
ประมาณ 10,000 เครดิตสำหรับหน้าเว็บทั่วไป มากขึ้นหากบางหน้าต้องใช้เบราว์เซอร์ 10,000 หน้า มีค่าใช้จ่าย US$3.75; เครดิตแบบเติมเงินไม่มีวันหมดอายุ: หน้าที่ไม่ได้ใช้จะยังคงอยู่ในบัญชีของคุณจนกว่าคุณจะใช้