ZhuLinsen/daily_stock_analysis · error · DataFetchError
Yahoo Finance 获取数据失败: {e}
Error message
Yahoo Finance 获取数据失败: {e} What it means
Catch-all wrapper in YfinanceFetcher.fetch_stock_data: any non-DataFetchError exception from the yfinance call path is re-raised as DataFetchError with the original message. yfinance is a screen-scraping client of Yahoo endpoints, so breakages cluster around network errors, HTTP 429 rate limiting, and upstream HTML/API changes that newer yfinance versions patch.
Source
Thrown at data_provider/yfinance_fetcher.py:234
multi_level_index=True
)
# 筛选出 yf_code 的列, 避免多只股票数据混淆
if isinstance(df.columns, pd.MultiIndex) and len(df.columns) > 1:
ticker_level = df.columns.get_level_values(1)
mask = ticker_level == yf_code
if mask.any():
df = df.loc[:, mask].copy()
if df.empty:
raise DataFetchError(f"Yahoo Finance 未查询到 {stock_code} 的数据")
return df
except Exception as e:
if isinstance(e, DataFetchError):
raise
raise DataFetchError(f"Yahoo Finance 获取数据失败: {e}") from e
def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:
"""
标准化 Yahoo Finance 数据
yfinance 返回的列名:
Open, High, Low, Close, Volume(索引是日期)
注意:新版 yfinance 返回 MultiIndex 列名,如 ('Close', 'AMD')
需要先扁平化列名再进行处理
需要映射到标准列名:
date, open, high, low, close, volume, amount, pct_chg
"""
df = df.copy()
# 处理 MultiIndex 列名(新版 yfinance 返回格式)
# 例如: ('Close', 'AMD') -> 'Close'View on GitHub (pinned to 5159bd72e8)
Solutions
- Read the inner exception message {e}: '429' → slow down/cache; 'JSONDecodeError'/None-format errors → pip install -U yfinance and retry.
- Retry with backoff for transient network failures, or fall through to Tushare/Akshare via the data_provider chain.
- Pin a known-good yfinance version in requirements.txt once verified, and keep it updated when this error recurs repo-wide.
- For batches, add per-request delay or use yf.download with multiple tickers in one call to reduce request count.
Defensive patterns
Strategy: retry
Validate before calling
import yfinance, requests
requests.head("https://query1.finance.yahoo.com", timeout=5).raise_for_status()
assert yfinance.__version__ >= "0.2.40", "yfinance too old for current Yahoo API" Try / catch
for attempt, delay in enumerate((0, 2, 8), 1):
try:
df = yfinance_fetcher.fetch_stock_data(code)
break
except DataFetchError as e:
if attempt == 3 or "未查询到" in str(e):
df = akshare_fetcher.fetch_stock_data(code)
break
time.sleep(delay) # transient 429/network -> backoff Prevention
- Pin and periodically upgrade yfinance; Yahoo API changes break old versions repo-wide.
- Space out batch downloads or fetch multiple tickers in one yf.download call to avoid 429s.
- Distinguish transient (retry) from structural (fallback) failures by inspecting the wrapped message.
When it happens
Trigger: yf.download raising for network timeouts, Yahoo rate limiting (429 'Too Many Requests'), JSONDecodeError after a Yahoo response-format change, or an outdated yfinance failing on the current endpoint contract. The empty-df case (184) is re-raised unchanged, not wrapped.
Common situations: yfinance pinned to an old version while Yahoo changed its API (very common; fixed only by upgrading yfinance); running large batch downloads that trip Yahoo rate limits; corporate proxy/egress rules blocking query1.finance.yahoo.com.
Related errors
- Akshare 所有渠道获取失败: {last_error}
- Tushare 获取数据失败: {e}
- read_failed
- internal_error
- {call_name} 调用超过 {wait_seconds:g}s,已放弃等待
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/2b7bce0075b3dd78.
Report an issue: GitHub.