如何用WebDriver读取Booking.com日历上用户选择的起止日期
需求说明
我正在学习网页抓取,需要让WebDriver等待用户在Booking.com的日历中手动选择开始日期和结束日期,之后读取这两个日期,用来处理该时间段内的可用房源,希望能得到帮助。
现有代码片段
获取日历日期的代码
tables = wait.until(EC.presence_of_all_elements_located((By.XPATH, "//table[@role='grid']"))) table_first_month = tables[0].find_element(By.TAG_NAME, "tbody") all_dates = table_first_month.find_elements(By.XPATH, "//td[@role='gridcell']") for date in all_dates: date_span = date.find_element(By.TAG_NAME, "span") aria_label_span = date_span.get_attribute("aria-label") print(aria_label_span) # userStartDate = wait.until(EC.element_to_be_clickable((this is where i need help))) if aria_label_span == str(userStartDate): date_span.click() time.sleep(4) break
日历翻页验证函数
def press_right_arrow_until_date_is_found(date): # get the text of the initial calendar current_calendar = driver.find_element(By.XPATH, "/html[1]/body[1]/div[2]/div[1]/div[3]/div[1]/div[2]/div[1]/div[1]/div[1]/div[1]/form[1]/div[1]/div[3]/div[4]/div[1]/div[1]").text # while the date does not appear in the calendar view press right arrow until it does while(date_formater(date) not in current_calendar): right_arrow = driver.find_element(By.XPATH, "//button[@class='fc63351294 a822bdf511 e3c025e003 fa565176a8 cfb238afa1 ae1678b153 c9fa5fc96d be298b15fa']") right_arrow.click() current_calendar = driver.find_element(By.XPATH, "/html[1]/body[1]/div[2]/div[1]/div[3]/div[1]/div[2]/div[1]/div[1]/div[1]/div[1]/form[1]/div[1]/div[3]/div[4]/div[1]/div[1]").text
解决方案
1. 等待用户手动选择日期
核心思路是监听用户选择后日历中出现的「选中状态日期元素」,通过WebDriverWait等待该元素出现后提取日期值:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 初始化等待器(最多等待30秒,给用户足够选择时间) wait = WebDriverWait(driver, 30) # 等待用户选择开始日期(监听带有选中标记的日期单元格) selected_start_elem = wait.until( EC.presence_of_element_located((By.XPATH, "//td[@role='gridcell' and contains(@class, 'selected')]")) ) userStartDate = selected_start_elem.find_element(By.TAG_NAME, "span").get_attribute("aria-label") # 等待用户选择结束日期(排除已选中的开始日期,确保拿到第二个选中的日期) selected_end_elem = wait.until( EC.presence_of_element_located((By.XPATH, "//td[@role='gridcell' and contains(@class, 'selected') and not(preceding-sibling::td[contains(@class, 'selected')])]")) ) userEndDate = selected_end_elem.find_element(By.TAG_NAME, "span").get_attribute("aria-label") print(f"开始日期:{userStartDate}") print(f"结束日期:{userEndDate}")
2. 修复现有代码的问题
- 日期查找范围错误:原代码中
table_first_month.find_elements(By.XPATH, "//td[@role='gridcell']")使用绝对XPath,会返回整个页面的所有日期单元格,应改为相对路径.//td[@role='gridcell'],仅查找当前月份表格内的日期:all_dates = table_first_month.find_elements(By.XPATH, ".//td[@role='gridcell']") - 绝对路径不稳定:原翻页函数使用绝对XPath,容易因页面结构变动失效,改用相对定位+属性定位优化:
def press_right_arrow_until_date_is_found(date): # 定位日历容器(用更稳定的属性定位) calendar_container = driver.find_element(By.CSS_SELECTOR, "div[data-testid='calendar-month']") target_date_str = date_formater(date) while target_date_str not in calendar_container.text: # 用aria-label定位翻页按钮,比class更稳定 right_arrow = driver.find_element(By.XPATH, "//button[@aria-label='Next month']") right_arrow.click() # 等待日历刷新完成 wait.until(EC.staleness_of(calendar_container)) calendar_container = driver.find_element(By.CSS_SELECTOR, "div[data-testid='calendar-month']")
内容的提问来源于stack exchange,提问作者LbS
相关产品推荐
相关产品推荐

