{"record":{"id":"2b7bce0075b3dd78","repo":"ZhuLinsen/daily_stock_analysis","slug":"yahoo-finance-e","errorCode":null,"errorMessage":"Yahoo Finance 获取数据失败: {e}","messagePattern":"Yahoo Finance 获取数据失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/yfinance_fetcher.py","lineNumber":234,"sourceCode":"                multi_level_index=True\n            )\n\n            # 筛选出 yf_code 的列, 避免多只股票数据混淆\n            if isinstance(df.columns, pd.MultiIndex) and len(df.columns) > 1:\n                ticker_level = df.columns.get_level_values(1)\n                mask = ticker_level == yf_code\n                if mask.any():\n                    df = df.loc[:, mask].copy()\n\n            if df.empty:\n                raise DataFetchError(f\"Yahoo Finance 未查询到 {stock_code} 的数据\")\n\n            return df\n\n        except Exception as e:\n            if isinstance(e, DataFetchError):\n                raise\n            raise DataFetchError(f\"Yahoo Finance 获取数据失败: {e}\") from e\n\n    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:\n        \"\"\"\n        标准化 Yahoo Finance 数据\n\n        yfinance 返回的列名：\n        Open, High, Low, Close, Volume（索引是日期）\n\n        注意：新版 yfinance 返回 MultiIndex 列名，如 ('Close', 'AMD')\n        需要先扁平化列名再进行处理\n\n        需要映射到标准列名：\n        date, open, high, low, close, volume, amount, pct_chg\n        \"\"\"\n        df = df.copy()\n\n        # 处理 MultiIndex 列名（新版 yfinance 返回格式）\n        # 例如: ('Close', 'AMD') -> 'Close'","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/yfinance_fetcher.py#L216-L252","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import yfinance, requests\n\nrequests.head(\"https://query1.finance.yahoo.com\", timeout=5).raise_for_status()\nassert yfinance.__version__ >= \"0.2.40\", \"yfinance too old for current Yahoo API\"","typeGuard":null,"tryCatchPattern":"for attempt, delay in enumerate((0, 2, 8), 1):\n    try:\n        df = yfinance_fetcher.fetch_stock_data(code)\n        break\n    except DataFetchError as e:\n        if attempt == 3 or \"未查询到\" in str(e):\n            df = akshare_fetcher.fetch_stock_data(code)\n            break\n        time.sleep(delay)  # transient 429/network -> backoff","preventionTips":["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."],"tags":["yfinance","network","rate-limit","wrap"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}