从Yahoo Finance爬取实时股价并实现实时绘图遇阻求助
解决实时股价绘图的问题
我帮你分析了代码里的几个关键问题,咱们一步步来修复:
问题1:列索引对应错误
你存储CSV的时候,每行的结构是 [时间戳, AAPL, AMZN, IBM, CSCO],也就是:
- 列0:时间戳
- 列1:Apple股价
- 列2:Amazon股价
- 列3:IBM股价
- 列4:Cisco股价
但你的绘图代码里,把df.iloc[1:,2]当成Apple的数据,这明显对应错了,而且iloc[1:]会跳过第一行有效数据,完全没必要。
问题2:股价字符串未转数值类型
爬取到的股价是字符串格式(比如"175.23"),直接拿来绘图会导致matplotlib无法识别为数值,必须转成float类型才能正常绘制折线。
问题3:爬取与绘图的运行逻辑
你的爬取代码是单独循环100次写入CSV,绘图代码是单独运行的——如果先跑爬取再跑绘图,只能看到静态历史图;如果想实现真正的实时绘图,应该把爬取逻辑整合到绘图的循环里,这样每一次更新绘图时都会同步获取最新股价。
修复后的完整代码
我把两部分代码整合,同时修复了上述所有问题,还优化了数据处理效率:
import requests from bs4 import BeautifulSoup import pandas as pd import datetime import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib import style # 爬取实时股价的函数 def real_time_price(stock_code): url = f'https://finance.yahoo.com/quote/{stock_code}?p={stock_code}&.tsrc=fin-srch' r = requests.get(url) web_content = BeautifulSoup(r.text, 'lxml') # 注意:Yahoo Finance的页面class可能会更新,如果失效请重新检查页面元素 price_element = web_content.find('div', {"class":'My(6px) Pos(r) smartphone_Mt(6px)'}) if price_element: raw_price = price_element.find('span').text # 处理带逗号的股价(比如"1,234.56") clean_price = raw_price.replace(',', '') else: clean_price = '0' return float(clean_price) # 配置绘图样式和子图 style.use('fivethirtyeight') fig = plt.figure(figsize=(12,8)) ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3) ax4 = fig.add_subplot(2, 2, 4) stock_list = ['AAPL','AMZN','IBM', 'CSCO'] # 用内存列表存储历史数据,避免频繁读写CSV(更高效) history_data = [] def animate(i): # 获取当前时间和最新股价 time_stamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") latest_prices = [real_time_price(code) for code in stock_list] # 添加到历史数据列表 history_data.append([time_stamp] + latest_prices) # 转成DataFrame方便处理 df = pd.DataFrame(history_data, columns=['Time', 'AAPL', 'AMZN', 'IBM', 'CSCO']) # 绘制Apple股价 ax1.clear() ax1.plot(df['Time'], df['AAPL'], color='red') ax1.set_title('Apple Stock Price', fontsize=12) ax1.tick_params(axis='x', rotation=45) # 旋转x轴标签避免重叠 # 绘制Amazon股价 ax2.clear() ax2.plot(df['Time'], df['AMZN'], color='blue') ax2.set_title('Amazon Stock Price', fontsize=12) ax2.tick_params(axis='x', rotation=45) # 绘制IBM股价 ax3.clear() ax3.plot(df['Time'], df['IBM'], color='green') ax3.set_title('IBM Stock Price', fontsize=12) ax3.tick_params(axis='x', rotation=45) # 绘制Cisco股价 ax4.clear() ax4.plot(df['Time'], df['CSCO'], color='orange') ax4.set_title('Cisco Stock Price', fontsize=12) ax4.tick_params(axis='x', rotation=45) plt.tight_layout() # 启动动画,每1000ms(1秒)更新一次 ani = animation.FuncAnimation(fig, animate, interval=1000) plt.show() # 可选:如果需要持久化数据,在动画关闭后执行下面的代码 # pd.DataFrame(history_data, columns=['Time', 'AAPL', 'AMZN', 'IBM', 'CSCO']).to_csv('real_time_stock_data.csv', index=False)
额外说明
- 页面结构兼容性:Yahoo Finance的HTML结构可能会随时更新,如果后续爬取不到数据,需要打开浏览器开发者工具,重新定位股价元素的class。
- 数据存储优化:我把频繁读写CSV改成了内存列表存储,避免磁盘IO开销;如果需要保存历史数据,可以在关闭绘图窗口后一次性写入CSV。
- 时间轴显示优化:给x轴标签添加了旋转45度的设置,避免时间戳重叠导致看不清。
- 异常处理:添加了对股价元素不存在的判断,以及去除千位分隔逗号的处理,避免转数值时出错。
内容的提问来源于stack exchange,提问作者Mathious Willie
相关产品推荐
相关产品推荐

