Obsługa błędów 429 i 50x przy pracy z API Wildberries i Ozon
Podczas parsowania danych z API Wildberries i Ozon programiści często napotykają błędy 429 (zbyt wiele żądań) i 50x (błędy serwerowe). Te problemy powstają z powodu wysokiego obciążenia endpointów. Standardowa odpowiedź wsparcia technicznego — skonfigurować ponowne próby. Rozważmy trzy podejścia: podstawową obsługę z powtórzeniami, optymalizację ilości żądań oraz monitorowanie z doładowaniem.
Podstawowa obsługa ponownych prób
Pierwszy krok — traktować 429 i 50x jako oczekiwane zdarzenia. Zaimplementuj logikę ponawiania z wykładniczymi przerwami i czytaniem nagłówków takich jak X-Ratelimit-Retry. To minimalizuje blokadę i zwiększa odporność.
Przykład funkcji dla żądania POST z ponownymi próbami:
def get_oz(url, heads, params, max_retries=5, timeout=30):
result = {}
for retries in range(1, max_retries + 1):
try:
response = requests.post(url, headers=heads, json=params, timeout=timeout)
except requests.RequestException as e:
print(f'!!! Błąd sieciowy w próbie {retries}: {e}!!!')
time.sleep(2 * retries)
continue
# Kod 200 otrzymano prawidłową odpowiedź
if response.status_code == 200:
return response.json()
# Kod 429 - Zbyt wiele żądań, robimy inteligentną przerwę i ponownie żądamy
elif response.status_code == 429:
pause_time = 2 ** retries
# X-Ratelimit-Retry - cecha WB, ale może i OZ kiedyś wprowadzi
if 'X-Ratelimit-Retry' in response.headers:
pause_time = int(response.headers['X-Ratelimit-Retry']) + 5
print(f'get_oz: ! -Zbyt wiele żądań- w próbie {retries}. Przerwa {pause_time} sek')
time.sleep(pause_time)
# Przy błędzie 5xx przez przerwę przechodzimy do następnej próby
elif 500 <= response.status_code < 600:
pause_time = 2 ** retries
print(f'get_oz: ! -Błąd {response.status_code}- w próbie {retries}. Przerwa {pause_time} sek')
time.sleep(pause_time)
# Jeśli inny błąd - wychodzimy z cyklu!
else:
print(f'get_oz: !!! Błąd pobierania danych przez API! code: {response.status_code}')
return None
print(f'get_oz: !!! Wszystkie {max_retries} próby zawiodły')
return None
- 5 ponownych prób zwykle wystarczy dla typowych obciążeń.
- Cykl paginacji (offset/strona) przenieś na wyższy poziom.
- Przy całkowitej porażce odłóż na godzinę+.
Ta logika integruje się w dowolny potok ETL dla API.
Optymalizacja ilości danych
Duże żądania (np. transakcje z tygodnia) prowokują błędy na późnych stronach paginacji. Dziel na małe niezależne partie: po dniach, po kategoriach lub po filtrach. Zapisz każdą partię od razu w bazie danych — utrata jednej porcji nie resetuje całego postępu.
Zalety:
- Mniej stron na żądanie (1–3 zamiast 20).
- Niezależne ponowne próby po partiach.
- Częściowe zapisywanie przy awariach.
Przykład ładowania transakcji Ozon po dniach:
date_from = today() - timedelta(days=7)
date_to = today() - timedelta(days=1)
current_date = date_from
delta = timedelta(days=1)
#przechodzimy przez dni od date_from do date_to
while current_date <= date_to:
transactions_oneday = pd.DataFrame([])
url = "https://api-seller.ozon.ru/v3/finance/transaction/list"
ipage = 1
all_pages_data = []
while True:
data = {
"filter": {
"date": {
"from": str(current_date) + "T00:00:00.000Z",
"to": str(current_date) + "T23:59:59.999Z"
}
},
"page": ipage,
"page_size": 1000
}
dd = []
apioz_response = get_oz(url, headers, data, 5)
if len(apioz_response) > 0 :
dd = apioz_response['result']['operations']
all_pages_data.extend(dd)
else:
print(f'!!! Pusta odpowiedź od API')
# jeśli na stronie mniej niż 1000 wierszy - to ostatnia, wychodzimy z cyklu
if len(dd) < 1000: break
ipage +=1
transactions_oneday = pd.DataFrame(all_pages_data)
#natychmiast eksportujemy do bazy, co otrzymaliśmy z API
export_to_db('oz_transactions', transactions_oneday)
#przechodzimy do następnego dnia
current_date += delta
Mimo zagnieżdżonych cykli, niezawodność rośnie wykładniczo.
Monitorowanie i doładowanie
Dla pełnej automatyzacji dodaj "kołek" — tło monitorujące. Po głównym uruchomieniu (np. o 6–7 rano) sprawdzaj logi/bazę danych co godzinę (8–12 rano).
- Analizuj status ostatniego zadania.
- Sprawdź integralność danych (luki w datach).
- Uruchamiaj ukierunkowane ponowne próby tylko dla braków.
To redukuje ręczne interwencje do minimum, szczególnie przy dziennych aktualizacjach.
Co jest ważne
- Używaj wykładniczego backoff z nagłówkami retry dla 429.
- Dziel duże żądania na partie po dniach/filtrach z natychmiastowym zapisywaniem.
- Wprowadzaj godzinne monitorowanie po głównym zbiorze dla uzupełnienia.
- 5 ponownych prób pokrywa 95% awarii; całkowite porażki odłóż na godzinę+.
- Integruj w ETL bez sztywnych zależności od paginacji.
— Editorial Team
Brak komentarzy.