{"record":{"id":"9e5bc37c4d49f41a","repo":"ZhuLinsen/daily_stock_analysis","slug":"baostock-e","errorCode":null,"errorMessage":"Baostock 获取数据失败: {e}","messagePattern":"Baostock 获取数据失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/baostock_fetcher.py","lineNumber":253,"sourceCode":"                if rs.error_code != '0':\n                    raise DataFetchError(f\"Baostock 查询失败: {rs.error_msg}\")\n                \n                # 转换为 DataFrame\n                data_list = []\n                while rs.next():\n                    data_list.append(rs.get_row_data())\n                \n                if not data_list:\n                    raise DataFetchError(f\"Baostock 未查询到 {stock_code} 的数据\")\n                \n                df = pd.DataFrame(data_list, columns=rs.fields)\n                \n                return df\n                \n            except Exception as e:\n                if isinstance(e, DataFetchError):\n                    raise\n                raise DataFetchError(f\"Baostock 获取数据失败: {e}\") from e\n    \n    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:\n        \"\"\"\n        标准化 Baostock 数据\n        \n        Baostock 返回的列名：\n        date, open, high, low, close, volume, amount, pctChg\n        \n        需要映射到标准列名：\n        date, open, high, low, close, volume, amount, pct_chg\n        \"\"\"\n        df = df.copy()\n        \n        # 列名映射（只需要处理 pctChg）\n        column_mapping = {\n            'pctChg': 'pct_chg',\n        }\n        ","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/baostock_fetcher.py#L235-L271","documentation":"The generic DataFetchError catch-all at the bottom of BaostockFetcher's query block: any exception during login-context query execution that is not already a DataFetchError (those are re-raised verbatim) gets wrapped with the original cause chained. It covers row iteration, DataFrame construction, and any unexpected baostock SDK exception.","triggerScenarios":"Exceptions while consuming the baostock result: rs.next()/get_row_data() throwing on a dropped socket, pd.DataFrame construction failing on mismatched rs.fields after a baostock version change, or attribute errors from a partially-initialized baostock module. Explicit DataFetchErrors (137/138) bypass this wrapper via the isinstance re-raise.","commonSituations":"baostock package updated with a changed result API breaking the row loop; connection dying mid-iteration under load; monkeypatched/mocked baostock in tests missing attributes.","solutions":["Inspect e.__cause__ for the real exception type — that determines fix direction (SDK version, network, or data shape).","For socket drops, retry once inside a fresh _baostock_session (a new login resets the connection).","Pin the baostock version if rs.fields/row API changed.","Let the manager fall back to Akshare for this code if baostock keeps failing."],"exampleFix":"# before\ntry:\n    df = baostock_fetcher.fetch(code, start, end)\nexcept DataFetchError:\n    raise  # no diagnostics, batch dies\n\n# after\ntry:\n    df = baostock_fetcher.fetch(code, start, end)\nexcept DataFetchError as e:\n    logger.error('baostock failed for %s: %s (cause=%r)', code, e, e.__cause__)\n    df = akshare_fetcher.fetch(code, start, end)  # fallback","handlingStrategy":"fallback","validationCode":"import baostock as bs\nrs = bs.query_history_k_data_plus(code='sh.600519', fields='date,open,high,low,close,volume,amount,pctChg', start_date='2025-01-01', end_date='2025-01-10', frequency='d', adjustflag='2')\nassert rs.fields, 'baostock result API mismatch — pin the SDK version'","typeGuard":null,"tryCatchPattern":"try:\n    df = baostock_fetcher.fetch(code, start, end)\nexcept DataFetchError as e:\n    logger.warning('baostock failed for %s: %s (cause=%r)', code, e, e.__cause__)\n    df = akshare_fetcher.fetch(code, start, end)","preventionTips":["Pin the baostock package version; its result-set API (fields/next/get_row_data) drifts between releases.","Log __cause__ to separate SDK-shape errors from network drops.","Use a fresh _baostock_session per retry so a broken connection is re-established."],"tags":["baostock","wrapper","fallback","a-shares","data-provider"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}