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

如何在Puppeteer网页爬取中管理会话数据?

解决Puppeteer爬取immobilienscout24.de的会话管理与反爬问题

现有代码的核心问题

  1. 冗余Cookie操作:每次页面跳转后重复获取并设置Cookie完全没必要——同一个页面实例会自动维护会话Cookie,重复操作反而可能干扰正常会话。
  2. 用户目录冲突:直接使用Chrome默认的userDataDir,可能和日常使用的Chrome会话冲突,自动化场景应该用独立的用户数据目录,避免被网站识别为异常会话。
  3. 等待策略不合理:waitUntil: "load"仅等待页面所有资源加载完成,对于动态渲染的内容,应该用networkidle2(等待网络请求空闲)或等待关键元素出现,避免抓取到空内容。
  4. 固定延迟太僵化:硬编码10秒等待时间既浪费效率又不一定能避开反爬,应该根据页面加载状态动态等待。
  5. 并行处理触发反爬:tiles.map里用async会导致所有链接请求并行发起,短时间内大量请求很容易被识别为机器人。

优化后的解决方案

以下是调整后的代码,重点优化会话管理、反爬规避和请求逻辑:

const puppeteer = require('puppeteer-extra')
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
const cheerio = require('cheerio')

// 启用Stealth插件做基础反爬伪装
puppeteer.use(StealthPlugin())

// 独立的用户数据目录,避免和日常Chrome会话冲突
const USER_DATA_DIR = './puppeteer-chrome-profile'

puppeteer.launch({
    headless: false,
    args: [
        "--disable-setuid-sandbox",
        "--disable-blink-features=AutomationControlled", // 隐藏自动化标识
        "--start-maximized" // 模拟正常窗口大小
    ],
    ignoreHTTPSErrors: true,
    executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
    userDataDir: USER_DATA_DIR, // 用独立目录保存会话数据,重启可复用
    defaultViewport: null // 使用当前窗口视口,避免固定尺寸暴露机器人特征
}).then(async browser => {
    const page = await browser.newPage()
    const baseURL = 'https://www.immobilienscout24.de'

    // 模拟真实用户代理(Stealth已处理,额外增强伪装)
    await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36')

    for (let p = 1; p <= 10; p++) {
        const targetURL = `https://www.immobilienscout24.de/Suche/de/neubauwohnung-mieten?pagenumber=${p}`
        
        try {
            await page.goto(targetURL, {
                waitUntil: 'networkidle2', // 等待网络请求空闲,确保动态内容加载完成
                timeout: 30000 // 超时时间设为30秒,避免因网络问题卡死
            })

            // 等待关键元素出现,确认页面渲染完成
            await page.waitForSelector('.result-list__listing', { timeout: 20000 })

            // 模拟人类滚动行为,触发页面动态加载逻辑
            await page.evaluate(() => {
                window.scrollTo(0, document.body.scrollHeight)
            })
            await page.waitForTimeout(Math.floor(Math.random() * 3000) + 2000) // 随机延迟2-5秒

            const html = await page.content()
            const $ = cheerio.load(html)
            const tiles = $('.result-list__listing')

            // 串行处理每个链接,避免并行请求触发反爬
            for (const item of tiles.toArray()) {
                let link = $(item).find('a.result-list-entry__brand-title-container').attr('href')
                if (link && link.includes("expose")) {
                    link = baseURL + link
                    console.log(link)

                    // 若需进入详情页,可打开新页面处理(示例仅打印链接)
                    // const detailPage = await browser.newPage()
                    // await detailPage.goto(link, { waitUntil: 'networkidle2' })
                    // // 处理详情页逻辑...
                    // await detailPage.close()
                    // await page.waitForTimeout(Math.floor(Math.random() * 4000) + 1000)
                }
            }

            // 页面间随机延迟3-8秒,模拟人类浏览间隔
            await page.waitForTimeout(Math.floor(Math.random() * 5000) + 3000)
        } catch (error) {
            console.error(`第${p}页加载失败:`, error.message)
            // 失败后可重试或跳过当前页面
            continue
        }
    }

    await browser.close()
})

关键优化点说明

  • 独立会话目录:userDataDir指定本地独立目录,Puppeteer会自动保存Cookie、localStorage等会话数据,重启后可复用,避免每次启动重新建立会话。
  • 增强反爬伪装:添加--disable-blink-features=AutomationControlled参数隐藏Chrome的自动化标识,配合Stealth插件进一步降低被识别概率。
  • 动态等待逻辑:用networkidle2和waitForSelector确保页面内容完全渲染,替代固定延迟,同时加入随机延迟模拟人类行为。
  • 串行请求控制:将tiles.map改为for...of循环,串行处理每个链接,避免短时间内大量请求触发反爬机制。
  • 错误处理:添加try-catch捕获页面加载失败的情况,避免整个爬虫因单页出错而崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:25:19