Không cần KYC — không ID, không selfie, không giấy tờ. Thanh toán bằng crypto: BTC, USDT, USDC, ETH, SOL, LTC
Ngôn ngữ: Tiếng Việt
Lấy khóa API

Tài liệu · Node.js

Chuyển trang web sang Markdown trong Node.js

Node.js 18 trở lên đã có sẵn fetch, nên bạn không cần cài thêm dependency nào. Ba công thức: đọc một trang, đọc một danh sách với pool concurrency nhỏ, và theo dõi một crawl job cho đến khi xong.

Cập nhật lần cuối: · 4 phút đọc

Câu trả lời nhanh

Làm sao để chuyển một trang web sang Markdown trong Node.js?

Dùng fetch có sẵn của Node.js 18+: gọi https://webreaderapi.com/api/v1/read?url=… với khóa API của bạn trong header Authorization và đọc markdown từ câu trả lời JSON. WebReaderAPI trả về nội dung chính của trang kèm tiêu đề, tác giả và ngày. Một trang tốn 1 credit, 2 credit nếu dùng trình duyệt, từ 0,07 US$/1K trang tính đến tháng 10 năm 2026. Không cần KYC; thanh toán bằng crypto.

Tôi cần gì?

Node.js 18 trở lên, để có fetch toàn cục, và một khóa API trong biến môi trường WEBREADER_API_KEY. Các ví dụ là ES module: lưu chúng với đuôi .mjs, hoặc đặt "type": "module" trong package.json của bạn, để await ở cấp cao nhất hoạt động được.

Các chú thích JSDoc mô tả cấu trúc của response, nên các editor như VS Code sẽ gợi ý hoàn thành mà không cần đến bước build TypeScript.

read.mjs: một trang
/**
 * @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)');

Làm sao để đọc một danh sách URL mà không chạm rate limit?

Chạy một số lượng worker cố định lấy URL từ một hàng đợi chung. Cách này đơn giản hơn Promise.all trên toàn bộ danh sách, vì làm vậy sẽ khởi chạy mọi request cùng lúc và chạm 429 concurrency_limit. Mỗi tài khoản có giới hạn số trang đọc cùng lúc; dashboard của bạn hiển thị giới hạn đó, và bộ phận hỗ trợ có thể tăng lên.

Pool bên dưới giữ lỗi ngay cạnh kết quả, nên một trang bị từ chối không làm dừng cả lượt chạy. Những lần bị từ chối như blocked_by_robots là chung thẩm và miễn phí; hãy đếm chúng rồi đi tiếp.

pool.mjs: một danh sách URL, 8 cái một lúc
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);

Làm sao để theo dõi một crawl job trong Node.js?

Khởi động job bằng POST https://webreaderapi.com/api/v1/crawl, rồi đọc https://webreaderapi.com/api/v1/jobs/{job_id} trong một vòng lặp. Truyền cursor mỗi lần next_cursor trả về; khi không còn cursor và trạng thái là done, job đã xong. Hãy chờ giữa các lần poll rỗng và tăng gấp đôi thời gian chờ tối đa 30 giây, vì một crawl tôn trọng Crawl-delay của trang có thể chậm.

Trang batch và crawl mô tả cách crawl chọn trang và cách limit giới hạn những gì nó đọc.

crawl.mjs: khởi động một crawl và thu thập mọi trang
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);

Làm sao để truyền kết quả cho model?

Gửi Markdown, không phải toàn bộ JSON. Trường markdown là thứ model nên đọc; phần metadata thì nên giữ để trích dẫn nguồn. Thêm tiêu đề và final_url vào đầu, để model có thể nêu nguồn, và giữ max_chars ở kích thước mà context của model chứa được, ví dụ 20.000 ký tự mỗi trang.

Trang OpenAI function-calling trình bày đầy đủ vòng lặp tool bằng Python; chính hàm readPage ở trên cũng có thể làm thân tool trong một agent Node.js.

Node.js: các câu hỏi thường gặp

Cái này có chạy trong Deno, Bun hay trình duyệt không?

Deno và Bun hỗ trợ cùng fetch và ES module. Đừng gọi API từ trang trình duyệt: khóa API sẽ lộ cho mọi người truy cập. Hãy gọi từ server của bạn.

Có package npm không?

Không. Các hàm trên trang này là toàn bộ phần tích hợp. WebReaderAPI chỉ là HTTPS và JSON thuần, nên bạn giữ được quyền kiểm soát retry, timeout và logging.

Làm sao để xử lý lỗi 429 concurrency_limit?

Giảm số worker, hoặc retry sau một khoảng chờ ngắn tăng gấp đôi mỗi lần. Lỗi 429 không tốn gì, và trang errors có sẵn một hàm backoff.

Đọc 10.000 trang tốn bao nhiêu?

Khoảng 10.000 credit cho các trang thường, nhiều hơn nếu một số trang cần dùng trình duyệt. 10.000 trang tốn 3,75 US$; Credit trả trước không bao giờ hết hạn: số trang chưa dùng vẫn ở trong tài khoản của bạn cho đến khi bạn dùng.

Từ 0,07 US$/1K trang · không cần KYC

Lấy khóa API