ZhuLinsen/daily_stock_analysis · error · DataFetchError

Baostock 获取数据失败: {e}

Error message

Baostock 获取数据失败: {e}

What it means

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.

Source

Thrown at data_provider/baostock_fetcher.py:253

                if rs.error_code != '0':
                    raise DataFetchError(f"Baostock 查询失败: {rs.error_msg}")
                
                # 转换为 DataFrame
                data_list = []
                while rs.next():
                    data_list.append(rs.get_row_data())
                
                if not data_list:
                    raise DataFetchError(f"Baostock 未查询到 {stock_code} 的数据")
                
                df = pd.DataFrame(data_list, columns=rs.fields)
                
                return df
                
            except Exception as e:
                if isinstance(e, DataFetchError):
                    raise
                raise DataFetchError(f"Baostock 获取数据失败: {e}") from e
    
    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:
        """
        标准化 Baostock 数据
        
        Baostock 返回的列名:
        date, open, high, low, close, volume, amount, pctChg
        
        需要映射到标准列名:
        date, open, high, low, close, volume, amount, pct_chg
        """
        df = df.copy()
        
        # 列名映射(只需要处理 pctChg)
        column_mapping = {
            'pctChg': 'pct_chg',
        }
        

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Inspect e.__cause__ for the real exception type — that determines fix direction (SDK version, network, or data shape).
  2. For socket drops, retry once inside a fresh _baostock_session (a new login resets the connection).
  3. Pin the baostock version if rs.fields/row API changed.
  4. Let the manager fall back to Akshare for this code if baostock keeps failing.

Example fix

# before
try:
    df = baostock_fetcher.fetch(code, start, end)
except DataFetchError:
    raise  # no diagnostics, batch dies

# after
try:
    df = baostock_fetcher.fetch(code, start, end)
except DataFetchError as e:
    logger.error('baostock failed for %s: %s (cause=%r)', code, e, e.__cause__)
    df = akshare_fetcher.fetch(code, start, end)  # fallback
Defensive patterns

Strategy: fallback

Validate before calling

import baostock as bs
rs = 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')
assert rs.fields, 'baostock result API mismatch — pin the SDK version'

Try / catch

try:
    df = baostock_fetcher.fetch(code, start, end)
except DataFetchError as e:
    logger.warning('baostock failed for %s: %s (cause=%r)', code, e, e.__cause__)
    df = akshare_fetcher.fetch(code, start, end)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/9e5bc37c4d49f41a. Report an issue: GitHub.