Eksporty i zadania asynchroniczne
Trzy różne sposoby wyciągania danych z API — mylenie ich to najczęstsza przyczyna timeoutów przy „dużych pobraniach”.
| Tryb | Kiedy | Co dostajesz |
|---|---|---|
| Raport synchroniczny | domyślnie, większość endpointów | JSON w odpowiedzi, stronicowany (paginacja) |
| Zadanie asynchroniczne | narzędzia SERP (crawl SERP-a, TOP100, listy URL-i) | task_id od razu, dane po zakończeniu zadania |
| Eksport plikowy | gdy chcesz plik zamiast JSON-a | CSV/plik do pobrania, bez koperty {success, data} |
Nie ma ogólnego mechanizmu „zleć raport i odbierz później”. Zwykłe raporty
(np. positions/getData, dashboard/getDomainStatistics) liczą się w trakcie żądania —
nie zwracają identyfikatora zadania i nie da się ich zakolejkować. Duże pobranie dzielisz
paginacją i zakresem dat, a nie zleceniem w tle. Kolejkowanie istnieje wyłącznie
w rodzinach tasks/management/* opisanych niżej.
Jak rozpoznać, w którym trybie działa Twój endpoint
Tryb rozpoznasz po ścieżce i wymaganych parametrach:
| Sygnał w endpoincie | Tryb | Co to znaczy |
|---|---|---|
ścieżka zaczyna się od /api/tasks/management/… | zadanie asynchroniczne | create zwraca task_id, wyniki odbierasz po check |
endpoint wymaga task_id w parametrach | odbiór wyników zadania | zadanie musi być już zakończone |
w ścieżce jest segment exports | eksport plikowy | odpowiedzią jest plik (CSV), nie JSON |
| nic z powyższych | raport synchroniczny | dane liczą się w trakcie żądania; brak job ID i brak kolejkowania |
Innymi słowy: job ID istnieje wyłącznie w trzech rodzinach tasks/management/* wymienionych niżej.
Jeśli Twojego endpointu tam nie ma i nie przyjmuje task_id, to nie da się go „zlecić i odebrać
później” — zostaje paginacja, zawężenie zakresu albo eksport plikowy.
1. Duże pobranie z raportu synchronicznego
Gdy raport przerywa się timeoutem (data.error.type = "timeout" — patrz Błędy),
zawężaj żądanie, zamiast je ponawiać w tej samej postaci:
- Stronicuj.
limit+page; łączną liczbę wierszy podajepagination.count, apagination.has_next_pagemówi, kiedy przestać. Maksymalnylimitzależy od endpointu (często 100) — wyższa wartość to418, nie szybsze pobranie. - Tnij zakres dat. Raporty historyczne (
date_min/date_max) kosztują tym więcej, im szerszy zakres i im większa domena. Miesiąc po miesiącu przechodzi tam, gdzie rok naraz się wywraca. - Ogranicz zbiór na wejściu.
filteringpo stronie API jest tańsze niż pobranie wszystkiego i filtrowanie u siebie. - Rozważ eksport plikowy (sekcja 3) — dla tych samych danych zwraca CSV jednym żądaniem, bez składania stron.
Odpowiedź 200 z pustym data: [] to nie timeout ani błąd — dla tej domeny i tego zakresu
po prostu nie ma danych. Sprawdź fetch_mode, zakres dat i pisownię domeny.
2. Zadania asynchroniczne (tasks/management/*)
Narzędzia, które muszą najpierw zebrać dane z Google, działają w cyklu
create → check (polling) → odbiór wyników. create zwraca task_id natychmiast;
dane pojawiają się dopiero, gdy zadanie się zakończy.
| Rodzina | create | check | Wyniki |
|---|---|---|---|
| Analiza SERP | POST /api/tasks/management/serp_analysis/create | GET …/serp_analysis/check | raporty serp_analysis/reports/* |
| TOP100 crawl | POST /api/tasks/management/top100_crawl/create | GET …/top100_crawl/check | top100_crawl/getData lub eksport CSV |
| URLs crawl | POST /api/tasks/management/urls_crawl/create | GET …/urls_crawl/check | urls_crawl/getList lub eksport CSV |
Skąd wiadomo, że zadanie jest gotowe
check przyjmuje task_id w query stringu i zwraca obiekt zadania. Sygnał gotowości
różni się między rodzinami — dlatego czytaj konkretne pole, a nie „jakikolwiek status”:
- Analiza SERP —
progress.has_serp_data = true(crawl SERP gotowy) orazprogress.has_keywords_analysis_data = true(dane Bazy słów gotowe). Odpytanie raportu wcześniej zwraca błąd walidacjiUnfinished task. - TOP100 / URLs crawl —
status = "completed"(świeżo utworzone zadanie mawaiting) orazprogress = {all, finished, unfinished}, po którym widać postęp.
Czas realizacji zależy od rodzaju i wielkości zadania — od minut po godziny. Nie zakładaj
stałej wartości: odpytuj check w odstępach (np. co 30–60 s) i przerwij po własnym limicie czasu.
Przechowuj task_id
create zwraca identyfikator tylko raz — zapisz go po swojej stronie. Zadanie nie wygasa:
raporty zakończonego zadania odpytasz również następnego dnia, bez tworzenia nowego i bez
konsumpcji limitu. Zgubiony task_id oznacza zlecenie analizy od nowa, czyli kolejną jednostkę limitu.
Szkic pętli
Python
import time, requests
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
BASE = "https://api.senuto.com"
# 1. zlecenie zadania — zużywa limit narzędzi (tools_daily_limit)
task = requests.post(f"{BASE}/api/tasks/management/top100_crawl/create",
headers=H, json={"keywords": ["buty"], "country_id": 1}).json()
task_id = task["data"]["id"]
# 2. polling — task_id w QUERY STRINGU, nie w ciele
deadline = time.time() + 3600
while time.time() < deadline:
state = requests.get(f"{BASE}/api/tasks/management/top100_crawl/check",
headers=H, params={"task_id": task_id}).json()["data"]
if state["status"] == "completed":
break
time.sleep(60)
else:
raise TimeoutError(f"zadanie {task_id} nie zdążyło — sprawdź je później przez /list")
# 3. odbiór wyników
rows = requests.post(f"{BASE}/api/serp_analysis/tools/top100_crawl/getData",
headers=H, json={"task_id": task_id, "limit": 100, "page": 1}).json()create zużywa limit — serp_analysis_daily_limit dla Analizy SERP,
tools_daily_limit (plus limit wejściowy narzędzia) dla crawlów. check, list i odczyt
wyników limitu nie zużywają, więc polling jest bezpieczny — podobnie jak ponowienie create
po timeoucie (Ponowienia po timeoucie). Stan liczników:
GET /api/users/getLimits.
3. Eksporty plikowe (CSV)
Endpointy z segmentem exports zwracają plik, nie kopertę JSON — nie mają playgroundu
i nie parsuj ich jak zwykłej odpowiedzi. Przydają się tam, gdzie alternatywą jest przejście
przez kilkadziesiąt stron paginacji.
| Moduł | Endpoint | Zawartość |
|---|---|---|
| Analiza SERP | POST /api/serp_analysis/tools/exports/top100_crawl/getData | wyniki zadania TOP100 crawl |
| Analiza SERP | POST /api/serp_analysis/tools/exports/urls_crawl/getList | wyniki zadania URLs crawl |
| Baza słów kluczowych | POST /api/keywords_analysis/tools/exports/statistics/getKeywords | frazy z raportu statystyk |
Eksporty narzędziowe (tools/exports/*) zużywają tools_daily_limit — tak samo jak
wywołanie samego narzędzia. Powtórzenie tego samego eksportu w ciągu 24 h już nie nalicza
kolejnej jednostki (patrz Ponowienia po timeoucie), ale eksport
z innym zestawem parametrów to nowa jednostka.
Ponowienia po timeoucie
Timeout po stronie klienta nie mówi, czy operacja wykonała się po stronie Senuto. Nie ma nagłówka
Idempotency-Key — i nie jest potrzebny, bo każdy z trzech trybów ma własny sposób bezpiecznego
ponowienia. Wybierz właściwy dla swojego endpointu:
| Tryb | Jak sprawdzić, czy operacja przeszła | Czy ponowienie kosztuje |
|---|---|---|
| Raport synchroniczny | usage w GET /api/users/getLimits; dla domeny w Analizie widoczności — checkQuery | Nie — identyczne zapytanie w oknie 24 h trafia w Grace Window (szczegóły) |
Zadanie async (tasks/management/*) | …/list — zwraca wszystkie zadania konta z ich task_id i statusami | Analiza SERP: nie (create zwraca istniejące zadanie dla tej samej frazy i kraju). Crawle: powstanie nowe zadanie, ale tools_daily_limit nie naliczy się drugi raz dla identycznego payloadu w 24 h |
Narzędzie z public_id (KA statistics/create) | brak listy — public_id odzyskasz tylko z odpowiedzi, checkData sprawdza znany public_id | Nie dla identycznego payloadu w oknie 24 h, ale wynik dostaniesz pod nowym public_id |
| Eksport plikowy | brak — to zwykłe pobranie pliku | Nie dla powtórzenia tego samego eksportu w 24 h |
Zasady, które warto zaszyć w kliencie:
- Retry wysyłaj bajt w bajt. Klucz Grace Window liczy się z parametrów żądania, więc zmieniona
kolejność fraz w
keywordsalbo dorzucony opcjonalny parametr tworzy nową jednostkę limitu. - Zanim ponowisz
createzadania — zajrzyj dolist. To najtańszy sposób ustalenia, czy zadanie już istnieje, i jedyny sposób odzyskania zgubionegotask_id. public_idzapisuj natychmiast po odebraniu odpowiedzi. Jest generowany losowo i nie ma endpointu, który wylistuje wyniki narzędzi konta — utraconypublic_idoznacza ponowne wywołaniecreate(kosztowo bezpieczne w oknie 24 h, ale wynik dostaniesz pod nowym identyfikatorem).- Podnieś timeout, zamiast ponawiać agresywnie. Ciężkie wywołania (
createz kilkuset frazami, szerokie raporty historyczne) potrafią liczyć się minutami — ustaw timeout klienta rzędu 120 s. - Dwie operacje naliczają się przy każdym wywołaniu i nie mają Grace Window:
refreshw Analizie SERP oraz ręczne odświeżanie pozycji w Monitoringu. Tutaj retry realnie kosztuje.
Co dalej
- Paginacja —
limit,pagei polepagination. - Limity zapytań — które liczniki zużywają zadania i eksporty.
- Błędy —
timeout,418i pozostałe kategorie. - Analiza SERP — pełny opis rodzin zadań i raportów.