Yahoo Stocks API部分退市股票报错,Python异常捕获失效求优化
解决Yfinance API退市股票触发AttributeError且捕获失效的高效优化方案
我一直用Yahoo的yfinance库批量获取全球多交易所股票数据,之前代码运行正常,但API更新后,部分退市股票(比如ANTM)会触发AttributeError: 'float' object has no attribute 'upper'错误,而且原代码的try-except根本抓不到这个异常,直接导致代码卡死无限运行。我搞了个临时解决办法,但处理上千只股票时速度慢得离谱,现在要找个能高效捕获异常、不拖慢运行速度的优化方案。
原代码
!pip install yfinance import yfinance as yf import datetime as dt start = '2021-01-01' end = dt.datetime.today().strftime('%Y-%m-%d') tickers=['AAPL', 'ANTM'] for ticker in tickers: try: df=yf.download(ticker, start, end, progress=False) df.index = df.index.strftime('%Y/%m/%d') df.to_csv(f'{ticker}.csv') except Exception: if ticker not in tickers: continue
临时解决方案(性能瓶颈)
我加了个前置检查,先通过yf.Ticker(ticker).info['regularMarketPrice']判断股票是否活跃,但这个方法每次都要额外请求一次API,处理上千只股票时重复请求导致速度骤降:
# 临时 workaround 代码 tickers=['AAPL','ANTM'] for ticker in tickers: try: if yf.Ticker(ticker).info['regularMarketPrice'] != None: # 额外API请求拖慢速度 df=yf.download(ticker, start, end, progress=False) df.index = df.index.strftime('%Y/%m/%d') df.to_csv(f'{ticker}.csv') else: continue except Exception: if ticker not in tickers: continue
高效优化方案
1. 精准捕获特定异常,清理无效逻辑
原try-except抓不到异常,是因为错误发生在yf.download内部的特定代码路径,直接捕获AttributeError并针对性处理,同时去掉无意义的ticker not in tickers判断(循环里的ticker肯定在列表里):
import yfinance as yf import datetime as dt start = '2021-01-01' end = dt.datetime.today().strftime('%Y/%m/%d') tickers=['AAPL', 'ANTM'] for ticker in tickers: try: df = yf.download(ticker, start, end, progress=False) # 先检查数据是否有效,避免后续处理空DataFrame报错 if df.empty: print(f"{ticker} 无有效数据(可能已退市)") continue df.index = df.index.strftime('%Y/%m/%d') df.to_csv(f'{ticker}.csv') except AttributeError as e: if "'float' object has no attribute 'upper'" in str(e): print(f"{ticker} 触发退市相关错误,跳过") continue except Exception as e: print(f"{ticker} 出现其他错误: {e}") continue
2. 批量请求减少API调用次数
yfinance支持批量下载多个ticker,一次性请求能大幅减少API交互次数,提升效率,同时在批量结果里过滤无效数据:
import yfinance as yf import datetime as dt start = '2021-01-01' end = dt.datetime.today().strftime('%Y/%m/%d') tickers=['AAPL', 'ANTM'] # 优先批量下载所有ticker数据 try: df_batch = yf.download(tickers, start, end, progress=False, group_by='ticker') for ticker in tickers: # 提取单只股票的数据 ticker_df = df_batch[ticker] if ticker_df.empty: print(f"{ticker} 无有效数据(可能已退市)") continue ticker_df.index = ticker_df.index.strftime('%Y/%m/%d') ticker_df.to_csv(f'{ticker}.csv') except AttributeError as e: # 若批量请求中出现退市股票错误,转为逐个处理异常ticker print("批量请求触发错误,转为逐个处理") for ticker in tickers: try: df = yf.download(ticker, start, end, progress=False) if df.empty: print(f"{ticker} 无有效数据") continue df.index = df.index.strftime('%Y/%m/%d') df.to_csv(f'{ticker}.csv') except AttributeError as e: if "'float' object has no attribute 'upper'" in str(e): print(f"{ticker} 已退市,跳过") continue
3. 禁用不必要的API字段请求
通过yf.download的参数减少不必要的数据请求,比如关闭分红拆分数据、自动调整等,进一步提升速度:
df = yf.download(ticker, start, end, progress=False, actions=False, auto_adjust=False, threads=True)
内容的提问来源于stack exchange,提问作者JD_BNL
相关产品推荐
相关产品推荐

