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));
关键说明
- 定位滚动容器:Google Maps的结果列表容器使用
div[role="feed"],通过waitForSelector确保容器加载完成后再操作。 - 动态检测加载状态:通过对比前后两次的地点数量,判断是否还有新内容加载。连续多次无新增内容时停止滚动,避免无效循环。
- 容器内滚动:直接操作滚动容器的
scrollTop属性,滚动到容器底部触发加载,而非滚动整个窗口。 - 适配性:这种基于容器滚动+内容数量检测的逻辑,可适配大多数类似的滚动加载页面,只需替换对应的容器选择器和内容元素选择器即可。
内容的提问来源于stack exchange,提问作者garson
相关产品推荐
相关产品推荐

