Python Selenium无法仅定位右侧日历元素问题求助
问题:Python Selenium筛选日历元素时包含左侧日历内容
我是Selenium新手,用Python Selenium做日历自动化测试时遇到问题:测试页面为letcode日历页面,目标是选择右侧日历的日期,但筛选日期元素时,结果包含了左侧日历的元素。
当前定位右侧日历的代码:
calendarInside = driver.find_element(By.XPATH,"/html/body/app-root/app-calender/section[1]/div/div/div[1]/div/div/div[1]/div[2]")
筛选日期元素的代码:
allDays = calendarInside.find_elements(By.XPATH, "//div[@class='datepicker-date is-current-month']")
执行后返回结果包含左侧日历元素,完整测试代码如下:
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager def testCalendar(): driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install())) driver.maximize_window() driver.implicitly_wait(10) driver.get("https://letcode.in/calendar") calendarInside = driver.find_element(By.XPATH,"/html/body/app-root/app-calender/section[1]/div/div/div[1]/div/div/div[1]/div[2]") calendarInside.find_element(By.CLASS_NAME, "datetimepicker-clear-button").click() calendarInside.find_element(By.CSS_SELECTOR, ".datetimepicker-dummy-input.is-datetimepicker-range").click() dayExpected = [6, 25] allDays = calendarInside.find_elements(By.XPATH, "//div[@class='datepicker-date is-current-month']") for dayfrom in allDays: print("dayfrom: " + str(dayfrom.text) + " - expected: " + str(dayExpected[0])) if str(dayfrom.text) == str(dayExpected[0]): dayfrom.click() break time.sleep(2) allDays = calendarInside.find_elements(By.XPATH, "//div[@class='datepicker-date is-current-month']") for dayto in allDays: print("dayto: " + str(dayto.text) + " - expected: " + str(dayExpected[1])) if str(dayto.text) == str(dayExpected[1]): dayto.click() break time.sleep(5) driver.quit() def main(): testCalendar() if __name__ == "__main__": main()
使用Selenium版本为4.9.1,请问如何仅筛选右侧日历内的元素?
解决思路
1. 问题根源
你使用的//div[@class='datepicker-date is-current-month']是全局XPath,即使通过calendarInside元素调用find_elements,//依然会从整个HTML文档根节点开始查找,而非从calendarInside节点下开始,这就是结果包含左侧日历元素的原因。
2. 核心修正方案
要从当前元素的子节点开始查找,需将XPath开头的//改为.//,.代表当前节点,这样就只会在calendarInside的后代节点中筛选元素。
修改后的筛选代码:
allDays = calendarInside.find_elements(By.XPATH, ".//div[@class='datepicker-date is-current-month']")
3. 额外优化建议
- 避免使用绝对XPath(如
/html/body/...),这种路径极易因页面结构微调失效,建议改用相对定位获取右侧日历:calendarInside = driver.find_element(By.CSS_SELECTOR, "div.datetimepicker-calendar:nth-child(2)") - 替换
time.sleep()为Selenium显式等待(WebDriverWait),让代码更稳定,避免依赖固定等待时间:from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待日历输入框可点击 WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".datetimepicker-dummy-input.is-datetimepicker-range"))).click()
修改后的完整代码
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def testCalendar(): driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install())) driver.maximize_window() driver.implicitly_wait(10) driver.get("https://letcode.in/calendar") # 改用相对定位获取右侧日历 calendarInside = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "div.datetimepicker-calendar:nth-child(2)")) ) calendarInside.find_element(By.CLASS_NAME, "datetimepicker-clear-button").click() # 用显式等待替代固定sleep WebDriverWait(calendarInside, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, ".datetimepicker-dummy-input.is-datetimepicker-range")) ).click() dayExpected = [6, 25] # 使用.//从当前节点开始查找日期元素 allDays = calendarInside.find_elements(By.XPATH, ".//div[@class='datepicker-date is-current-month']") for dayfrom in allDays: print(f"dayfrom: {dayfrom.text} - expected: {dayExpected[0]}") if dayfrom.text == str(dayExpected[0]): dayfrom.click() break # 等待日历元素更新,避免 stale element 异常 WebDriverWait(driver, 10).until( EC.staleness_of(allDays[0]) ) # 重新获取右侧日历的日期元素 allDays = calendarInside.find_elements(By.XPATH, ".//div[@class='datepicker-date is-current-month']") for dayto in allDays: print(f"dayto: {dayto.text} - expected: {dayExpected[1]}") if dayto.text == str(dayExpected[1]): dayto.click() break time.sleep(2) driver.quit() def main(): testCalendar() if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者NovLe
相关产品推荐
相关产品推荐

