当前位置: 首页 > news >正文

JavaScript 渲染内容爬取实践:Puppeteer 进阶技巧

进一步探讨如何使用 Puppeteer 进行动态网页爬取,特别是如何等待页面元素加载完成、处理无限滚动加载、单页应用的路由变化以及监听接口等常见场景。

一、等待页面元素加载完成

在爬取动态网页时,确保页面元素完全加载是获取完整数据的关键。Puppeteer 提供了多种等待页面元素加载完成的方法。

1.1 使用 waitForSelector 方法

async function waitForElement() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();await page.goto('https://example.com');await page.waitForSelector('selector-of-element'); // 替换为实际的 CSS 选择器console.log('元素加载完成');// 提取元素内容const content = await page.$eval('selector-of-element', el => el.textContent);console.log('元素内容:', content);await browser.close();
}waitForElement();

1.2 使用 waitForXPath 方法

async function waitForXPathElement() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();await page.goto('https://example.com');await page.waitForXPath('//*[@id="element-id"]'); // 替换为实际的 XPath 表达式console.log('元素加载完成');// 提取元素内容const content = await page.evaluate(() => {return document.evaluate('//*[@id="element-id"]', document).iterateNext().textContent;});console.log('元素内容:', content);await browser.close();
}waitForXPathElement();

二、处理无限滚动加载

无限滚动加载是一种常见的动态网页加载方式,通过监听滚动事件动态加载更多内容。可以使用 Puppeteer 模拟滚动操作,获取所有内容。

async function handleInfiniteScroll() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();await page.goto('https://example.com/infinite-scroll-page');// 设置页面高度,模拟无限滚动const prevPageHeight = await page.evaluate('document.body.scrollHeight');let newPageHeight;while (true) {await page.evaluate(() => {window.scrollTo(0, document.body.scrollHeight);});await page.waitForTimeout(2000); // 等待内容加载newPageHeight = await page.evaluate('document.body.scrollHeight');if (newPageHeight === prevPageHeight) {break; // 如果页面高度不再变化,退出循环}prevPageHeight = newPageHeight;}// 提取内容const contentList = await page.evaluate(() => {return Array.from(document.querySelectorAll('selector-of-content-item')).map(item => item.textContent);});console.log('内容列表:', contentList);await browser.close();
}handleInfiniteScroll();

三、单页应用的路由变化处理

单页应用(SPA)通常通过 JavaScript 动态更新页面内容而不重新加载整个页面。可以使用 Puppeteer 监听路由变化,获取不同路由下的内容。

async function handleSpaRouteChanges() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();await page.goto('https://example.com/spa-page');// 监听路由变化page.on('response', async (response) => {if (response.url().includes('api/new-route')) {console.log('路由变化检测到,获取新内容');// 提取新路由下的内容const content = await page.evaluate(() => {return document.querySelector('selector-of-new-route-content').textContent;});console.log('新路由内容:', content);}});// 触发路由变化的操作await page.click('selector-of-route-link');await browser.close();
}handleSpaRouteChanges();

四、监听接口请求

在某些情况下,我们可能需要监听特定的接口请求,获取接口返回的数据。Puppeteer 提供了监听网络请求的功能。

async function listenApiRequest() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();// 监听网络请求page.on('response', async (response) => {const url = response.url();if (url.includes('api/data')) { // 监听特定接口try {const data = await response.json(); // 获取接口返回的 JSON 数据console.log('接口数据:', data);} catch (error) {console.error('解析接口数据出错:', error);}}});await page.goto('https://example.com/page-with-api-calls');// 执行触发接口请求的操作await page.click('selector-of-api-call-trigger');await browser.close();
}listenApiRequest();

五、完整示例:爬取动态电商网站

以下是一个完整的示例,演示如何使用 Puppeteer 爬取一个动态电商网站的商品列表,该网站使用无限滚动加载商品内容。

async function scrapeEcommerceProducts() {const browser = await puppeteer.launch({ headless: true });const page = await browser.newPage();await page.goto('https://example.com/products', { waitUntil: 'networkidle2' });// 设置页面高度,模拟无限滚动const prevPageHeight = await page.evaluate('document.body.scrollHeight');let newPageHeight;const productSet = new Set(); // 使用集合避免重复while (true) {// 提取当前页面的商品内容const products = await page.evaluate(() => {return Array.from(document.querySelectorAll('.product-item')).map(item => {return {title: item.querySelector('.product-title').textContent,price: item.querySelector('.product-price').textContent};});});// 将商品信息添加到集合products.forEach(product => productSet.add(JSON.stringify(product)));// 滚动页面await page.evaluate(() => {window.scrollTo(0, document.body.scrollHeight);});await page.waitForTimeout(2000); // 等待内容加载newPageHeight = await page.evaluate('document.body.scrollHeight');if (newPageHeight === prevPageHeight) {break; // 如果页面高度不再变化,退出循环}prevPageHeight = newPageHeight;}// 将集合转换为数组并输出const productList = Array.from(productSet).map(item => JSON.parse(item));console.log('商品列表:', productList);await browser.close();
}scrapeEcommerceProducts();

六、总结

通过本文的案例和实践,深入探讨了如何使用 Puppeteer 进行动态网页爬取,包括等待页面元素加载、处理无限滚动加载、单页应用的路由变化以及监听接口请求等常见场景

相关文章:

  • Socket
  • 【STL】unordered_map
  • 【速写】多LoRA并行衍生的一些思考
  • Nginx:前后端分离配置(静态资源+反向代理)
  • navicat导入sql文件 所有问题解决方法集合
  • ios开发中xxx.debug.dylib not found
  • day21 | 26暑期实习
  • windows server2019 内网离线安装mysql5.7方式;windows server2019安装软件提示丢失msvcp100.dll问题处理
  • char32_t、char16_t、wchar_t 用于 c++ 语言里存储 unicode 编码的字符,给出它们的具体定义
  • Linux系统编程 day9 SIGCHLD and 线程
  • uniapp开发2--uniapp中的条件编译总结
  • 【HarmonyOS】ArKUI框架
  • 基于贝叶斯优化的Transformer多输入单输出回归预测模型Bayes-Transformer【MATLAB】
  • HarmonyOS Next 编译之如何使用多目标产物不同包名应用
  • 字符串全排列(Java版本自己用)
  • 随机数算法原理以及模拟实现
  • 如何高效的进行生产管理?
  • UnityDots学习(四)
  • 使用java实现设计图中多个设备的自动布线,根据如下要求生成详细设计方案文档
  • 前沿分享|技术雷达202504月刊精华
  • 广汽全域赋能,领程皮卡概念车重磅登陆上海车展
  • 今年底,全国新拍电视剧、纪录片将基本实现超高清化
  • 上海又现昆虫新物种:体长仅1.5毫米,却是凶猛的捕食者
  • 全球在役最大火电厂被通报
  • 4月LPR保持不变:1年期3.1%,5年期以上3.6%
  • 谁在贩卖个人信息?教培机构信息失守,电商平台“订单解密”