Python使用Selenium选择Datetimepicker年份无法选中2021年问题求助
问题描述
操作Selenium调用页面datetimepicker控件选择2021年作为起始年份时,代码运行后实际选中结果为2022年,原有实现代码如下:
driver.get('http://www.sse.com.cn/disclosure/bond/announcement/company/') wait = WebDriverWait(driver, 50) datefield_st = wait.until(EC.element_to_be_clickable((By.ID, "start_date"))) datefield_st.click() wait.until(EC.element_to_be_clickable((By.XPATH, "/html/body/div[12]/div[3]/table/thead/tr[1]/th[2]"))).click() wait.until(EC.element_to_be_clickable((By.XPATH, "//div[@class='datetimepicker-years']//table/tbody/tr/td/span[text()='{}']".format("2021")))).click() wait.until(EC.element_to_be_clickable((By.XPATH, "//div[@class='datetimepicker-months']//table/tbody/tr/td/span[text()='{}']".format("十二月")))).click() day=15
问题根因
- 代码使用写死层级的绝对XPath定位弹窗头部按钮,datetimepicker弹窗的DOM序号会随页面渲染动态变化,极易点错翻页控件导致年份区间偏移
- 未做年份范围校验:该站点使用的bootstrap datetimepicker年份视图默认仅展示10年区间,首次进入年份视图时默认展示的区间大概率包含当前年,若2021不在当前可见区间内直接查找元素,会触发元素不存在异常,或误点到相邻年份
- 未做视图切换等待:点击年份/月份切换按钮后,控件有视图切换动画,未等目标视图完全渲染就执行点击,会出现点击落点偏移、命中隐藏元素的问题
- 全局匹配元素未筛选可见状态:页面可能留存多个隐藏的历史datetimepicker DOM节点,直接全局class匹配会命中隐藏元素,点击操作不生效
修复代码
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver.get('http://www.sse.com.cn/disclosure/bond/announcement/company/') wait = WebDriverWait(driver, 50) # 触发起始日期选择框 datefield_st = wait.until(EC.element_to_be_clickable((By.ID, "start_date"))) datefield_st.click() # 定位当前可见的激活日期弹窗,规避写死DOM序号的问题 active_picker = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.datetimepicker"))) # 点击头部切换按钮进入年份视图 switch_btn = active_picker.find_element(By.CSS_SELECTOR, "th.picker-switch") switch_btn.click() wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.datetimepicker-years"))) # 翻页直到2021出现在可选年份列表中 while True: year_items = active_picker.find_elements(By.CSS_SELECTOR, "div.datetimepicker-years tbody span") visible_years = [item.text for item in year_items if item.is_displayed()] if "2021" in visible_years: break # 点击上一页箭头翻找更早年份 prev_arrow = active_picker.find_element(By.CSS_SELECTOR, "th.prev") prev_arrow.click() # 选择2021年 wait.until(EC.element_to_be_clickable( (By.XPATH, "//div[contains(@class,'datetimepicker-years') and not(contains(@style,'display:none'))]//span[text()='2021']") )).click() # 等待月份视图加载完成后选择12月 wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.datetimepicker-months"))) wait.until(EC.element_to_be_clickable( (By.XPATH, "//div[contains(@class,'datetimepicker-months') and not(contains(@style,'display:none'))]//span[text()='十二月']") )).click() # 后续选择日期逻辑 day = 15 wait.until(EC.element_to_be_clickable( (By.XPATH, f"//div[contains(@class,'datetimepicker-days') and not(contains(@style,'display:none'))]//td[text()='{day}' and not(contains(@class,'old')) and not(contains(@class,'new'))]") )).click()
注意事项
- 所有控件定位优先筛选可见状态,不要匹配隐藏的DOM节点,避免点击无效
- 禁止使用固定层级的绝对XPath定位动态弹窗元素,优先通过可见性、相对位置关系定位
- 涉及控件多视图切换的操作,必须等待目标视图完全渲染可见后再执行下一步点击,避免动画过程中点击错位
内容的提问来源于stack exchange,提问作者Joyce
相关产品推荐
相关产品推荐

