如何让Selenium稳定定位元素以创建Kahoot填空题测验?
Selenium自动创建Kahoot填空题的元素定位问题解决
问题说明
使用Selenium从电子表格自动生成Kahoot填空题测验时,大部分功能正常,但在以下两处代码执行时不稳定,频繁抛出「找不到Web元素」的错误:
- 第87-91行:添加新的填空题
- 第98-101行:输入题目内容和答案
核心原因是页面元素加载存在延迟,当前使用的隐式等待无法精准适配动态元素的加载时机,需要改用显式等待确保元素可交互后再执行操作。
解决思路
显式等待通过WebDriverWait配合expected_conditions(EC)模块,针对特定元素设置等待条件(如元素可点击、可见、可输入),直到元素满足条件或超时。相比全局生效的隐式等待,显式等待更灵活精准,适合处理动态加载的页面元素。
需替换问题代码中的driver.implicitly_wait(),针对每个关键元素设置显式等待:
- 等待「添加题目」按钮可点击后再点击
- 等待「填空题类型」按钮可点击后再点击
- 等待题目输入框可交互后再输入内容
- 等待答案输入框可交互后再输入内容
修改后的关键代码片段
# 替换原问题中的循环代码部分 for index, row in quiz.iterrows(): # 等待并点击「添加题目」按钮 add_question_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-functional-selector="add-question-button"]')) ) add_question_btn.click() # 等待并点击「填空题」类型按钮 answer_type_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-functional-selector="create-button__open-ended"]')) ) answer_type_btn.click() # 获取题目和答案内容 question_input = row['Question'] answer_input = row['Answer'] # 等待题目输入框可输入,然后输入内容 question_text = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'p[data-placeholder="Start typing your question"]')) ) question_text.send_keys(question_input) # 等待答案输入框可输入,然后输入内容 answer_text = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'input[placeholder="Type an answer"]')) ) answer_text.send_keys(answer_input)
完整修改后的代码
import pandas as pd from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import openpyxl # 读取电子表格 df = pd.read_excel('1000 of the most common Spanish Nouns.xlsx') # 账号信息 email = 'email' password = 'password' folder_name = input('Folder Name: ') quiz_question_length = int(input('Length of each quiz: ')) # 初始化浏览器驱动 driver = webdriver.Chrome() # 打开Kahoot登录页 driver.get('https://create.kahoot.it/auth/login') # 输入账号密码 driver.implicitly_wait(10) driver.find_element(By.ID, 'username').send_keys(f"{email}") driver.find_element(By.ID, 'password').send_keys(f"{password}") # 处理Cookie弹窗 try: driver.find_element(By.CSS_SELECTOR, 'button[id="onetrust-pc-btn-handler"]').click() driver.find_element(By.CSS_SELECTOR, 'button[class="ot-pc-refuse-all-handler"]').click() print('跳过Cookie弹窗') except: print('无Cookie弹窗') # 点击登录按钮 driver.find_element(By.CSS_SELECTOR, 'button[id="login-submit-btn"]').click() # 等待跳转至创建页面 WebDriverWait(driver, 30).until(EC.url_contains("create.kahoot.it")) # 处理引导弹窗 try: driver.find_element(By.CSS_SELECTOR, 'button[aria-label="Next"]').click() driver.find_element(By.CSS_SELECTOR, 'button[aria-label="Next"]').click() driver.find_element(By.CSS_SELECTOR, 'a[class="btn btn--text"]').click() print('跳过引导弹窗') except: print('无引导弹窗') # 进入库页面 driver.implicitly_wait(10) driver.find_element(By.CSS_SELECTOR, 'a[data-functional-selector="side-bar-link__library"]').click() # 创建新文件夹 driver.find_element(By.CSS_SELECTOR, 'button[data-functional-selector="library_side-bar_create-folder"]').click() driver.find_element(By.CSS_SELECTOR, 'input[placeholder="New folder"]').send_keys(f'{folder_name}', Keys.ENTER) # 拆分数据为多个测验 quizzes = [] for i in range(0, len(df), quiz_question_length): quizzes.append(df.iloc[i:i + quiz_question_length]) # 批量创建测验 for quiz in quizzes: # 创建新Kahoot driver.implicitly_wait(10) driver.find_element(By.CSS_SELECTOR, 'button[class="button__Button-sc-c6mvr2-0 iwRYhY create-button__PrimaryButton-sc-1wmq7f8-0 jaZrfx"]').click() driver.find_element(By.CSS_SELECTOR, 'button[aria-label="Create new Kahoot."]').click() # 选择空白模板 driver.find_element(By.CSS_SELECTOR, 'button[class="styles__FlowOptionInnerContainer-sc-hcxgxq-2 gmFgAG"]').click() driver.find_element(By.CSS_SELECTOR, 'button[class="flat-button__FlatButton-sc-6uljam-0 iEWtrJ"]').click() # 关闭主题面板 driver.find_element(By.CSS_SELECTOR, 'button[aria-label="Close Themes panel"]').click() # 逐个添加填空题 for index, row in quiz.iterrows(): # 等待并点击「添加题目」按钮 add_question_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-functional-selector="add-question-button"]')) ) add_question_btn.click() # 等待并点击「填空题」类型按钮 answer_type_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-functional-selector="create-button__open-ended"]')) ) answer_type_btn.click() # 获取题目和答案 question_input = row['Question'] answer_input = row['Answer'] # 等待题目输入框可交互并输入内容 question_text = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'p[data-placeholder="Start typing your question"]')) ) question_text.send_keys(question_input) # 等待答案输入框可交互并输入内容 answer_text = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'input[placeholder="Type an answer"]')) ) answer_text.send_keys(answer_input)
测试用DataFrame示例
df = pd.DataFrame({ 'Question': ['la explosión', 'el apellido', 'la conferencia', 'la intensidad', 'el paquete'], 'Answer': ['explosion', 'last name', 'conference', 'intensity', 'package'] })
内容的提问来源于stack exchange,提问作者Richmond Nguyen
相关产品推荐
相关产品推荐

