2024-10-31 20:26:49
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。 Puppeteer API 是分层次的,反映了浏览器结构。
Puppeteer 使用 DevTools 协议 与浏览器进行通信。
Browser 实例可以拥有浏览器上下文。
BrowserContext 实例定义了一个浏览会话并可拥有多个页面。
Page 至少有一个框架:主框架。 可能还有其他框架由 iframe 或 框架标签 创建。
frame 至少有一个执行上下文 - 默认的执行上下文 - 框架的 JavaScript 被执行。 一个框架可能有额外的与 扩展 关联的执行上下文。
Worker 具有单一执行上下文,并且便于与 WebWorkers 进行交互。
【Puppeteer 错误处理】Error handling
如果 Puppeteer 方法无法执行一个请求,就会抛出一个错误。例如,page.waitForSelector(selector[, options])选择器如果在给定的时间范围内无法匹配节点,就会失败。 对于某些类型的错误,Puppeteer 使用特定的错误类处理。这些类可以通过 require('puppeteer/Errors') 获得。 支持的类列表:
TimeoutError 一个处理超时错误的例子:
const?{????TimeoutError}?=?require('puppeteer/Errors');?//?...try?{????await?page.waitForSelector('.foo');}?catch(e)?{????if?(e?instanceof?TimeoutError)?{??????//?如果超时,做一些处理。?????}}Puppeteer Working with Chrome ExtensionsPuppeteer 可以用来测试 Chrome 扩展
注意 Chrome / Chromium 扩展当前只能在非无头模式下使用。
下面的代码用来处理扩展的background page,该扩展的代码在 ./my-extension:
const?puppeteer?=?require('puppeteer');?(async()?=?>?{const?pathToExtension?=?require('path').join(__dirname,?'my-extension');const?browser?=?puppeteer.launch({????headless:?false,????args:?[`--disable?-?extensions?-?except?=?$?{????????pathToExtension????}`,?`--load?-?extension?=?$?{????????pathToExtension????}`]});const?targets?=?await?browser.targets();const?backgroundPageTarget?=?targets.find(target?=?>target.type()?===?'background_page');const?backgroundPage?=?await?backgroundPageTarget.page();?//?像处理任何其他页面一样测试背景页面。??await?browser.close();})();【Puppeteer class:puppeteer】Puppeteer 模块提供了一种启动 Chromium 实例的方法。 下面就是使用 Puppeteer 进行自动化的一个典型示例:
const?puppeteer?=?require('puppeteer');puppeteer.launch().then(async?browser?=?>{const?page?=?await?browser.newPage();await?page.goto('https://www.google.com');?//?其他操作...??await?browser.close();});Methodspuppeteer.connect(options)v0.9.0
puppeteer.createBrowserFetcher([options])v0.9.0
puppeteer.defaultArgs([options])v0.9.0
puppeteer.executablePath()v0.9.0
puppeteer.launch([options])v0.9.0
Methodspuppeteer.connect(options)v0.9.0options <Object>
browserWSEndpoint <string> 一个 浏览器 websocket 端点链接。
ignoreHTTPSErrors <boolean> 是否在导航期间忽略 HTTPS 错误. 默认是 false。
defaultViewport <?Object> 为每个页面设置一个默认视口大小。默认是 800x600。如果为 null 的话就禁用视图口。
width <number> 页面宽度像素。
height <number> 页面高度像素。
deviceScaleFactor <number> 设置设备的缩放(可以认为是 dpr)。默认是 1。
isMobile <boolean> 是否在页面中设置了meta viewport 标签。默认是 false。
hasTouch``<boolean> 指定viewport是否支持触摸事件。默认是 false。
isLandscape <boolean> 指定视口是否处于横向模式。默认是 false。
slowMo <number> 将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。
returns: <Promise<Browser>> 此方法将 Puppeteer 添加到已有的 Chromium 实例。
puppeteer.createBrowserFetcher([options])v0.9.0options <Object>
host <string> 要使用的下载主机. 默认是 https://storage.googleapis.com。
path <string> 下载文件夹的路径. 默认是 <root>/.local-chromium, <root> 是 puppeteer 的包根目录。
platform <string> 可能的值有: mac, win32, win64, linux。默认是当前平台。
returns: <BrowserFetcher>
puppeteer.defaultArgs([options])v0.9.0options <Object> 设置浏览器可选项。有一下字段:
headless <boolean> 是否在 无头模式 下运行浏览器。默认是 true 除非 devtools 选项是 true。
args <Array<string>> 传递给浏览器实例的其他参数。可以 在这 找到 Chromium 标志列表。
userDataDir <string> 用户数据目录 的路径。
devtools <boolean> 是否为每个选项卡自动打开 DevTools 面板。如果这个选项是 true 的话, headless 选项将被设置为 false。
returns: <Array<string>> Chromium 启动时使用的默认参数。
puppeteer.executablePath()v0.9.0returns: <string> Puppeteer 希望找到绑定的 Chromium 的路径。
如果使用 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD跳过下载,则 Chromium 可能不存在。
puppeteer.launch([options])v0.9.0options <Object> 在浏览器上设置的一组可配置选项。 有以下字段:
ignoreHTTPSErrors <boolean> 是否在导航期间忽略 HTTPS 错误. 默认是 false。
headless <boolean> 是否以 无头模式 运行浏览器。默认是 true,除非 devtools 选项是 true。
executablePath <string> 可运行 Chromium 或 Chrome 可执行文件的路径,而不是绑定的 Chromium。如果 executablePath 是一个相对路径,那么他相对于 当前工作路径 解析。
slowMo <number> 将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。
defaultViewport <?Object> 为每个页面设置一个默认视口大小。默认是 800x600。如果为 null 的话就禁用视图口。
width <number> 页面宽度像素。
height <number> 页面高度像素。
deviceScaleFactor <number> 设置设备的缩放(可以认为是 dpr)。默认是 1。
isMobile <boolean> 是否在页面中设置了 meta viewport 标签。默认是 false。
hasTouch``<boolean> 指定viewport是否支持触摸事件。默认是 false。
isLandscape <boolean> 指定视口是否处于横向模式。默认是 false。
args <Array<string>> 传递给浏览器实例的其他参数。 这些参数可以参考 这里。
ignoreDefaultArgs <(boolean|<Array<string>>)> 如果是 true,那就不要使用 puppeteer.defaultArgs()。 如果给出了数组,则过滤掉给定的默认参数。这个选项请谨慎使用。默认为 false。
handleSIGINT <boolean> Ctrl-C 关闭浏览器进程。默认是 true。
handleSIGTERM <boolean> 关闭 SIGTERM 上的浏览器进程。默认是 true。
handleSIGHUP <boolean> 关闭 SIGHUP 上的浏览器进程。默认是 true.
timeout <number> 等待浏览器实例启动的最长时间(以毫秒为单位)。默认是 30000 (30 秒). 通过 0 来禁用超时。
dumpio <boolean> 是否将浏览器进程标准输出和标准错误输入到 process.stdout 和 process.stderr 中。默认是 false。
userDataDir <string> 用户数据目录 路径。
env <Object> 指定浏览器可见的环境变量。默认是process.env。
devtools <boolean> 是否为每个选项卡自动打开DevTools面板。如果这个选项是 true,headless 选项将会设置成 false。
pipe <boolean> 通过管道而不是WebSocket连接到浏览器。默认是 false。
returns: <Promise<Browser>> 浏览器实例支持 Promise。 这个方法结合了下面3个步骤:
使用 puppeteer.defaultArgs() 作为一组默认值来启动 Chromium。启动浏览器并根据 executablePath ,handleSIGINT,dumpio 和其他选项开始管理它的进程。 创建一个 Browser 类的实例,并根据 defaultViewport,slowMo 和 ignoreHTTPSErrors 初始化它。 ignoreDefaultArgs 选项可用于自定义(1)步骤的行为。 例如,要从参数中过滤掉 --mute-audio:
const?browser?=?await?puppeteer.launch({????ignoreDefaultArgs:?['--mute-audio']});Puppeteer 浏览器extends: EventEmitter 当 Puppeteer 连接到一个 Chromium 实例的时候会通过 puppeteer.launch 或 puppeteer.connect 创建一个 Browser 对象。 下面是使用 Browser 创建 Page 的例子
const?puppeteer?=?require('puppeteer');puppeteer.launch().then(async?browser?=?>{const?page?=?await?browser.newPage();await?page.goto('https://example.com');await?browser.close();});一个断开连接和重连到 Browser 的例子:
const?puppeteer?=?require('puppeteer');puppeteer.launch().then(async?browser?=?>{?//?存储节点以便能重新连接到?Chromium??const?browserWSEndpoint?=?browser.wsEndpoint();??//?从?Chromium?断开和?puppeteer?的连接??browser.disconnect();??//?使用节点来重新建立连接??const?browser2?=?await?puppeteer.connect({browserWSEndpoint});??//?关闭?Chromium??await?browser2.close();});Puppeteer 页面Page 提供操作一个 tab 页或者 extension background page 的方法。一个 Browser 实例可以有多个 Page 实例。 下面的例子创建一个 Page 实例,导航到一个 url ,然后保存截图:
const?puppeteer?=?require('puppeteer');puppeteer.launch().then(async?browser?=?>{??const?page?=?await?browser.newPage();??await?page.goto('https://example.com');??await?page.screenshot({??????path:?'screenshot.png'??});??await?browser.close();});Page会触发多种事件(下面描述的),可以用 node原生的方法 来捕获处理,比如 on,once 或者 removeListener。 下面的例子捕获了一个 page 实例的 load 事件,打印了一句话:
page.once('load',?()?=>?console.log('Page?loaded!'));可以用 removeListener 取消对事件的监听:
function?logRequest(interceptedRequest)?{??console.log('A?request?was?made:',?interceptedRequest.url());}page.on('request',?logRequest);?//?一段时间后...page.removeListener('request',?logRequest);###?Methods####?page.$(selector)v0.9.0-?selector?`<string>`?选择器?返回:?`<Promise<?ElementHandle>>`-?此方法在页面内执行?`document.querySelector`。如果没有元素匹配指定选择器,返回值是?null。-?page.mainFrame().$(selector)?的简写。####?page.$$(selector)v0.9.0-?selector?`<string>`?选择器-?返回:?`<Promise<Array<ElementHandle>>>`-?此方法在页面内执行?`document.querySelectorAll`。如果没有元素匹配指定选择器,返回值是?[]。-?`page.mainFrame().$$(selector)?`的简写。####?page.waitForSelector(".index-content?.click-zoom?a")-?等待页面元素加载完成```jsawait?page.waitForSelector(".index-content?.click-zoom?a")page.waitFor(1000)等待1000毫秒执行
const?puppeteer?=?require('puppeteer');?(async()?=?>?{const?pathToExtension?=?require('path').join(__dirname,?'my-extension');const?browser?=?puppeteer.launch({????headless:?false,????args:?[`--disable?-?extensions?-?except?=?$?{????????pathToExtension????}`,?`--load?-?extension?=?$?{????????pathToExtension????}`]});const?targets?=?await?browser.targets();const?backgroundPageTarget?=?targets.find(target?=?>target.type()?===?'background_page');const?backgroundPage?=?await?backgroundPageTarget.page();?//?像处理任何其他页面一样测试背景页面。??await?browser.close();})();0page.click('.btn')const?puppeteer?=?require('puppeteer');?(async()?=?>?{const?pathToExtension?=?require('path').join(__dirname,?'my-extension');const?browser?=?puppeteer.launch({????headless:?false,????args:?[`--disable?-?extensions?-?except?=?$?{????????pathToExtension????}`,?`--load?-?extension?=?$?{????????pathToExtension????}`]});const?targets?=?await?browser.targets();const?backgroundPageTarget?=?targets.find(target?=?>target.type()?===?'background_page');const?backgroundPage?=?await?backgroundPageTarget.page();?//?像处理任何其他页面一样测试背景页面。??await?browser.close();})();1点击class 为btn元素
page.evaluate执行原生js
const?puppeteer?=?require('puppeteer');?(async()?=?>?{const?pathToExtension?=?require('path').join(__dirname,?'my-extension');const?browser?=?puppeteer.launch({????headless:?false,????args:?[`--disable?-?extensions?-?except?=?$?{????????pathToExtension????}`,?`--load?-?extension?=?$?{????????pathToExtension????}`]});const?targets?=?await?browser.targets();const?backgroundPageTarget?=?targets.find(target?=?>target.type()?===?'background_page');const?backgroundPage?=?await?backgroundPageTarget.page();?//?像处理任何其他页面一样测试背景页面。??await?browser.close();})();2示例代码执行
安装 puppeteer 依赖包
node xxx.js 运行js
const?puppeteer?=?require('puppeteer');?(async()?=?>?{const?pathToExtension?=?require('path').join(__di