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

使用Puppeteer爬取温德姆酒店网站时搜索结果加载不稳定问题排查

问题

尝试使用Puppeteer对温德姆酒店官网进行爬取,但搜索结果无法稳定加载,已尝试更换UserAgent、不拦截资源,均无效,询问该网站是否存在反爬机制。

搜索结果有时无法加载

原代码:

const puppeteer = require("puppeteer"); // ^21.0.2
const {setTimeout} = require("node:timers/promises");

const url = "https://www.wyndhamhotels.com/wyndham";

const navClick = async (page, sel) => {
  const nav = page.waitForNavigation();
  await page.click(sel);
  return nav;
};

let browser;
(async () => {
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();
  await page.goto(url);
  await page.type('[name="destination"]', "Chicago, IL, USA");
  await navClick(page, ".search-btn.btn-primary");
  const el = await page.waitForSelector("#chk-show-avail");
  await page.waitForFunction(`
    !document.querySelector("#chk-show-avail").disabled
  `);
  await el.evaluate(el => el.click());

  // not part of the logic; temporarily added so you can see
  // the box was ticked (screenshots can be hidden by modals)
  await setTimeout(60_000);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

回答

温德姆酒店官网确实存在反爬机制,针对自动化工具(如Puppeteer)有特征检测,同时你的代码在等待逻辑、交互模拟上也存在问题,导致搜索结果无法稳定加载。以下是具体解决思路和优化方案:

核心问题分析

  1. Puppeteer特征暴露:默认情况下,Puppeteer会留下window.navigator.webdriver等特征,仅更换UserAgent不足以绕过检测。
  2. 错误的等待逻辑:搜索属于单页应用的AJAX请求,并非页面跳转,原代码中waitForNavigation会导致不必要的等待甚至超时,错过结果加载时机。
  3. 机械操作被识别:输入、点击操作过于迅速,不符合正常用户的操作节奏,容易触发反爬规则。

解决方案

1. 隐藏自动化特征

使用puppeteer-extra搭配stealth插件,一键消除Puppeteer的常见识别特征,这是绕过这类反爬的关键。

2. 优化等待逻辑

放弃waitForNavigation,改用waitForNetworkIdle等待搜索请求完成,或直接等待结果列表元素出现,确保页面完全加载。

3. 模拟人类操作节奏

在输入、点击之间添加合理延迟,避免操作过于机械。

4. 处理前置弹窗

网站通常会有Cookie授权弹窗,需先处理避免阻塞后续操作。

优化后的代码

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const { setTimeout } = require('node:timers/promises');

puppeteer.use(StealthPlugin());

const url = "https://www.wyndhamhotels.com/wyndham";

let browser;
(async () => {
  browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null,
    args: [
      '--start-maximized',
      '--disable-blink-features=AutomationControlled'
    ]
  });
  const [page] = await browser.pages();

  // 设置真实浏览器环境参数
  await page.setExtraHTTPHeaders({
    'Accept-Language': 'en-US,en;q=0.9'
  });
  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36');

  await page.goto(url, { waitUntil: 'networkidle2' });

  // 处理Cookie弹窗
  try {
    await page.waitForSelector('#onetrust-accept-btn-handler', { timeout: 5000 });
    await page.click('#onetrust-accept-btn-handler');
    await setTimeout(1000);
  } catch (err) {
    console.log('无Cookie弹窗或已自动处理');
  }

  // 模拟人类输入目的地
  await page.click('[name="destination"]');
  await setTimeout(500);
  await page.type('[name="destination"]', "Chicago, IL, USA", { delay: 100 });
  await setTimeout(1000);

  // 点击搜索并等待请求完成
  await page.click(".search-btn.btn-primary");
  await page.waitForNetworkIdle({ idleTime: 2000, timeout: 30000 });

  // 处理"仅显示可预订酒店"复选框
  try {
    const el = await page.waitForSelector("#chk-show-avail", { timeout: 10000 });
    await page.waitForFunction(el => !el.disabled, {}, el);
    await el.click();
    await setTimeout(2000);

    // 等待结果列表加载完成
    await page.waitForSelector('.hotel-list-item', { timeout: 15000 });
    console.log('搜索结果已稳定加载');
  } catch (err) {
    console.error('加载失败或超时:', err);
  }

  await setTimeout(60_000);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

额外注意事项

  • 若仍不稳定,可尝试使用代理更换IP,避免频繁请求被封禁。
  • 控制请求频率,不要短时间内重复发起大量请求。
  • 网站反爬规则可能更新,需定期检查选择器和等待逻辑是否有效。

内容的提问来源于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.10 17:40:06