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

Puppeteer滚动无法获取Google Maps全部内容的技术求助

Puppeteer抓取Google Maps滚动加载内容问题

问题描述

使用Puppeteer抓取某Google Maps列表页面的完整HTML源码时,遇到滚动加载问题:页面共有27个地点,但当前代码只能获取自动加载的前19个,滚动触发加载的剩余内容无法获取。希望解决方案能适配其他类似滚动加载页面。曾参考过Puppeteer滚动div的相关方案,但因找不到明确的滚动div名称,不确定是否适用。

已尝试方案

尝试配置光标位置、增加滚动次数,均无效果。原代码如下:

const googleMapsURL = 'https://www.google.com/maps/@41.9128478,-87.808076,11z/data=!4m2!11m1!2sJ1hSE9TaCGi4u4zFeqFDOj8weXjZRQ?entry=ttu';

function scrapeGoogleMaps() {
    return puppeteer.launch()
        .then(browser => browser.newPage())
        .then(page => {
            return page.goto(googleMapsURL, { waitUntil: 'networkidle2' })
                .then(() => page);
        })
        .then(page => {
            const scrollCount = 10;
            const scrollInterval = 1000; // milliseconds

             // Function to scroll and wait for content to load
            const scrollAndLoad = () => {
                return page.evaluate(scrollPercentage => {
                    const innerHeight = window.innerHeight;
                    const scrollX = window.innerWidth * 0.05;
                    window.scrollTo(scrollX, innerHeight / 2);
                    console.log('Inner Height:', innerHeight);
                    console.log('Scroll X:', scrollX);
                }, 0.05).then(() => {
                    return new Promise(resolve => setTimeout(resolve, scrollInterval));
                });
            };

            // Perform scrolling sequentially
            let promiseChain = Promise.resolve();
            for (let i = 0; i < scrollCount; i++) {
                promiseChain = promiseChain.then(scrollAndLoad);
            }

            // After all scrolling, capture the content
            return promiseChain.then(() => page.content());
        })
        .then(content => {
            console.log("Should print the full content, but only prints the first 19 results");
            console.log(content);
            return content;
        })
        .catch(error => {
            console.error('Error during scraping:', error);
            throw error;
        });
}

scrapeGoogleMaps()
    .then(() => console.log('Scraping completed successfully.'))
    .catch(error => console.error('Error during scraping:', error))
    .finally(() => process.exit());

解决方案

Google Maps的结果列表并非通过整个窗口滚动加载,而是在特定的内部容器中滚动。核心思路是找到这个滚动容器,动态滚动直到内容加载完成,而非固定次数滚动。

修改后的代码

const puppeteer = require('puppeteer');
const googleMapsURL = 'https://www.google.com/maps/@41.9128478,-87.808076,11z/data=!4m2!11m1!2sJ1hSE9TaCGi4u4zFeqFDOj8weXjZRQ?entry=ttu';

async function scrapeGoogleMaps() {
    let browser;
    try {
        browser = await puppeteer.launch({ headless: false }); // 可改为true启用无头模式
        const page = await browser.newPage();
        await page.goto(googleMapsURL, { waitUntil: 'networkidle2', timeout: 60000 });

        // 等待滚动容器出现(Google Maps结果列表容器通常是role="feed"的div)
        await page.waitForSelector('div[role="feed"]', { timeout: 30000 });

        let previousCount = 0;
        let currentCount = 0;
        let retryCount = 0;
        const maxRetries = 3; // 连续3次无新内容则停止滚动

        while (retryCount < maxRetries) {
            // 获取当前已加载的地点数量
            currentCount = await page.evaluate(() => {
                return document.querySelectorAll('div[role="feed"] > div[jsaction]').length;
            });

            if (currentCount === previousCount) {
                retryCount++;
            } else {
                retryCount = 0;
                previousCount = currentCount;
            }

            // 滚动容器到底部触发加载
            await page.evaluate(() => {
                const feedContainer = document.querySelector('div[role="feed"]');
                feedContainer.scrollTop = feedContainer.scrollHeight;
            });

            // 等待内容加载完成(可根据网络情况调整时长)
            await page.waitForTimeout(2000);
        }

        // 获取完整页面HTML
        const fullContent = await page.content();
        console.log(`已加载${currentCount}个地点,抓取完成`);
        console.log(fullContent);
        return fullContent;
    } catch (error) {
        console.error('抓取出错:', error);
        throw error;
    } finally {
        if (browser) {
            await browser.close();
        }
        process.exit();
    }
}

scrapeGoogleMaps()
    .then(() => console.log('抓取完成'))
    .catch(error => console.error('抓取失败:', error));

关键说明

  1. 定位滚动容器:Google Maps的结果列表容器使用div[role="feed"],通过waitForSelector确保容器加载完成后再操作。
  2. 动态检测加载状态:通过对比前后两次的地点数量,判断是否还有新内容加载。连续多次无新增内容时停止滚动,避免无效循环。
  3. 容器内滚动:直接操作滚动容器的scrollTop属性,滚动到容器底部触发加载,而非滚动整个窗口。
  4. 适配性:这种基于容器滚动+内容数量检测的逻辑,可适配大多数类似的滚动加载页面,只需替换对应的容器选择器和内容元素选择器即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 01:43:13