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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:15:06