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

如何用Puppeteer点击希尔顿官网日历弹窗的下月按钮?

问题描述

使用Puppeteer操作希尔顿官网时,无法点击日历弹窗的下月按钮,日历弹窗截图如下:
Hilton Calendar Pop-up

代码问题

以下代码行执行无效:

await page.click('[data-testid="calendar-container"] > [class="flex justify-between"] > [class="sr-only"]');

hilton_constants.js 文件

START_MONTH: "September",
START_DAY: 1,
START_YEAR: 2023,
END_MONTH: "September",
END_DAY: 4,
END_YEAR: 2023,

主Node函数

const puppeteer = require('puppeteer-extra');
const constants = require('./hilton_constants.js');
const fs = require('fs/promises');

// * Main Function
let browser;
async function hiltonScan() {
  browser = await puppeteer.launch({
    headless: false
  });
  const [page] = await browser.pages();
  const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
  await page.setUserAgent(ua);
  await page.setViewport({ width: 750, height: 10700 });

  // Block resources
  await page.setRequestInterception(true);
  page.on('request', (request) => {
      if (request.resourceType() === 'image' || request.resourceType() === 'font' || request.resourceType() === 'media') {
        request.abort();
      } else {
        request.continue()
      }
  });

  await page.goto('https://www.hilton.com/en/', { waitUntil: "domcontentloaded" });

  // Fill in Location
  await page.type('[class="form-input w-full"]', "Seattle, WA, USA");

  // Click calendar UI to select dates
  await page.click('[data-testid="search-dates-button"]');
  await page.waitForSelector('[data-testid="calendar-container"]');


  // ! This is NOT WORKING - Fill in calendar UI stay dates
  await fill_stayDates(page, constants);



  //* Helper function for above: click to the correct starting month
  async function fill_stayDates(page, constants){
    const findMonth = async targetMonth => {
      for (let i = 0; i < 12; i++) {
        // Not sure if this is causing an error
        const month = await page.$eval('[id^="calendar-month-"]', el => el.textContent);
        if (month.includes(targetMonth)) break;

        //! THIS IS NOT WORKING
        await page.click('[data-testid="calendar-container"] > [class="flex justify-between"] > [class="sr-only"]');
    };

    await findMonth(constants.START_MONTH);
    await chooseDay(constants.START_DAY);
    await findMonth(constants.END_MONTH);
    await chooseDay(constants.END_DAY);

    // click X button to close
    await page.click('[class="stroke-text"]');
  };

  //! this works, comment out for now Click Find a Hotel
  // await page.click('[data-testid="search-submit-button"]');

  // Wait for navigation
  await page.waitForNavigation();
  }
}


// * Call the main function
(async () => {
  console.log('Starting the Hilton scraper program...');
  await hiltonScan()
    .catch(err => console.error(err))
    .finally(() => browser?.close());
})();

核心问题:fill_stayDates函数中用于切换目标月份的下月按钮点击代码无法执行,需解决该问题。


解决方案

1. 修正选择器问题

原选择器依赖的sr-only类是屏幕阅读器专用的隐藏元素,实际可交互的下月按钮是它的父级或带有明确标识的元素。替换为精准的交互元素选择器:

// 优先使用data-testid标识的按钮
await page.click('[data-testid="calendar-next-button"]');
// 若data-testid不存在,使用aria标签选择器
await page.click('[aria-label="Next month"]');

2. 增加元素可见性与可交互性检查

点击前确保按钮已完全渲染并可操作,避免因元素未加载完成导致点击失效:

// 等待按钮可见且可交互
await page.waitForSelector('[aria-label="Next month"]', { visible: true, timeout: 5000 });
await page.click('[aria-label="Next month"]');

3. 修复findMonth函数语法错误

原函数的for循环缺少闭合},导致逻辑异常,修正后完整函数:

const findMonth = async targetMonth => {
  for (let i = 0; i < 12; i++) {
    // 等待月份标题加载完成
    await page.waitForSelector('[id^="calendar-month-"]', { visible: true });
    const month = await page.$eval('[id^="calendar-month-"]', el => el.textContent.trim());
    if (month.includes(targetMonth)) break;

    // 点击下月按钮
    await page.waitForSelector('[aria-label="Next month"]', { visible: true });
    await page.click('[aria-label="Next month"]');
  }
};

4. 补充chooseDay函数实现

原代码缺少日期选择的核心函数,补充如下:

async function chooseDay(day) {
  // 等待目标日期元素可见
  await page.waitForSelector(`[data-testid="calendar-day-${day}"]`, { visible: true });
  await page.click(`[data-testid="calendar-day-${day}"]`);
}

5. 优化日历弹窗加载等待逻辑

调用日期选择函数前,确保日历弹窗完全渲染:

await page.click('[data-testid="search-dates-button"]');
// 等待日历内的月份标题可见,确认弹窗加载完成
await page.waitForSelector('[id^="calendar-month-"]', { visible: true });
await fill_stayDates(page, constants);

内容的提问来源于stack exchange,提问作者Nelson Mak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:05:10