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

Selenium仅获取网页部分HTML的原因排查及WebUntis课程元素定位失败问题求助

解决WebUntis时间表元素无法被Selenium定位的问题

我之前爬WebUntis的时候也踩过几乎一模一样的坑,你的问题主要是几个常见的Selenium爬取动态页面的误区导致的,咱们一个个来解决:

1. 复合类名不能直接用By.CLASS_NAME

你要定位的类un-timetable__dnd-avatar un-timetable__dnd-avatar--hidden是两个类名的组合,而By.CLASS_NAME只能匹配单个类,直接用它自然找不到元素。你需要换成CSS选择器或者XPATH来匹配多个类:

用CSS选择器(推荐)

test = driver.find_elements(By.CSS_SELECTOR, ".un-timetable__dnd-avatar.un-timetable__dnd-avatar--hidden")

(注意两个类名之间没有空格,.代表类选择器,连写表示同时匹配这两个类)

用XPATH

test = driver.find_elements(By.XPATH, "//div[contains(@class, 'un-timetable__dnd-avatar') and contains(@class, 'un-timetable__dnd-avatar--hidden')]")

2. 检查是否存在iframe嵌套

WebUntis的核心内容(比如时间表)经常是在iframe里加载的,Selenium默认只会在主页面的DOM里查找元素,不会自动进入iframe。你需要先切换到对应的iframe才能定位到里面的元素:

# 先导入显式等待的工具
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 显式等待iframe加载完成,然后切换
wait = WebDriverWait(driver, 10)
iframe = wait.until(EC.presence_of_element_located((By.TAG_NAME, "iframe")))
driver.switch_to.frame(iframe)

# 现在再去查找时间表元素
test = driver.find_elements(By.CSS_SELECTOR, ".un-timetable__dnd-avatar.un-timetable__dnd-avatar--hidden")

# 操作完iframe内容后,记得切回主页面(如果需要操作其他元素的话)
# driver.switch_to.default_content()

3. 替换time.sleep为显式等待,提升稳定性

硬编码的time.sleep非常不稳定——网络慢或者页面渲染延迟的时候,等待时间就不够用了。用WebDriverWait的显式等待,直到目标元素出现/可点击再执行下一步,才是可靠的做法。比如登录、点击按钮这些步骤都可以优化:

# 等待"Mein Stundenplan"按钮可点击再点击
timetable_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Mein Stundenplan']")))
timetable_btn.click()

4. 优化无头模式配置

无头模式有时候会因为窗口尺寸太小、渲染机制不同导致页面元素加载异常,给Chrome添加这些配置试试:

options = Options()
options.add_argument("headless=new")  # 新版无头模式,更接近正常浏览器的渲染效果
options.add_argument("window-size=1920,1080")  # 设置桌面级窗口大小
options.add_argument("disable-gpu")
options.add_argument("enable-javascript")  # 确保JavaScript正常启用

整合后的完整代码

把上面的优化点整合到你的代码里,最终版本如下:

import time
from bs4 import BeautifulSoup as bs
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 设置浏览器配置
url = "https://klio.webuntis.com"
options = Options()
options.add_argument("headless=new")
options.add_argument("window-size=1920,1080")
options.add_argument("disable-gpu")
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
wait = WebDriverWait(driver, 15)  # 最长等待15秒
driver.get(url)

###################################################################################################
# 进入登录页面
school_parent = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "Select-input")))
school_input = school_parent.find_element(By.XPATH, "./*[1]")
school_input.send_keys("<schoolName>")
time.sleep(0.6)  # 这里短暂等待下拉选项加载
school_input.send_keys(Keys.RETURN)

# 登录操作
user_inputs = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "un-input-group__input")))
for element in user_inputs:
    if element.get_attribute("type") == "text":
        element.send_keys("<username>")
    elif element.get_attribute("type") == "password":
        element.send_keys("<password>")
element.send_keys(Keys.RETURN)

# 进入时间表页面
timetable_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Mein Stundenplan']")))
timetable_btn.click()

# 检查并切换到iframe(如果存在)
try:
    iframe = wait.until(EC.presence_of_element_located((By.TAG_NAME, "iframe")))
    driver.switch_to.frame(iframe)
except:
    # 如果没有iframe,跳过切换步骤
    pass

# 查找目标元素
test = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".un-timetable__dnd-avatar.un-timetable__dnd-avatar--hidden")))
print(f"成功找到 {len(test)} 个目标元素")

# 切回主页面(如果切换过iframe)
driver.switch_to.default_content()

# 打印页面源码
this_week = bs(driver.page_source, "html.parser")
print(this_week.prettify())

# 关闭浏览器
driver.quit()

内容的提问来源于stack exchange,提问作者Jonas Stefan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 12:47:38