Bez KYC — bez dowodu, bez selfie, bez dokumentów. Płatność kryptowalutą: BTC, USDT, USDC, ETH, SOL, LTC
Język: Polski
Uzyskaj klucz API

Dokumentacja · błędy

Błędy, odmowy robots.txt i ponowienia

Każdy błąd ma status HTTP, stabilny code i czytelny message. Żaden z nich nie zużywa kredytu. Niektóre warto ponowić; odmowy pochodzące z witryny są ostateczne i nigdy ich nie obchodzimy.

Ostatnia aktualizacja: · 5 min czytania

Szybka odpowiedź

Co oznaczają kody błędów WebReaderAPI i które warto ponowić?

Błędy WebReaderAPI występują w trzech grupach i żaden nigdy nie jest rozliczany. Problemy z zapytaniem (invalid_url, invalid_api_key, insufficient_credits) wymagają poprawki po Twojej stronie. Decyzje witryny (blocked_by_robots, blocked_by_site_policy, target_refused) są ostateczne. Przejściowe awarie (fetch_failed, fetch_timeout, concurrency_limit) można ponowić z backoffem. Kredyty zaczynają się od 0,07 USD/1K stron, płatne kryptowalutą bez KYC.

Które kody błędów może zwrócić API?

Treść to zawsze {"error": {"code", "message"}}, plus target_status, gdy odmowa pochodziła z witryny.

HTTPcodePrzyczynaPonowić?
400invalid_urlNie jest to http ani https, adres jest zbyt długi albo to prywatny, lokalny lub chmurowy adres metadanychNie: popraw URL
400invalid_parameterParametr ma wartość poza swoją listą lub zakresemNie: popraw zapytanie
401invalid_api_keyKlucz brakuje, jest błędny lub unieważnionyNie: sprawdź klucz
402insufficient_creditsNa Twoim saldzie nie ma już kredytówPo zakupie pakietu
403blocked_by_robotsrobots.txt strony nie zezwala na tę stronę dla WebReaderAPI ani dla wszystkich robotówNie: ostatecznie
403blocked_by_site_policyStrona deklaruje Content-Signal: ai-input=noNie: ostatecznie
422unsupported_contentTyp, którego nie odczytujemy (wideo, archiwum), albo plik zbyt dużyNie
429concurrency_limitZbyt wiele Twoich zapytań działa jednocześnieTak, z backoffem
502target_refusedStrona odmówiła: 403, 429, strona wyzwania lub ściana logowania; jej status jest w target_statusNie: ostatecznie
502fetch_failedBłąd DNS, TLS lub połączenia albo strona odpowiedziała 404 lub 410Raz lub dwa razy, z backoffem
504fetch_timeoutStrona nie odpowiedziała w ciągu timeoutTak, z backoffem lub dłuższym timeoutem

Dlaczego robots.txt i odmowy strony są ostateczne?

Bo to decyzja właściciela strony, a WebReaderAPI jest zbudowany tak, by ją respektować. Respektujemy robots.txt: nasz crawler identyfikuje się jako WebReaderAPI, przestrzega reguł napisanych dla niego lub dla wszystkich robotów i nie czyta strony, której witryna zabrania. Odrzucone strony nie są obciążane opłatą. Jeśli witryna zadeklaruje Content-Signal: ai-input=no w swoim robots.txt, nie czytamy jej stron dla Ciebie.

Gdy strona odrzuca zapytanie w inny sposób — przez 403, 429, stronę wyzwania lub formularz logowania — otrzymujesz target_refused i własny status strony w target_status. Jeśli witryna odrzuci nasze zapytanie, zwracamy jej odpowiedź: nigdy nie rozwiązujemy CAPTCHA, nie logujemy się do kont ani nie próbujemy obejść blokady lub paywalla. Ponowna próba tego samego URL-a minutę później zwykle da tę samą odpowiedź, więc traktuj te kody jako wynik, a nie błąd: zapisz je w logach i idź dalej.

Jak sprawdzić, dlaczego strona została odrzucona?

Otwórz /robots.txt strony i poszukaj grupy, która wymienia WebReaderAPI, albo grupy *, która dotyczy wszystkich robotów. Linia Disallow pasująca do ścieżki wyjaśnia blocked_by_robots. Linia taka jak Content-Signal: ai-input=no wyjaśnia blocked_by_site_policy.

Trzymamy kopię każdego robots.txt przez maksymalnie 24 godziny. Jeśli strona właśnie otworzyła sekcję dla robotów, zmiana może zacząć obowiązywać dopiero po upływie dnia. Właściciele stron mogą przeczytać, jak zachowuje się nasz crawler i jak go dozwolić lub zablokować, na naszej stronie o crawlerze.

Jak ponawiać przejściowe błędy?

Ponawiaj tylko concurrency_limit, fetch_timeout i raz lub dwa razy fetch_failed. Przed każdą nową próbą odczekaj i za każdym razem podwajaj czas oczekiwania, z odrobiną losowego jittera, żeby równolegli workerzy nie ponawiali jednocześnie. Zatrzymaj się po 4 lub 5 próbach.

W przypadku concurrency_limit lepszym rozwiązaniem jest wysyłanie mniejszej liczby zapytań naraz: Każde konto ma limit liczby stron czytanych jednocześnie; Twój dashboard go pokazuje, a support może go podnieść. W przypadku fetch_timeout zwiększ timeout do 60 sekund, zanim ponowisz próbę dla wolnej strony. Ponowienia nic nie kosztują, bo nieudana próba nigdy nie jest rozliczana.

Python: ponawiaj tylko błędy, które mogą się zmienić
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: ta sama zasada z wykładniczym backoffem
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);
  }
}

Co z błędami wewnątrz batcha lub crawlu?

Zadanie nie zatrzymuje się, bo jedna strona zawiodła. Ta strona pojawia się w results jako {url, error} z tymi samymi kodami co powyżej i nic nie kosztuje. Crawling, który napotka blocked_by_robots w sekcji, po prostu czyta resztę witryny.

Na końcu zadania policz kody błędów. Wiele target_refused w jednej witrynie oznacza, że witryna nie akceptuje zautomatyzowanych czytników; wiele fetch_timeout oznacza, że jest wolna, a dłuższy timeout w opcjach zadania może pomóc.

Błędy: najczęstsze pytania

Czy płacę za stronę blokowaną przez robots.txt?

Nie. 1 kredyt = 1 odczytana strona bez przeglądarki; 2 kredyty, gdy strona wymaga przeglądarki do wyrenderowania JavaScript. Zapytanie, które się nie powiedzie lub które zostanie odrzucone przez robots.txt witryny, nie jest obciążane opłatą. To samo dotyczy każdego innego błędu na tej stronie.

Czy możecie odczytać stronę, która blokuje wasz crawler, jeśli o to poproszę?

Nie. Respektujemy wybór właściciela witryny, a polityka jest taka sama dla każdego klienta. Jeśli jesteś właścicielem witryny, dodaj regułę dla WebReaderAPI w swoim robots.txt; strona crawlera pokazuje jak.

Dlaczego dostaję fetch_failed dla strony, która istnieje?

Witryna mogła być niedostępna, wolno akceptować połączenie TLS lub zwracać 404 zautomatyzowanym klientom. Ponów próbę raz lub dwa z backoffem. Jeśli nadal się nie udaje, sprawdź adres w przeglądarce.

Co mój agent powinien powiedzieć użytkownikowi po odmowie?

Coś prostego, np. że witryna nie pozwala na zautomatyzowane odczytywanie tej strony. Następnie pozwól modelowi skorzystać z innych źródeł. Zwrócenie kodu błędu jako wyniku narzędzia wystarcza większości modeli.

Od 0,07 USD/1K stron · bez KYC

Uzyskaj klucz API