如何使用Python+Selenium提取morningstar.com的表格数据
问题背景
- 需求:抓取对应页面关键比率(Key ratio)表格中的ROE等财务数据
- 故障现象:使用Selenium编写自动化脚本,执行iframe切换操作后依然无法定位目标元素,无法获取表格数据
- 原实现代码:
from selenium import webdriver from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import time url = 'https://www.morningstar.com/stocks/xnas/amzn/quote' browser = webdriver.Firefox() #Open the URL in browser browser.get(url) #####Click Key ratio button##### #Wait until the Key ratio button is clickable element = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="keyStats"]'))) #Click keyRatioBtn element.click() #####Click Full Key ratio url##### #Wait until the Full Key ratio url is clickable element = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, '//a[@class="sal-mds-link"]'))) #Click Full Key ratio url element.click() #####Get ROE list#####browser.implicitly_wait(20) time.sleep(5) iframe = browser.find_elements(By.TAG_NAME, 'iframe') browser.switch_to.frame(1) roeList = browser.find_element_by_xpath('//*[@id="tab-profitability"]') print(roeList.get_attribute('innerHTML'))
故障根因
拿不到数据是多个逻辑错误叠加导致的:
- 点击「完整关键比率」链接后,浏览器会新开标签页加载目标内容,原代码全程停留在初始的股票报价页操作,没有切换到新标签页,自然找不到对应元素
- 硬编码iframe索引
switch_to.frame(1)稳定性极差:页面加载过程中iframe的数量、排序会动态变化,靠序号选iframe大概率匹配到错误的iframe - 代码使用的
find_element_by_xpath是Selenium旧版本的废弃API,Selenium 4+版本中该方法已被移除,运行时会直接抛出方法不存在的异常 - 等待逻辑混乱:混用隐式等待和硬编码
time.sleep(5),没有针对iframe、目标表格做显式等待,页面异步渲染的内容还没加载完成就执行查找,必然定位失败 - 定位「完整关键比率」链接的XPath
//a[@class="sal-mds-link"]匹配范围过宽,页面上存在多个同class的链接,很容易点错非目标元素
修复后代码
以下代码已经修复上述所有问题,可以直接运行获取目标数据:
from selenium import webdriver from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By url = 'https://www.morningstar.com/stocks/xnas/amzn/quote' browser = webdriver.Firefox() wait = WebDriverWait(browser, 15) # 打开初始股票报价页 browser.get(url) # 点击Key ratio入口按钮 key_stats_btn = wait.until(EC.element_to_be_clickable((By.ID, 'keyStats'))) key_stats_btn.click() # 通过文本精准定位完整关键比率链接,避免点错 full_ratio_link = wait.until(EC.element_to_be_clickable( (By.XPATH, '//a[contains(normalize-space(text()), "Full Key Ratios")]') )) full_ratio_link.click() # 切换到最新打开的关键比率标签页 browser.switch_to.window(browser.window_handles[-1]) # 通过src特征定位加载比率数据的iframe,不依赖不稳定的索引 ratio_iframe = wait.until(EC.presence_of_element_located( (By.XPATH, '//iframe[contains(@src, "ratios/r.html")]') )) browser.switch_to.frame(ratio_iframe) # 等待盈利能力tab(含ROE数据)加载完成后获取内容 roe_tab = wait.until(EC.presence_of_element_located((By.ID, 'tab-profitability'))) print(roe_tab.get_attribute('innerHTML')) # 数据抓取完成后可按需关闭浏览器 # browser.quit()
实现说明
- 全流程使用显式等待替代硬编码sleep,既提升运行速度,也能适配不同网络环境下的页面加载速度,避免元素未加载就执行查找
- iframe通过src路径特征匹配,不受页面iframe加载顺序、数量变化影响,定位更稳定
- 所有元素定位均使用Selenium当前版本支持的标准API,不存在废弃方法报错问题
- 标签页切换逻辑取窗口句柄列表的最后一个值,也就是最新打开的关键比率页面,不会出现在旧页面查找元素的问题
内容的提问来源于stack exchange,提问作者user2991037
相关产品推荐
相关产品推荐

