使用Selenium定位Canvas元素遇NoSuchElementException,如何获取成绩?
如何用Selenium获取IFSP Sisu候补名单中人名旁的黄色成绩数字(解决NoSuchElementException)
我需要从指定页面获取所有课程的成绩(即人名旁的黄色数字),但使用Selenium查找Canvas元素时始终抛出NoSuchElementException。以下是我尝试的代码:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.action_chains import ActionChains class CrawlerEspera: def __init__(self) -> None: self.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) self.driver.maximize_window() self.pessoas = [] self.falhas = [] def clicar(self, xpath): item = self.find_xpath(xpath) ActionChains(self.driver).move_to_element(item).perform() item.click() def find_xpath(self, item): return self.driver.find_element('xpath', item) def get_espera(self): self.driver.get('https://fiibrasil.com/lista-de-espera-sisu/ifsp-instituto-federal-de-educacao-de-sao-paulo/') self.driver.find_element('xpath', '/html/body/div[2]/div[3]/div[1]/div[1]/div/div[2]/div[13]/div/div/div/div[1]/div[11]/div[1]/div[2]/canvas[2]') espera = CrawlerEspera() espera.get_espera()
求可行的解决方法获取所有成绩。
可行解决方案
1. 替换绝对XPath为相对定位
绝对XPath依赖页面完整层级结构,只要页面元素位置微调就会失效。改用基于元素属性或父元素特征的相对定位,稳定性更高:
# 示例:通过候补项容器定位对应的Canvas canvas = self.driver.find_element('xpath', '//div[contains(@class, "lista-espera-item")]//canvas[2]')
2. 添加显式等待,确保元素完成渲染
页面加载存在延迟,直接执行查找会因元素未渲染导致异常。使用WebDriverWait等待元素可见:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def get_espera(self): self.driver.get('https://fiibrasil.com/lista-de-espera-sisu/ifsp-instituto-federal-de-educacao-de-sao-paulo/') # 等待目标Canvas可见,最长等待10秒 target_canvas = WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(('xpath', '//div[contains(@class, "lista-espera-item")]//canvas[2]')) )
3. 检查并处理iframe嵌套
如果目标Canvas位于iframe内部,必须先切换到iframe上下文才能查找元素:
def get_espera(self): self.driver.get('https://fiibrasil.com/lista-de-espera-sisu/ifsp-instituto-federal-de-educacao-de-sao-paulo/') # 定位并切换到目标iframe iframe = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located(('xpath', '//iframe[contains(@src, "sisu")]')) ) self.driver.switch_to.frame(iframe) # 此时可以正常查找Canvas元素 target_canvas = WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(('xpath', '//div[contains(@class, "lista-espera-item")]//canvas[2]')) ) # 操作完成后切回主文档上下文 self.driver.switch_to.default_content()
4. 直接从页面JS数据提取(最优方案)
Canvas仅用于可视化渲染成绩,实际数据通常存储在页面的JavaScript变量中。直接执行JS获取原始数据,无需操作Canvas,效率更高:
def get_espera(self): self.driver.get('https://fiibrasil.com/lista-de-espera-sisu/ifsp-instituto-federal-de-educacao-de-sao-paulo/') # 等待页面JS资源加载完成 WebDriverWait(self.driver, 15).until( lambda driver: driver.execute_script('return document.readyState') == 'complete' ) # 执行JS提取成绩数据(需根据页面实际JS变量调整,示例假设数据在listaEsperaData中) scores = self.driver.execute_script(""" return window.listaEsperaData ? listaEsperaData.map(item => item.nota) : []; """) # 输出所有成绩 for idx, score in enumerate(scores, 1): print(f"第{idx}位候选人成绩:{score}")
5. 处理滚动加载的内容
如果候补名单是滚动加载,需模拟滚动到底部并等待新内容加载,才能获取完整数据:
import time def scroll_load_all(self): last_height = self.driver.execute_script("return document.body.scrollHeight") while True: # 滚动到底部 self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 等待新内容加载 time.sleep(2) # 检查页面高度是否变化 new_height = self.driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height def get_espera(self): self.driver.get('https://fiibrasil.com/lista-de-espera-sisu/ifsp-instituto-federal-de-educacao-de-sao-paulo/') # 滚动加载所有候补内容 self.scroll_load_all() # 再执行数据提取操作
内容的提问来源于stack exchange,提问作者João Pedro Gomes
相关产品推荐
相关产品推荐

