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

Puppeteer 实践笔记

概念理解

Puppeteer 是一个 Node.js 库,提供了高级 API 来控制无头(headless)Chrome 或 Chromium 浏览器。它通过 Chrome DevTools Protocol(CDP)与浏览器通信,可以实现页面自动化、爬虫、性能测试等功能。

Puppeteer 默认会安装对应版本的浏览器,如果只是想使用 Puppeteer 提供的高级 API 去控制浏览器 ,可以直接使用puppeteer-core而不是puppeteerpuppeteer具体安装的浏览器版本可以查看 支持的浏览器。

核心概念

  • Browser(浏览器实例):通过puppeteer.launch()创建的浏览器实例,可以管理多个页面。
  • Page(页面实例):代表浏览器中的一个标签页,每个页面都是独立的执行环境。
  • ElementHandle(元素句柄):通过选择器获取的 DOM 元素引用,可以对其进行操作。
  • CDP(Chrome DevTools Protocol):Chrome 开发者工具协议,Puppeteer 通过该协议与浏览器通信。

应用场景

  • 自动化脚本操作:自动化表单填写、页面操作等。
  • 爬虫:抓取网页数据,处理动态内容。
  • 自动化测试:端到端测试、UI 测试。
  • 性能分析:页面性能监控、性能报告生成,小推一下自己在维护的 MCP Server 项目 puppeteer-debugger-mcp-server。
  • 截图和 PDF 生成:页面截图、PDF 导出。

基础使用

创建浏览器实例

constbrowser=awaitpuppeteer.launch({headless:'new',defaultViewport:{width:1920,height:1080,},executablePath:path.resolve(EXCUTABLE_PATH),});// 关闭浏览器awaitbrowser.close();

参数说明

  • headless:无头浏览器设置,可选值:
    • false:显示浏览器窗口。
    • 'new':启用新的无头浏览器模式(推荐)。
    • true:已废弃,因为旧版无头浏览器存在各种问题。
    • 无头浏览器(不显示浏览器页面)有更少的内存占用和 CPU 消耗,适合命令行环境,但可能触发反爬机制,需要手动添加userAgent等参数。
  • defaultViewport:浏览器内的页面视窗大小。
  • executablePath:浏览器的运行路径,不填则使用 Puppeteer 安装时自带的 Chromium 浏览器。

创建页面实例

constpage=awaitbrowser.newPage();// 关闭页面awaitpage.close();

执行操作后,Puppeteer 会在当前浏览器内新建一个页面,每个page代表一个标签页,每个标签页的操作都是独立开的。

页面跳转

awaitpage.goto(url,options);

参数说明

  • url:要跳转的页面地址
  • options(可选):配置选项,如waitUntil(等待条件)、timeout(超时时间)等

元素操作

选中元素

Puppeteer 提供了两种方式来选中和操作元素:

1. 使用 CDP 协议选中元素
constelementHandle=awaitpage.$(selector);

Puppeteer 调用底层 CDP 协议去选中元素,会根据元素类型返回相应的ElementHandle对象,此时可以直接使用对象来进行元素相关操作。

2. 使用 JavaScript 代码操作 DOM
constresult=awaitpage.evaluate(()=>{returndocument.querySelector(selector);});

page.evaluate()是在页面内执行代码的函数,通过返回值来获取元素或执行操作。

注意page.evaluate()内部是一个独立于 Node.js 进程的浏览器环境,外部变量无法直接在函数内使用,需要通过page.evaluate()的第二个参数传入:

constname='Aliex';awaitpage.evaluate((name)=>{console.log(name);},name);

输入内容

awaitpage.type(selector,text,options);

参数说明

  • selector:被输入的元素选择器。
  • text:输入到浏览器中的内容。
  • options(可选):配置选项,如输入延迟等。

page.type()可以模拟键盘操作,在特定元素中键入内容。也可以模拟键盘快捷键操作。

点击元素

awaitpage.click(selector,options);

参数说明

  • selector:被点击的元素选择器。
  • options(可选):配置选项,如点击次数、延迟等。

通过该方法可以点击页面上的元素,不过有时行不通,需要借助page.evaluate()这种原生操作去实现点击。

等待操作

由于页面加载会涉及很多脚本执行,通常需要一些等待操作来确保页面或元素已加载完成。Puppeteer 提供了各种环境下的waitFor函数供我们使用。

等待一段时间

awaitpage.waitForTimeout(timeout);

可以控制一定的等待时间,在这之后才继续执行后面的函数。

等待元素存在于页面

awaitpage.waitForSelector(selector,options);

可用于等待当前页面元素出现,支持 query 选择方式。

但在测试中发现有时候会选不到相应的元素,所以可以使用另外一种方式:

awaitpage.waitForFunction(()=>{returndocument.querySelector(selector);});

waitForFunction()是一种较为灵活的等待方式,我们可以用它来等待元素加载完毕,或者实现一些其他操作,例如等待元素显示出来:

awaitpage.waitForFunction(()=>{returndocument.querySelector(selector).style.display!=='none';});

只要返回的结果为true,函数就会停止继续等待。

等待页面加载完毕

awaitpage.waitForNavigation(options);

可以等待页面加载完毕后再执行后面的函数,即页面左上角的刷新图标停止转动之后,才执行后面的代码。

设置等待超时时间

有时候因为网络问题导致出现网卡的情况,会导致等待时间过长。Puppeteer 本身会在等待超过 30s 之后停止等待,因此在需要的情况下,可以重新设置超时等待时间:

page.setDefaultTimeout(timeout);

等待网络请求

waitForRequest()是 Puppeteer 中的一个方法,用于等待特定的请求发出:

awaitpage.waitForRequest(urlOrPredicateOrPattern,options);

参数说明

  • urlOrPredicateOrPattern:可接受字符串、正则表达式或预定义的请求匹配器函数来指定需要等待的请求。
  • options(可选):可传递一个对象来指定附加选项,如超时时间等。

示例用法

// 等待特定 URL 的请求awaitpage.waitForRequest('https://example.com/api/data');// 使用正则表达式awaitpage.waitForRequest(/api/data$/);// 使用自定义匹配器函数awaitpage.waitForRequest((request)=>request.url().includes('api')&&request.method()==='POST');

在上述示例中,waitForRequest()会等待发出匹配条件的请求。一旦请求被发出,waitForRequest()会立即返回。

高级技巧

文件上传

如果页面比较遵守 W3C 开发规范,通常上传元素会使用<input type="file" />去实现。这时就可以通过 Puppeteer 原生的元素获取方式来进行文件上传:

constvideoInputHandle=awaitpage.$(inputSelector);// uploadFile 是 ElementHandle input 对象特有的方法awaitvideoInputHandle.uploadFile(path);

参数说明

  • path:需要上传的本地文件路径,不支持网络文件。

这样就可以触发本地上传功能。

将函数注入到页面内

使用page.exposeFunction()将本地函数暴露到页面的window对象上:

// 注入函数awaitpage.exposeFunction('handleMutation',(str)=>{console.log('DOM mutated!',str);console.log(page);// 这里可以拿到外部内容});awaitpage.evaluate(()=>{constobserver=newMutationObserver(()=>{window.handleMutation('params');// 可以传递参数到注入的函数中});observer.observe(document.querySelector('.element-class'),{childList:true,subtree:true,attributes:true,});});

页面跳转时注入/执行代码

在页面跳转时调用page.evaluate(),可能会因为 page 的上下文环境不同,导致代码执行崩溃。

解决方式是保存 URL 地址,在执行之前进行比较判断:

consturl1=page.url();// ... 其他操作consturl2=page.url();// 避免执行时上下文环境不同导致 Puppeteer 崩溃if(url1===url2){awaitpage.evaluate(fn);}

清空浏览器 Cookie

利用 CDP (Chrome DevTools Protocol) 清除 Cookie

constpage=awaitbrowser.newPage();constclient=awaitpage.target().createCDPSession();awaitclient.send('Network.clearBrowserCookies');

提升浏览器运行性能

constbrowser=awaitpuppeteer.launch({headless:'new',defaultViewport:{width:1920,height:1080,},args:['--disable-gpu','--disable-dev-shm-usage','--disable-setuid-sandbox','--no-first-run','--no-sandbox','--no-zygote',],});

这些参数可以禁用一些不必要的功能,减少资源消耗,提升浏览器运行性能。

分支流程处理

当有两个 Puppeteer 异步流程时,可以使用Promise.any()来实现异步分支:

constres=awaitPromise.any([page.waitForNavigation(),page.waitForTimeout(15000),]);

这样可以实现 “等待导航完成或超时 15 秒” 的逻辑。

思考

1. 为什么需要使用无头浏览器模式?

无头浏览器模式(headless)不显示浏览器窗口,有更少的内存占用和 CPU 消耗,适合在服务器环境或命令行界面中使用。但可能会触发一些网站的反爬机制,需要手动添加userAgentviewport等参数来模拟真实浏览器。

2.page.evaluate()page.$()的区别是什么?

  • page.$()使用 CDP 协议选中元素,返回ElementHandle对象,可以直接调用 Puppeteer 提供的方法进行操作。
  • page.evaluate()在页面内执行 JavaScript 代码,可以访问页面的 DOM 和全局对象,但返回的是序列化后的值,无法直接操作 DOM 元素。

3. 如何避免页面跳转时的上下文丢失问题?

在页面跳转时,页面的上下文环境会发生变化,如果在跳转过程中调用page.evaluate()可能会失败。解决方式是保存跳转前后的 URL,在执行代码前比较 URL 是否一致,或者使用page.waitForNavigation()等待跳转完成后再执行操作。

总结

  • Puppeteer 核心概念:通过 Browser、Page、ElementHandle 等对象实现对浏览器的控制,使用 CDP 协议与浏览器通信。
  • 基础操作:创建浏览器实例、新建页面、页面跳转、元素操作(选中、输入、点击)是 Puppeteer 的基础功能。
  • 等待机制:提供了多种等待函数(waitForSelectorwaitForNavigationwaitForFunction等)来确保页面或元素已加载完成。
  • 高级技巧:文件上传、函数注入、性能优化、分支流程处理解决复杂场景下的问题。
  • 注意事项:需要注意页面上下文环境的变化、无头浏览器可能触发反爬机制、等待超时等问题。

参考内容

  • Puppeteer 官方文档
  • Chrome DevTools Protocol
  • Puppeteer性能优化与执行速度提升
http://www.cnnetsun.cn/news/187543.html

相关文章:

  • 城通网盘直链提取神器:3步告别繁琐下载
  • WarcraftHelper魔兽辅助工具终极完整简单使用手册
  • 城通网盘下载加速:ctfileGet解析工具完整使用指南
  • 如何高效掌控演讲时间?这款免费PPT计时器让你告别超时尴尬!
  • 城通网盘直链提取终极指南:3步突破下载限制
  • Sunshine多设备游戏串流终极指南:打造完美家庭娱乐中心
  • 抖音视频批量下载神器:告别繁琐,轻松收藏心仪内容
  • 终极演讲时间管理方案:PPTTimer智能助手完全指南
  • Flutter 2025 状态管理工程体系:从简单共享到复杂协同,构建可预测、可测试、可维护的状态流架构
  • ComfyUI-VideoHelperSuite视频合成节点完整修复终极指南
  • WarcraftHelper终极指南:解决魔兽争霸现代系统兼容性难题
  • Cats Blender插件:5分钟完成VRChat模型优化的终极指南
  • ncmdumpGUI:轻松解密网易云音乐加密文件的专业解决方案
  • ES在物联网实时数据场景中的部署方案
  • 城通网盘直链解析终极方案:3分钟实现高速下载的完整教程
  • 城通网盘直连解析器:3步告别繁琐下载流程
  • Sunshine游戏串流:打造家庭多设备娱乐中枢的完整指南
  • 虾皮怎样避免订单逾期出货
  • WarcraftHelper:让经典魔兽争霸在现代系统重获新生
  • Sunshine游戏串流终极指南:三步打造个人云游戏系统
  • WarcraftHelper:魔兽争霸III现代化优化完整指南
  • 魔兽争霸III兼容性修复:WarcraftHelper技术指南
  • 终极指南:wx-calendar微信小程序日历组件从零到精通实战
  • 闲鱼数据采集工具:5分钟快速上手安卓自动化爬虫
  • Windows平台控制器驱动冲突终极解决方案:多软件共存架构深度解析
  • 魔兽争霸III兼容性修复工具:解决现代系统运行难题
  • Sketch MeaXure:智能化设计标注的革新之路
  • 魔兽争霸III现代化重生指南:解锁经典游戏的终极体验
  • “三层过滤法”降ai率绝了,一篇文章教你如何快速降ai【附降ai提示词】
  • 跨国企业 AI-ITSM 多终端支持 —— 构建智能全球服务管理平台