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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:54:53