You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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)

额外说明

  1. 页面结构兼容性:Yahoo Finance的HTML结构可能会随时更新,如果后续爬取不到数据,需要打开浏览器开发者工具,重新定位股价元素的class。
  2. 数据存储优化:我把频繁读写CSV改成了内存列表存储,避免磁盘IO开销;如果需要保存历史数据,可以在关闭绘图窗口后一次性写入CSV。
  3. 时间轴显示优化:给x轴标签添加了旋转45度的设置,避免时间戳重叠导致看不清。
  4. 异常处理:添加了对股价元素不存在的判断,以及去除千位分隔逗号的处理,避免转数值时出错。

内容的提问来源于stack exchange,提问作者Mathious Willie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:57:47