# Da pagina web a Markdown in Node.js

> Converti pagine web in Markdown in Node.js con fetch nativo, un pool di concorrenza e polling. Da 0,07 USD/1K pagine, senza KYC, in criptovalute.

- URL: https://webreaderapi.com/it/docs/node/
- Ultimo aggiornamento: 2026-10-22
- Editore: WebReaderAPI (https://webreaderapi.com)

Node.js 18 e successivi includono `fetch`, quindi non ti serve alcuna dipendenza. Tre ricette: leggi una pagina, leggi una lista con un piccolo pool di concorrenza e segui un crawl job fino alla fine.

**Risposta rapida — Come converto una pagina web in Markdown in Node.js?**

Usa `fetch` integrato di Node.js 18+: chiama `https://webreaderapi.com/api/v1/read?url=…` con la tua chiave nell'header `Authorization` e leggi `markdown` dalla risposta JSON. **WebReaderAPI** restituisce il contenuto principale della pagina con titolo, autore e data. Una pagina costa 1 credito, 2 con un browser, da 0,07 USD/1K pagine a ottobre 2026. Senza KYC; paghi in criptovalute.

## Di cosa ho bisogno?

Node.js 18 o successivo, per il `fetch` globale, e una chiave API nella variabile d'ambiente `WEBREADER_API_KEY`. Gli esempi sono moduli ES: salvali con l'estensione `.mjs`, oppure imposta `"type": "module"` nel tuo `package.json`, così che `await` di primo livello funzioni.

I commenti JSDoc descrivono la forma della risposta, così editor come VS Code ti danno il completamento senza bisogno di una build TypeScript.

*read.mjs: una pagina*

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

```

## Come leggo una lista di URL senza superare il limite?

Esegui un numero fisso di worker che prendono gli URL da una coda condivisa. È più semplice di `Promise.all` sull'intera lista, che avvierebbe tutte le richieste insieme e farebbe scattare `429 concurrency_limit`. Ogni account ha un limite di pagine lette contemporaneamente; la tua dashboard lo mostra e il supporto può aumentarlo.

Il pool qui sotto tiene gli errori accanto ai risultati, così una pagina rifiutata non blocca l'esecuzione. Rifiuti come `blocked_by_robots` sono definitivi e gratuiti; contali e vai avanti.

*pool.mjs: una lista di URL, 8 alla volta*

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

```

## Come seguo un crawl job in Node.js?

Avvia il job con `POST https://webreaderapi.com/api/v1/crawl`, poi leggi `https://webreaderapi.com/api/v1/jobs/{job_id}` in un ciclo. Passa `cursor` ogni volta che `next_cursor` torna; quando non c'è cursor e lo status è `done`, il job è finito. Aspetta tra un polling vuoto e l'altro e raddoppia l'attesa fino a 30 secondi, perché un crawl che rispetta il Crawl-delay di un sito può essere lento.

La [pagina batch e crawl](https://webreaderapi.com/it/docs/crawl/) spiega come il crawl sceglie le pagine e come `limit` limita ciò che legge.

*crawl.mjs: avvia un crawl e raccogli ogni pagina*

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

```

## Come passo il risultato a un modello?

Invia il Markdown, non l'intero JSON. Il campo `markdown` è ciò che dovrebbe leggere un modello; i metadati è meglio tenerli per le citazioni. Anteponi titolo e `final_url`, così il modello può indicare la sua fonte, e mantieni `max_chars` a una dimensione che il contesto del tuo modello possa contenere, ad esempio 20.000 caratteri per pagina.

La [pagina OpenAI function calling](https://webreaderapi.com/it/docs/openai/) mostra l'intero tool loop in Python; la stessa funzione `readPage` qui sopra può servire da corpo del tool in un agente Node.js.

## Node.js: domande frequenti

### Funziona in Deno, Bun o nel browser?

Deno e Bun supportano lo stesso `fetch` e i moduli ES. Non chiamare l'API da una pagina del browser: la chiave sarebbe visibile a ogni visitatore. Chiamala invece dal tuo server.

### Esiste un pacchetto npm?

No. Le funzioni di questa pagina sono l'intera integrazione. WebReaderAPI è semplice HTTPS e JSON, così mantieni il controllo su retry, timeout e logging.

### Come gestisco il 429 concurrency_limit?

Riduci il numero di worker, oppure riprova dopo una breve attesa che raddoppia ogni volta. Un 429 non costa nulla, e la [pagina degli errori](https://webreaderapi.com/it/docs/errors/) ha una funzione di backoff pronta.

### Quanto costa leggere 10.000 pagine?

Circa 10.000 crediti per pagine semplici, di più se alcune richiedono un browser. 10.000 pagine costano 3,75 USD; I crediti prepagati non scadono mai: le pagine non utilizzate restano sul tuo account finché non le usi.

---

WebReaderAPI: WebReaderAPI è un'API web reader per agenti AI che converte qualsiasi pagina web pubblica in Markdown pulito, con pagamento in criptovalute e senza caricare documenti d'identità. I crediti prepagati da 0,07 USD/1K pagine non scadono mai e robots.txt viene rispettato. Senza KYC — niente documento, niente selfie, niente documenti. Paga in criptovalute.
