从Morningstar下载股票价格数据时出现错误及代码求助
错误排查与解决办法
嘿,我来帮你搞定这个从Morningstar下载股票数据的问题!看了你的代码和描述,这里有几个核心问题和对应的解决思路:
一、最关键的错误原因:Morningstar数据源已失效
首先,pandas_datareader里的morningstar数据源早就不能用了——Morningstar在几年前就关闭了公开的API接口,所以你调用web.DataReader(stock, 'morningstar', ...)肯定会抛出连接错误或者数据不存在的异常,这是导致你失败的核心原因。
除此之外,你的代码还有几个小问题:
- 最后一行
temp=f['C...明显没写完,应该是要取收盘价(比如Close列),语法不完整会直接报错; - 嵌套循环每年只取单天数据,不仅效率低,还容易触发请求限制,而且如果5月1日是节假日(美股休市),也会因为没有数据报错;
- CSV读取用
dataa.extend(i)可能会把每行的所有列都塞进列表,如果你的CSV是每行一个股票代码,应该用append取第一列,不然会混入无关数据。
二、具体解决办法
1. 替换成可用的数据源
既然Morningstar凉了,推荐用Yahoo Finance作为替代,现在可以通过yfinance库来对接,步骤如下:
首先安装依赖:
pip install yfinance pandas-datareader
然后在代码里添加接口修复:
import yfinance as yf yf.pdr_override() # 让pandas_datareader能用Yahoo的数据源
之后把原来的'morningstar'改成'yahoo'就行:
f = web.DataReader(stock, 'yahoo', start, end)
如果需要更稳定的数据源,也可以试试Alpha Vantage(需要免费API密钥),不过有请求次数限制,适合小批量数据获取。
2. 修复代码逻辑与语法
- 补全截断的代码:如果要取单天收盘价,应该写成
temp = f['Close'].iloc[0](因为单天数据只有一行,用iloc[0]提取); - 优化循环逻辑:不用每年循环,直接指定时间范围,然后筛选每年5月1日的数据,这样更高效:
# 直接设置总时间范围 start = datetime(2010, 5, 1) end = datetime(2019, 5, 1) for stock in dataa[2:100]: try: df = web.DataReader(stock, 'yahoo', start, end) # 筛选所有5月1日的数据 may_1_data = df[(df.index.month == 5) & (df.index.day == 1)] for date, price in may_1_data['Close'].items(): Dates.append(date) Prices.append(price) Tick.append(stock) except Exception as e: print(f"获取{stock}数据失败: {e}") - 修复CSV读取:如果你的CSV是每行一个股票代码,前两行是表头/无关数据,改成这样更靠谱:
with open('sp500const.csv', newline='') as File: reader = csv.reader(File) # 跳过前两行 next(reader) next(reader) dataa = [row[0] for row in reader if row] # 跳过空行,只取第一列的股票代码
3. 增加异常处理
一定要加try-except块,不然单个股票获取失败会导致整个程序崩溃,还能打印错误信息帮你排查问题。
三、完整可运行的示例代码
import math import pandas_datareader.data as web import matplotlib.pyplot as plt from datetime import datetime from matplotlib import style import csv import yfinance as yf # 修复pandas_datareader与Yahoo Finance的对接 yf.pdr_override() style.use('ggplot') # 读取股票代码CSV dataa = [] with open('sp500const.csv', newline='') as File: reader = csv.reader(File) # 跳过前两行(根据你的CSV结构调整) next(reader) next(reader) for row in reader: if row: # 跳过空行 dataa.append(row[0]) Dates = [] Prices = [] Tick = [] # 设置时间范围 start_date = datetime(2010, 5, 1) end_date = datetime(2019, 5, 1) for stock in dataa[:98]: # 对应原代码的dataa[2:100] try: # 获取股票数据 df = web.DataReader(stock, 'yahoo', start_date, end_date) # 筛选每年5月1日的数据 target_dates = df[(df.index.month == 5) & (df.index.day == 1)] if not target_dates.empty: for idx, row in target_dates.iterrows(): Dates.append(idx) Prices.append(row['Close']) Tick.append(stock) else: print(f"{stock}在2010-2019年的5月1日无交易数据") except Exception as e: print(f"处理{stock}时出错: {str(e)}") # 输出结果统计 print(f"数据获取完成,共获取{len(Prices)}条有效记录")
内容的提问来源于stack exchange,提问作者AlexandrosB
相关产品推荐
相关产品推荐

