와일드베리즈·오존 API에서 429·50x 오류 처리하기
와일드베리즈와 오존 API에서 데이터를 스크래핑할 때 개발자들은 자주 429(요청 과다)와 50x(서버 오류)에 부딪힙니다. 엔드포인트에 과부하가 걸려 이런 문제가 발생하죠. 기술 지원팀의 단골 처방은 재시도입니다. 이번 글에서는 기본 재시도 처리, 요청량 최적화, 부분 재로드 모니터링 등 세 가지 확실한 전략을 다뤄보겠습니다.
기본 재시도 처리
429와 50x 오류를 예상치 못한 사고가 아닌 정상적인 일시적 장애로 다루세요. 지수 백오프(exponential backoff)와 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'!!! 네트워크 오류 재시도 {retries}: {e}!!!')
time.sleep(2 * retries)
continue
# 200은 성공
if response.status_code == 200:
return response.json()
# 429 - 요청 과다, 똑똑한 대기 후 재시도
elif response.status_code == 429:
pause_time = 2 ** retries
# X-Ratelimit-Retry - 와일드베리즈 팁, 오존도 언젠가 추가할 듯
if 'X-Ratelimit-Retry' in response.headers:
pause_time = int(response.headers['X-Ratelimit-Retry']) + 5
print(f'get_oz: ! -요청 과다- 재시도 {retries}. {pause_time}초 대기')
time.sleep(pause_time)
# 5xx 오류 - 대기 후 재시도
elif 500 <= response.status_code < 600:
pause_time = 2 ** retries
print(f'get_oz: ! -오류 {response.status_code}- 재시도 {retries}. {pause_time}초 대기')
time.sleep(pause_time)
# 기타 오류 - 포기!
else:
print(f'get_oz: !!! API 데이터 수집 실패! 코드: {response.status_code}')
return None
print(f'get_oz: !!! {max_retries}회 모두 실패')
return None
- 5회 재시도로 대부분의 일반 부하를 커버합니다.
- 페이지네이션 루프(offset/page)는 상위 레벨에서 처리하세요.
- 완전 실패 시 1시간 이상 백오프하세요.
이 로직은 어떤 ETL 파이프라인에도 바로 끼워넣을 수 있습니다.
데이터량 최적화
한 주 거래 내역 같은 대용량 요청은 뒤쪽 페이지에서 오류가 발생합니다. 이를 하루 단위, 카테고리별, 필터별로 작은 독립 배치로 쪼개세요. 각 배치를 즉시 DB에 저장하면 하나 실패해도 전체가 날아가지 않습니다.
장점:
- 요청당 페이지 수 감소(20개 → 1~3개).
- 배치별 독립 재시도.
- 실패 시 부분 저장.
예시: 오존 거래 내역을 하루씩 불러오기
date_from = today() - timedelta(days=7)
date_to = today() - timedelta(days=1)
current_date = date_from
delta = timedelta(days=1)
# date_from부터 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'!!! 빈 API 응답')
# 페이지에 1000개 미만이면 마지막 - 종료
if len(dd) < 1000: break
ipage +=1
transactions_oneday = pd.DataFrame(all_pages_data)
# API에서 받은 데이터 즉시 DB 내보내기
export_to_db('oz_transactions', transactions_oneday)
# 다음 날
current_date += delta
중첩 루프가 복잡해 보일 수 있지만, 신뢰성은 폭발적으로 올라갑니다.
모니터링과 부분 재로드
완전 자동화를 위해 안전장치를 더하세요: 백그라운드 모니터링. 메인 실행(새벽 6~7시) 후 로그/DB를 매시간 확인(오전 8~12시).
- 최근 작업 상태 검토.
- 데이터 무결성 확인(날짜 공백).
- 누락 청크만 타겟 재시도.
이렇게 하면 수동 수정이 최소화되며, 특히 매일 업데이트에 유리합니다.
핵심 요약
- 429 오류는 재시도 헤더와 지수 백오프로 처리.
- 대용량 요청은 일자/필터 배치로 쪼개 즉시 저장.
- 수집 후 매시간 모니터링으로 공백 메우기.
- 5회 재시도로 95% 실패 커버; 완패 시 1시간+ 지연.
- 페이지네이션과 느슨하게 연동하는 ETL 통합.
— Editorial Team
아직 댓글이 없습니다.