Senza KYC — niente documento, niente selfie, niente documenti. Paga in criptovalute: BTC, USDT, USDC, ETH, SOL, LTC
Lingua: Italiano
Ottieni una chiave API

Docs · jobs

API batch e crawl: leggi molti URL o un intero sito

Due endpoint avviano job in background: /batch per una lista di fino a 100 URL, /crawl per un sito web. Entrambi restituiscono un job ID; raccogli le pagine da /jobs/{job_id}, una pagina di risultati alla volta.

Ultimo aggiornamento: · 8 min di lettura

Risposta rapida

Come faccio il crawling di un sito web in Markdown con WebReaderAPI?

Invia l'URL di partenza a POST https://webreaderapi.com/api/v1/crawl con una pagina limit. WebReaderAPI legge il sito in background, solo nello stesso dominio, seguendo la sua sitemap, robots.txt e Crawl-delay, fino a 10.000 pagine per job. Raccogli le pagine Markdown dal job, una pagina di risultati alla volta. Ogni pagina letta costa 1 credito (2 con un browser), da 0,07 USD/1K pagine a partire da ottobre 2026. Senza KYC; paghi in criptovalute.

I job in breve

BatchFino a 100 URL per job batch: POST https://webreaderapi.com/api/v1/batch
CrawlCrawling di un sito web per job, fino a 10.000 pagine, seguendo la sua sitemap, il suo robots.txt e il suo Crawl-delay: POST https://webreaderapi.com/api/v1/crawl
RisultatiGET https://webreaderapi.com/api/v1/jobs/{job_id}, poi ?cursor=… per la pagina di risultati successiva
FatturazioneOgni pagina letta viene fatturata come una chiamata /read; le pagine saltate da robots.txt e le pagine fallite non costano nulla
Ambito di un crawlUn dominio; i link ad altri domini vengono elencati ma non letti
Annullare un jobNon disponibile nella v1: imposta limit sul numero massimo di pagine che sei pronto a pagare

Avviare un job batch

POST/api/v1/batch

Legge fino a 100 URL in background con le stesse opzioni. Le opzioni usano i nomi e i valori di /read. La risposta è il job ID; i valori sono illustrativi.

Autenticazione: chiave API nell'header Authorization: Bearer API_KEY.

Corpo della richiesta

CampoTipoObbligatorioDescrizione
urlsarray of stringsSìDa 1 a 100 URL http o https. I duplicati vengono letti una volta sola.
optionsobjectNoQualsiasi parametro /read tranne url: format, main_content, render, include_links, include_images, country, max_chars, timeout.
Esempio: three articles as Markdown
{
  "urls": [
    "https://example.com/blog/post-1",
    "https://example.com/blog/post-2",
    "https://example.org/news/launch"
  ],
  "options": {
    "format": "markdown",
    "max_chars": 50000
  }
}

Risposta 202 Accepted

{
  "job_id": "job_5c1e8a90d2"
}

Esempi di codice

curl
curl -s "https://webreaderapi.com/api/v1/batch" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}}'
Python
import os
import requests

resp = requests.post(
    "https://webreaderapi.com/api/v1/batch",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}},
    timeout=30,
)
print(resp.json()["job_id"])
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/batch', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ urls: ['https://example.com/blog/post-1', 'https://example.com/blog/post-2'], options: { format: 'markdown' } }),
});
console.log((await res.json()).job_id);

Avvia un job di crawling

POST/api/v1/crawl

Legge un sito web da un URL di partenza, in ampiezza. Il crawler resta sul dominio dell'URL di partenza, usa la sitemap indicata in robots.txt o trovata su /sitemap.xml, e rispetta robots.txt e Crawl-delay. I valori sono a scopo illustrativo.

Autenticazione: chiave API nell'header Authorization: Bearer API_KEY.

Corpo della richiesta

CampoTipoObbligatorioDescrizione
urlstringSìLa pagina di partenza, ad esempio la home page di un sito di documentazione.
limitintegerNoNumero massimo di pagine da leggere, fino a 10.000. Il job si ferma quando raggiunge questo numero.
max_depthintegerNoNumero massimo di passaggi di link dall'URL di partenza.
include_pathsarray of stringsNoSemplici pattern di percorso da mantenere, ad esempio /docs/*.
exclude_pathsarray of stringsNoSemplici pattern di percorso da saltare, ad esempio /blog/tag/*.
optionsobjectNoQualsiasi parametro /read tranne url, applicato a ogni pagina.
Esempio: the docs section of a site, 500 pages at most
{
  "url": "https://docs.example.com/",
  "limit": 500,
  "max_depth": 3,
  "include_paths": [
    "/docs/*"
  ],
  "exclude_paths": [
    "/docs/archive/*"
  ],
  "options": {
    "format": "markdown"
  }
}

Risposta 202 Accepted

{
  "job_id": "job_8b27f41c0e"
}

Esempi di codice

curl
curl -s "https://webreaderapi.com/api/v1/crawl" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]}'
Python
import os
import requests

resp = requests.post(
    "https://webreaderapi.com/api/v1/crawl",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]},
    timeout=30,
)
print(resp.json()["job_id"])
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/crawl', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://docs.example.com/', limit: 500, include_paths: ['/docs/*'] }),
});
console.log((await res.json()).job_id);

Ottieni lo stato e i risultati del job

GET/api/v1/jobs/{job_id}

Restituisce lo stato del job e i risultati successivi pronti. Ogni elemento di results è una risposta /read completa oppure {url, error} per una pagina che non è stato possibile leggere. Quando next_cursor è presente, richiama con cursor impostato a quel valore; quando è assente, non ci sono ancora altri risultati pronti. I valori sono a scopo illustrativo.

Autenticazione: chiave API nell'header Authorization: Bearer API_KEY.

Parametri

NomeInTipoObbligatorioDescrizione
job_idpathstringSìL'ID restituito da /batch o /crawl.
cursorquerystringNoIl valore next_cursor della chiamata precedente, per ottenere i risultati successivi.

Risposta 200

{
  "job_id": "job_8b27f41c0e",
  "status": "running",
  "results": [
    {
      "url": "https://docs.example.com/docs/install",
      "final_url": "https://docs.example.com/docs/install",
      "status_code": 200,
      "rendered": false,
      "credits_used": 1,
      "title": "Install",
      "markdown": "# Install\n\nRun the installer...",
      "word_count": 418
    },
    {
      "url": "https://docs.example.com/docs/private",
      "error": {
        "code": "blocked_by_robots",
        "message": "robots.txt disallows this page for WebReaderAPI."
      }
    }
  ],
  "next_cursor": "c_000002",
  "credits_used": 1
}

Esempi di codice

curl
curl -sG "https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -d cursor=c_000002
Python
import os
import requests

resp = requests.get(
    "https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    params={"cursor": "c_000002"},
    timeout=30,
)
job = resp.json()
print(job["status"], len(job["results"]), job.get("next_cursor"))
Node.js
const res = await fetch('https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e?cursor=c_000002', {
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
});
const job = await res.json();
console.log(job.status, job.results.length, job.next_cursor);

Come faccio ad aspettare che un job finisca?

Fai polling su /jobs/{job_id} e conserva il cursore. Elabora i risultati che ricevi, poi richiama con cursor impostato a next_cursor. Quando next_cursor è assente e status è done, hai tutto; quando è assente e il job è ancora running, aspetta e richiedi di nuovo con lo stesso cursore.

Inizia a fare polling ogni 2 secondi e raddoppia l'attesa fino a 30 secondi finché non arriva nulla di nuovo. Un crawling che rispetta il Crawl-delay di un sito può richiedere un po', quindi un'attesa lunga è normale e non costa nulla.

Python: fare polling su un job e salvare ogni pagina come file .md
import os
import pathlib
import re
import time

import requests

JOBS = "https://webreaderapi.com/api/v1/jobs"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


def save_job(job_id, folder="pages"):
    out = pathlib.Path(folder)
    out.mkdir(exist_ok=True)
    cursor, wait, saved = None, 2, 0
    while True:
        params = {"cursor": cursor} if cursor else {}
        job = requests.get(f"{JOBS}/{job_id}", headers=HEADERS, params=params, timeout=30).json()
        for item in job["results"]:
            if "error" in item:
                print("skipped", item["url"], item["error"]["code"])
                continue
            name = re.sub(r"[^a-z0-9]+", "-", item["final_url"].lower()).strip("-")[:120]
            (out / f"{name}.md").write_text(item["markdown"], encoding="utf-8")
            saved += 1
        if job.get("next_cursor"):
            cursor, wait = job["next_cursor"], 2
            continue
        if job["status"] == "done":
            return saved
        time.sleep(wait)
        wait = min(wait * 2, 30)


if __name__ == "__main__":
    print(save_job("job_8b27f41c0e"), "pages saved")

Quali pagine legge un crawling?

Un crawling parte dal tuo URL e si espande verso l'esterno un passaggio di link alla volta, in ampiezza, fino a max_depth. Legge anche la sitemap del sito, dall'indirizzo indicato in robots.txt o da /sitemap.xml, per trovare pagine verso cui puntano pochi link.

  • Solo lo stesso dominio. I link ad altri domini sono elencati nei risultati quando richiedi include_links, ma non vengono letti.
  • Filtri di percorso. include_paths e exclude_paths accettano semplici pattern come /blog/*.
  • Una copia per pagina. Quando un sito dichiara un URL canonico, una pagina raggiunta tramite più indirizzi viene letta una volta sola.
  • Un limite invalicabile. Il job termina quando ha letto limit pagine.

Come rispetta il sito un crawling?

Ogni richiesta porta lo User-Agent WebReaderAPI/1.0 (+https://webreaderapi.com/bot/), e il crawler segue le regole di robots.txt per WebReaderAPI, o per tutti i robot quando nessuno lo nomina. Le pagine non consentite vengono saltate e compaiono in results con l'errore blocked_by_robots; non costano nulla.

Quando robots.txt imposta un Crawl-delay, il crawler attende quel tempo tra due richieste al sito. Se un sito dichiara Content-Signal: ai-input=no nel suo robots.txt, non leggiamo le sue pagine per te. Se un sito rifiuta la nostra richiesta, restituiamo la sua risposta: non risolviamo mai CAPTCHA, non accediamo agli account e non tentiamo di aggirare un blocco o un paywall.

Quanto costa un crawling?

Ogni pagina letta costa quanto una chiamata /read: 1 credito, 2 se la pagina ha richiesto un browser, più 10 con country. Le pagine saltate e quelle non riuscite sono gratuite. Il credits_used del job somma quanto è stato addebitato finora.

Un sito di documentazione di 500 pagine letto senza browser usa circa 500 crediti, che il pack 10.000 pagine (3,75 USD) copre molte volte. Poiché in v1 un job non può essere annullato, limit è il tuo tetto di spesa: impostalo al numero massimo di pagine che sei disposto a pagare.

Batch e crawling: domande frequenti

Devo usare /batch o molte chiamate /read?

Usa /batch quando hai già gli URL e non ti serve ogni risposta subito. Ti evita di gestire concorrenza e retry. Usa /read quando un agente ha bisogno di una pagina adesso.

Per quanto tempo vengono conservati i risultati di un job?

Raccoglili appena sono pronti. I risultati restano in attesa finché non li recuperi; una volta consegnati, non viene conservata alcuna copia del contenuto della pagina, quindi salva sul tuo lato ciò che ti serve.

No. Un crawling legge un solo dominio. Gli altri domini compaiono come link quando li richiedi, e puoi inviare quegli URL a /batch se vuoi che vengano letti.

Posso fermare un crawling già avviato?

Non in v1. Il job si ferma a limit pagine, quindi scegli un limite adeguato al tuo budget. Le pagine già lette restano fatturate; le pagine mai lette non costano nulla.

Da 0,07 USD/1K pagine · senza KYC

Ottieni una chiave API