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

如何处理phptravels.net网站的日历控件?如何编写通用处理函数?

如何处理phptravels.net网站的日历控件?如何编写通用处理函数?

兄弟,我之前也折腾过这个网站的酒店日历控件,结合你用的Java Selenium和Page Object Model(POM),给你分享一套实用的解决方案,还能写出通用的日历处理函数,以后换其他类似日历也能复用!

先理清楚这个日历的结构特点

phptravels的酒店日历是典型的「月份面板切换+日期点击」类型:点击入住/退房输入框会弹出日历面板,面板顶部显示当前年月,左右有切换月份的箭头,日期是按天排列的单元格,部分过期日期会置灰不可选。

基于POM的分步实现方案

我们把所有日历操作封装在你的HomePage类里,拆分几个核心方法,再组合成完整的日期选择流程:

1. 封装打开日历的方法

首先要触发日历面板显示,定位入住日期的输入框或者触发按钮(这个网站里点击输入框就会弹出日历):

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class HomePage {
    private WebDriver driver;

    // 定位入住日期输入框
    @FindBy(id = "checkin")
    private WebElement checkinInput;

    public HomePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    // 打开入住日历面板
    public void openCheckinCalendar() {
        // 先点击输入框触发日历弹出,避免直接操作元素找不到
        checkinInput.click();
    }
}

2. 编写通用的「月份切换」函数

这是日历处理的核心难点:要自动切换到目标日期所在的月份。我们可以通过对比当前日历显示的年月和目标年月,循环点击切换箭头,直到匹配成功:

import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

// 在HomePage类里继续添加元素和方法
@FindBy(xpath = "//div[contains(@class, 'datepicker-days')]/thead/tr[1]/th[2]")
private WebElement calendarCurrentMonthYear; // 日历顶部显示的年月,比如"October 2024"

@FindBy(xpath = "//div[contains(@class, 'datepicker-days')]/thead/tr[1]/th[1]")
private WebElement prevMonthBtn; // 上月切换箭头

@FindBy(xpath = "//div[contains(@class, 'datepicker-days')]/thead/tr[1]/th[3]")
private WebElement nextMonthBtn; // 下月切换箭头

// 通用的切换到目标年月的方法
private void navigateToTargetMonth(YearMonth targetYearMonth) {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM yyyy");

    while (true) {
        // 获取当前日历显示的年月并解析
        String currentMonthYearText = calendarCurrentMonthYear.getText().trim();
        YearMonth currentYearMonth = YearMonth.parse(currentMonthYearText, formatter);

        if (currentYearMonth.equals(targetYearMonth)) {
            break; // 匹配到目标年月,停止切换
        } else if (currentYearMonth.isBefore(targetYearMonth)) {
            // 当前年月早于目标,点下月按钮
            wait.until(ExpectedConditions.elementToBeClickable(nextMonthBtn)).click();
        } else {
            // 当前年月晚于目标,点上月按钮
            wait.until(ExpectedConditions.elementToBeClickable(prevMonthBtn)).click();
        }
    }
}

3. 编写通用的「日期选择」函数

切换到目标月份后,就可以定位并点击目标日期了。注意要判断日期是否可点击(避免选择过期日期):

import java.time.LocalDate;
import org.openqa.selenium.By;

// 在HomePage类里添加日期选择方法
private void selectTargetDate(LocalDate targetDate) {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    // 定位目标日期的元素:日期单元格的text等于目标日期的天数字符串
    WebElement targetDateElement = wait.until(ExpectedConditions.elementToBeClickable(
        By.xpath(String.format("//td[contains(@class, 'day') and text()='%d']", targetDate.getDayOfMonth()))
    ));
    
    // 确保日期不是灰化的不可选状态
    if (!targetDateElement.getAttribute("class").contains("disabled")) {
        targetDateElement.click();
    } else {
        throw new IllegalArgumentException("目标日期不可选,请检查日期是否合法");
    }
}

4. 组合成完整的日期选择方法

把上面的方法整合,对外提供一个简单的调用入口,传入LocalDate类型的目标日期即可:

// 在HomePage类里添加最终的公共方法
public void selectCheckinDate(LocalDate targetDate) {
    openCheckinCalendar();
    navigateToTargetMonth(YearMonth.from(targetDate));
    selectTargetDate(targetDate);
}

测试类中调用示例

在你的测试代码里,只需要实例化HomePage,传入目标日期即可完成操作:

import java.time.LocalDate;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class HotelBookingTest {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        driver.get("https://phptravels.net/");
        
        HomePage homePage = new HomePage(driver);
        // 选择3天后的日期作为入住日期
        LocalDate checkinDate = LocalDate.now().plusDays(3);
        homePage.selectCheckinDate(checkinDate);
        
        // 后续的退房日期选择可以复用同样的逻辑,只需要修改定位元素即可
    }
}

通用函数的扩展思路

这套逻辑可以很容易改造成通用的日历处理工具类:

  • 把年月切换、日期选择的核心逻辑抽离成独立的CalendarHandler类,传入不同的日历元素定位器(比如不同网站的年月元素、切换按钮的定位)
  • 支持传入不同的日期格式解析器,适配不同网站的年月显示格式
  • 添加更多边界处理,比如处理闰年、当月最后一天等特殊情况

备注:内容来源于stack exchange,提问作者Bhavesh Deshmukh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:43:01