{"record":{"id":"1a0aae043f02eb39","repo":"ZhuLinsen/daily_stock_analysis","slug":"akshare-e-1a0aae","errorCode":null,"errorMessage":"Akshare 获取美股数据失败: {e}","messagePattern":"Akshare 获取美股数据失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/akshare_fetcher.py","lineNumber":821,"sourceCode":"                if '成交量' in df.columns and '收盘' in df.columns:\n                    df['成交额'] = df['成交量'] * df['收盘']\n                else:\n                    df['成交额'] = 0\n                \n                return df\n            else:\n                logger.warning(f\"[API返回] ak.stock_us_daily 返回空数据, 耗时 {api_elapsed:.2f}s\")\n                return pd.DataFrame()\n            \n        except Exception as e:\n            error_msg = str(e).lower()\n            \n            # 检测反爬封禁\n            if any(keyword in error_msg for keyword in ['banned', 'blocked', '频率', 'rate', '限制']):\n                logger.warning(f\"检测到可能被封禁: {e}\")\n                raise RateLimitError(f\"Akshare 可能被限流: {e}\") from e\n            \n            raise DataFetchError(f\"Akshare 获取美股数据失败: {e}\") from e\n\n    def _fetch_hk_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:\n        \"\"\"\n        获取港股历史数据\n        \n        数据来源：ak.stock_hk_hist()\n        \n        Args:\n            stock_code: 港股代码，如 '00700', '01810'\n            start_date: 开始日期，格式 'YYYY-MM-DD'\n            end_date: 结束日期，格式 'YYYY-MM-DD'\n            \n        Returns:\n            港股历史数据 DataFrame\n        \"\"\"\n        import akshare as ak\n        \n        # 防封禁策略 1: 随机 User-Agent","sourceCodeStart":803,"sourceCodeEnd":839,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/akshare_fetcher.py#L803-L839","documentation":"Raised by AkshareFetcher._fetch_us_data when ak.stock_us_daily fails with an exception that is NOT a detected rate-limit (no 'banned'/'blocked'/'频率'/'rate'/'限制' in the message). It is the generic DataFetchError escape hatch wrapping the underlying Sina/akshare exception, designed so DataFetcherManager can fall back to another US data source (Yfinance, AlphaVantage).","triggerScenarios":"Fetching a US ticker like 'AMD' when Sina's endpoint is down, the ticker is unknown to Sina (empty/broken payload raising inside akshare), a network timeout, or an akshare version change to stock_us_daily's return shape. Note: an empty-but-clean response returns an empty DataFrame instead; this error means an actual exception was raised.","commonSituations":"akshare upgraded and stock_us_daily signature/return changed; delisted or exotic tickers (e.g. OTC symbols) that Sina does not cover; corporate-VPN TLS interception breaking the Sina connection.","solutions":["Log e.__cause__ to identify whether it is KeyError (payload shape change → pin akshare version), timeout (network), or HTTP error.","Verify the ticker exists on Sina Finance US quotes before blaming the fetcher.","If akshare changed the interface, upgrade/pin akshare to a compatible release and rerun.","Rely on the manager's fallback to YfinanceFetcher for US symbols."],"exampleFix":"// before\ntry:\n    df = akshare_fetcher.fetch('AMD', start, end)\nexcept DataFetchError:\n    raise  # whole job dies\n\n// after\ntry:\n    df = akshare_fetcher.fetch('AMD', start, end)\nexcept DataFetchError as e:\n    logger.warning('akshare US failed: %s, falling back', e)\n    df = yfinance_fetcher.fetch('AMD', start, end)","handlingStrategy":"fallback","validationCode":"import akshare as ak\n# verify Sina US coverage for the symbol first\nspot = ak.stock_us_spot()  # or a cheap single-symbol call\nassert 'AMD' in spot['symbol'].str.upper().values","typeGuard":null,"tryCatchPattern":"try:\n    df = akshare_fetcher.fetch(us_sym, start, end)\nexcept DataFetchError as e:\n    logger.warning('akshare US failed for %s: %s', us_sym, e)\n    df = yfinance_fetcher.fetch(us_sym, start, end)","preventionTips":["Pin the akshare version in requirements to avoid silent interface drift in stock_us_daily.","Route US symbols to a US-primary source (Yfinance) and use Akshare as fallback, reversing the usual A-share order.","Capture __cause__ in logs to distinguish code bugs from network faults."],"tags":["akshare","us-stocks","sina","data-provider","fallback"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}