Programming

🛠️ 야후 파이낸스 API 429 오류(Too Many Requests) 대응법 총정리

quantoasis 2025. 5. 8. 14:51
반응형

야후 파이낸스는 트레이딩 봇, 백테스트, 투자 정보 분석 등에 유용한 API입니다. 하지만 비공식 API인 만큼 일정 횟수 이상 요청을 보내면 HTTP 429 Too Many Requests 오류로 차단될 수 있습니다.

이번 포스트에서는 이 오류 발생 시:

  • 원인
  • 회복 방법
  • 코드 예시
  • 지수 백오프 + User-Agent 우회 + 자동복구

를 한 번에 다룹니다.


📌 1. 429 오류란?

HTTP 429: Too Many Requests
  • 너무 자주 요청을 보낼 경우 서버가 차단
  • 일반적으로 IP, User-Agent, 쿠키 등의 패턴 기반으로 감지
  • 보통 수 분~수 시간 후 자동 해제되며, 영구 차단은 드뭄

📦 2. fetch_trending_tickers() 함수 구조

import time
import random
import requests

def fetch_trending_tickers(region="US", count=10, max_retries=10):
    url = f"https://query1.finance.yahoo.com/v1/finance/trending/{region}"

    user_agents = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ...",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
    ]

    for attempt in range(max_retries):
        try:
            if attempt > 0:
                sleep_time = (2**attempt) * 10
                print(f"[재시도 {attempt+1}] {sleep_time}초 대기 중...")
                time.sleep(sleep_time)

            headers = {
                "User-Agent": random.choice(user_agents),
                "Accept": "application/json",
                "Referer": "https://finance.yahoo.com/",
                "Origin": "https://finance.yahoo.com/",
            }

            res = requests.get(url, headers=headers, timeout=30)
            print(f"응답 코드: {res.status_code}")

            if res.status_code == 429:
                raise requests.exceptions.HTTPError(response=res)

            res.raise_for_status()

            data = res.json().get("finance", {}).get("result", [])
            quotes = data[0].get("quotes", []) if data else []
            tickers = [item["symbol"] for item in quotes][:count]

            if not tickers:
                print("티커를 찾지 못했습니다.")
                continue

            return tickers

        except requests.exceptions.HTTPError as e:
            print(f"HTTP 오류: {e}")
            if attempt == max_retries - 1:
                return []
        except requests.exceptions.Timeout:
            print("요청 시간 초과. 재시도 중...")
        except Exception as e:
            print(f"예외 발생: {e}")

    print("최대 재시도 횟수 도달. 종료.")
    return []

⚙️ 3. 주요 기능 설명

기능 설명
User-Agent 회전 요청마다 브라우저 정보 변경해 탐지 회피
지수 백오프 재시도마다 10s → 20s → 40s … 대기 시간 증가
429 오류 탐지 상태코드 429일 경우 자동 재시도
최대 재시도 max_retries까지 자동 복구 시도

🧪 4. 실행 예시

if __name__ == "__main__":
    tickers = fetch_trending_tickers()
    print("트렌딩 티커:", tickers)

출력 예:

[재시도 1] 10초 대기 중...
응답 코드: 429
[재시도 2] 20초 대기 중...
응답 코드: 200
트렌딩 티커: ['AAPL', 'TSLA', 'NVDA', 'AMD', 'AMZN']

🧠 5. 보완 팁

  • IP 기반 차단 회피: VPN, 프록시를 회전시켜 사용
  • 요청 캐싱: 같은 데이터 반복 호출 방지 (예: pickle 또는 CSV)
  • 프록시 옵션 추가:
proxies = {"http": "http://proxy:port", "https": "http://proxy:port"}
requests.get(url, headers=headers, proxies=proxies)

✅ 마무리

야후 파이낸스는 유용하지만, 비공식 API라서 예기치 않은 차단이 발생할 수 있습니다.
이번 코드처럼:

  • User-Agent 우회
  • 지수 백오프
  • 자동 재시도

를 조합하면, 야후 API와의 안정적인 통신이 가능합니다.

반응형