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

Docs · errori

Errori, rifiuti da robots.txt e retry

Ogni errore ha uno stato HTTP, un code stabile e un message leggibile. Nessuno di essi usa un credito. Alcuni meritano un retry; i rifiuti che arrivano da un sito sono definitivi, e non li aggiriamo mai.

Ultimo aggiornamento: · 6 min di lettura

Risposta rapida

Cosa significano i codici di errore di WebReaderAPI, e quali conviene riprovare?

Gli errori WebReaderAPI si dividono in tre gruppi, e nessuno viene mai addebitato. I problemi di richiesta (invalid_url, invalid_api_key, insufficient_credits) richiedono una correzione da parte tua. Le decisioni del sito (blocked_by_robots, blocked_by_site_policy, target_refused) sono definitive. I fallimenti temporanei (fetch_failed, fetch_timeout, concurrency_limit) possono essere riprovati con backoff. I crediti partono da 0,07 USD/1K pagine, pagati in criptovalute senza KYC.

Quali codici di errore può restituire l'API?

Il body è sempre {"error": {"code", "message"}}, più target_status quando il rifiuto è arrivato dal sito.

HTTPcodeCausaRiprovare?
400invalid_urlNon http o https, troppo lungo, oppure un indirizzo privato, locale o di metadata cloudNo: correggi l'URL
400invalid_parameterUn parametro ha un valore fuori dal suo elenco o intervalloNo: correggi la richiesta
401invalid_api_keyChiave mancante, errata o revocataNo: controlla la chiave
402insufficient_creditsIl tuo saldo non ha più creditiDopo aver acquistato un pack
403blocked_by_robotsIl robots.txt del sito vieta la pagina a WebReaderAPI o a tutti i robotNo: definitivo
403blocked_by_site_policyIl sito dichiara Content-Signal: ai-input=noNo: definitivo
422unsupported_contentUn tipo che non leggiamo (video, archivio) o un file troppo grandeNo
429concurrency_limitTroppe delle tue richieste sono in esecuzione nello stesso momentoSì, con backoff
502target_refusedIl sito ha rifiutato: 403, 429, una pagina di challenge o un login wall; il suo stato è in target_statusNo: definitivo
502fetch_failedErrore DNS, TLS o di connessione, oppure il sito ha risposto 404 o 410Una o due volte, con backoff
504fetch_timeoutIl sito non ha risposto entro timeoutSì, con backoff o un timeout più lungo

Perché robots.txt e i rifiuti del sito sono definitivi?

Perché sono una decisione del proprietario del sito e WebReaderAPI è costruito per rispettarla. Rispettiamo robots.txt: il nostro crawler si identifica come WebReaderAPI, segue le regole scritte per lui o per tutti i robot e non legge una pagina che un sito vieta. Le pagine rifiutate non vengono addebitate. Se un sito dichiara Content-Signal: ai-input=no nel suo robots.txt, non leggiamo le sue pagine per te.

Quando un sito rifiuta una richiesta in un altro modo, con un 403, un 429, una pagina di challenge o un modulo di login, ricevi target_refused e lo stato del sito in target_status. 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. Riprovare lo stesso URL un minuto dopo di solito dà la stessa risposta, quindi tratta questi codici come un risultato, non come un errore: registrali e vai avanti.

Come faccio a controllare perché una pagina è stata rifiutata?

Apri il /robots.txt del sito e cerca un gruppo che nomina WebReaderAPI, oppure il gruppo * che vale per tutti i robot. Una riga Disallow che corrisponde al percorso spiega un blocked_by_robots. Una riga come Content-Signal: ai-input=no spiega un blocked_by_site_policy.

Conserviamo una copia di ogni robots.txt per un massimo di 24 ore. Se un sito ha appena aperto una sezione ai robot, la modifica può richiedere fino a un giorno per essere applicata. I proprietari dei siti possono leggere come si comporta il nostro crawler e come consentirlo o bloccarlo nella nostra pagina del crawler.

Come devo riprovare i fallimenti temporanei?

Riprova solo concurrency_limit, fetch_timeout e, una o due volte, fetch_failed. Aspetta prima di ogni nuovo tentativo e raddoppia l'attesa ogni volta, con un po' di jitter casuale così i worker paralleli non riprovano insieme. Fermati dopo 4 o 5 tentativi.

Per concurrency_limit, la soluzione migliore è inviare meno richieste contemporaneamente: Ogni account ha un limite di pagine lette contemporaneamente; la tua dashboard lo mostra e il supporto può aumentarlo. Per fetch_timeout, aumenta timeout fino a 60 secondi prima di riprovare con un sito lento. I tentativi non costano nulla, perché un tentativo fallito non viene mai addebitato.

Python: riprova solo gli errori che possono cambiare
import os
import random
import time

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}
RETRY = {"concurrency_limit", "fetch_timeout", "fetch_failed"}
FINAL = {"blocked_by_robots", "blocked_by_site_policy", "target_refused", "unsupported_content"}


def read_page(url, attempts=5, **options):
    wait = 1.0
    for attempt in range(1, attempts + 1):
        resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
        if resp.status_code == 200:
            return resp.json()
        error = resp.json().get("error", {})
        code = error.get("code", "unknown")
        if code in FINAL:
            return {"url": url, "skipped": code, "target_status": error.get("target_status")}
        if code not in RETRY or attempt == attempts or (code == "fetch_failed" and attempt >= 3):
            raise RuntimeError(f"{code}: {error.get('message')}")
        time.sleep(wait + random.uniform(0, wait / 2))
        wait = min(wait * 2, 30)
    raise RuntimeError("unreachable")


if __name__ == "__main__":
    print(read_page("https://example.com/blog/first-post", max_chars=20000).get("title"))
Node.js: la stessa regola con backoff esponenziale
const RETRY = new Set(['concurrency_limit', 'fetch_timeout', 'fetch_failed']);
const FINAL = new Set(['blocked_by_robots', 'blocked_by_site_policy', 'target_refused', 'unsupported_content']);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function readPage(url, options = {}, attempts = 5) {
  let wait = 1000;
  for (let attempt = 1; attempt <= attempts; attempt++) {
    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}` },
    });
    const body = await res.json();
    if (res.ok) return body;
    const code = body.error?.code ?? 'unknown';
    if (FINAL.has(code)) return { url, skipped: code, target_status: body.error.target_status };
    if (!RETRY.has(code) || attempt === attempts) throw new Error(`${code}: ${body.error?.message}`);
    await sleep(wait + Math.random() * (wait / 2));
    wait = Math.min(wait * 2, 30000);
  }
}

E per gli errori dentro un batch o un crawl?

Un lavoro non si ferma perché una pagina fallisce. Quella pagina compare in results come {url, error} con gli stessi codici di cui sopra, e non costa nulla. Un crawling che incontra blocked_by_robots su una sezione legge semplicemente il resto del sito.

Alla fine di un lavoro, conta i codici di errore. Molti target_refused su un sito significano che il sito non accetta lettori automatizzati; molti fetch_timeout significano che è lento, e un timeout più lungo nelle opzioni del lavoro può aiutare.

Errori: domande frequenti

Mi viene addebitata una pagina bloccata da robots.txt?

No. 1 credito = 1 pagina letta senza browser; 2 crediti quando la pagina richiede un browser per eseguire JavaScript. Una richiesta che fallisce, o che il robots.txt di un sito rifiuta, non viene addebitata. Lo stesso vale per ogni altro errore in questa pagina.

Puoi leggere una pagina che blocca il tuo crawler se te lo chiedo?

No. Rispettiamo la scelta del proprietario del sito, e la policy è la stessa per ogni cliente. Se il sito è tuo, aggiungi una regola per WebReaderAPI nel tuo robots.txt; la pagina del crawler mostra come.

Perché ricevo fetch_failed per una pagina che esiste?

Il sito potrebbe essere stato giù, lento ad accettare una connessione TLS o restituire 404 ai client automatizzati. Riprova una o due volte con backoff. Se continua a fallire, controlla l'indirizzo in un browser.

Cosa dovrebbe dire il mio agente all'utente dopo un rifiuto?

Qualcosa di semplice, come che il sito non consente la lettura automatizzata di quella pagina. Poi lascia che il modello usi altre fonti. Restituire il codice di errore come risultato del tool basta per la maggior parte dei modelli.

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

Ottieni una chiave API