Wildberries 和 Ozon API 中 429 和 50x 错误的处理策略
在从 Wildberries 和 Ozon API 抓取数据时,开发者经常遇到 429(请求过多)和 50x(服务器错误)问题。这些错误通常因端点负载过重而出现。技术支持的常规解决方案是重试。我们将介绍三种实用策略:基础重试机制、优化请求量,以及带部分重载的监控。
基础重试机制
首先,将 429 和 50x 错误视为正常波动。实现带有指数退避的重试逻辑,并解析如 X-Ratelimit-Retry 等头部信息。这能有效减少封禁风险并提升系统韧性。
以下是带重试的 POST 请求示例函数:
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'!!! Network error on attempt {retries}: {e}!!!')
time.sleep(2 * retries)
continue
# 200 means success
if response.status_code == 200:
return response.json()
# 429 - Too many requests, smart pause and retry
elif response.status_code == 429:
pause_time = 2 ** retries
# X-Ratelimit-Retry - Wildberries trick, Ozon might add it someday
if 'X-Ratelimit-Retry' in response.headers:
pause_time = int(response.headers['X-Ratelimit-Retry']) + 5
print(f'get_oz: ! -Too many requests- on attempt {retries}. Pausing {pause_time} sec')
time.sleep(pause_time)
# 5xx errors - pause and retry
elif 500 <= response.status_code < 600:
pause_time = 2 ** retries
print(f'get_oz: ! -Error {response.status_code}- on attempt {retries}. Pausing {pause_time} sec')
time.sleep(pause_time)
# Any other error - bail out!
else:
print(f'get_oz: !!! API data fetch failed! code: {response.status_code}')
return None
print(f'get_oz: !!! All {max_retries} attempts failed')
return None
- 5 次重试能应对大多数常见负载。
- 在更高层处理分页循环(offset/page)。
- 完全失败时,退避 1 小时或更长。
这种机制可无缝嵌入任何 API ETL 管道。
优化数据量
大批量请求(如一周交易记录)会在后续分页时触发错误。将它们拆分成小而独立的批次:按天、类别或过滤条件。每个批次立即保存到数据库——丢失一个不会影响整体进度。
优势:
- 每个请求页数减少(1–3 页 vs. 20 页)。
- 每个批次独立重试。
- 失败时支持部分保存。
示例:按天加载 Ozon 交易记录:
date_from = today() - timedelta(days=7)
date_to = today() - timedelta(days=1)
current_date = date_from
delta = timedelta(days=1)
# Loop through days from date_from to 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'!!! Empty API response')
# If page has <1000 rows, it's the last - break
if len(dd) < 1000: break
ipage +=1
transactions_oneday = pd.DataFrame(all_pages_data)
# Export to DB right away what we got from API
export_to_db('oz_transactions', transactions_oneday)
# Next day
current_date += delta
嵌套循环看似复杂,但可靠性大幅提升。
监控与部分重载
为实现全自动化,添加安全网:后台监控。主要任务结束后(例如凌晨 6–7 点),每小时检查日志/数据库(上午 8–12 点)。
- 检查上一次任务状态。
- 验证数据完整性(日期缺口)。
- 针对缺失片段触发定向重试。
这能最大限度减少手动干预,尤其适用于日常更新。
关键要点
- 对 429 使用指数退避结合重试头部。
- 将大请求拆分成按天/过滤批次,并立即保存。
- 采集后添加小时级监控填补缺口。
- 5 次重试覆盖 95% 失败;彻底失败延时 1 小时以上。
- 无需紧密绑定分页,直接集成到 ETL。
— Editorial Team
暂无评论。