Puppeteer API
Overview
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。
Puppeteer API 是分层次的,反映了浏览器结构。
注意:在下面的图表中,浅色框体内容目前不在 Puppeteer 中体现。
Puppeteer
使用 DevTools 协议 与浏览器进行通信。Browser
实例可以拥有浏览器上下文。BrowserContext
实例定义了一个浏览会话并可拥有多个页面。Page
至少有一个框架:主框架。 可能还有其他框架由 iframe 或 框架标签 创建。frame
至少有一个执行上下文 - 默认的执行上下文 - 框架的 JavaScript 被执行。 一个框架可能有额外的与 扩展 关联的执行上下文。Worker
具有单一执行上下文,并且便于与 WebWorkers 进行交互。
(图例资源: 链接)
puppeteer vs puppeteer-core
自 v1.7.0 以来的每个版本我们都发布了两个包:
puppeteer
是浏览器自动化的 产品。安装后,它会下载一个版本的 Chromium,然后使用puppeteer-core
驱动工作。作为最终用户产品,puppeteer
支持一堆方便的 PUPPETEER_*
env 变量来调整行为。
puppeteer-core
是一个 库 来帮助驱动任何支持 DevTools 协议的东西。puppeteer-core
在安装时不会下载 Chromium。作为一个库,puppeteer-core
是完全是通过其编程接口驱动的并忽略所有PUPPETEER_*
env 变量。
总结一下,puppeteer-core
与 puppeteer
不同的地方:
puppeteer-core
在安装时不会自动下载 Chromium。puppeteer-core
忽略所有的PUPPETEER_*
env 变量.
在大多数情况下,你可以使用 puppeteer
包。
然而, 如果是下面这些情况那你需要使用 puppeteer-core
:
- 你正在构建 DevTools 协议顶部的另一个最终用户产品或库。例如,可以使用
puppeteer-core
构建 PDF 生成器并编写下载headless_shell
的自定义install.js
脚本而不是 Chromium 来节省磁盘空间。 - 你正在打包 Puppeteer 用在 Chrome 扩展应用或浏览器中以使用 DevTools 协议,因为下载额外的 Chromium 二进制文件不是必须的。
当使用 puppeteer-core
时,使用下面这行代替原来的使用方式:
const puppeteer = require('puppeteer-core');
Environment Variables
Puppeteer 寻找某些环境变量来帮助其操作。 如果 puppeteer 在环境中没有找到它们,这些变量的小写变体将从 npm 配置 中使用。
HTTP_PROXY
,HTTPS_PROXY
,NO_PROXY
- 定义用于下载和运行 Chromium 的 HTTP 代理设置。PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
- 请勿在安装步骤中下载绑定的 Chromium。PUPPETEER_DOWNLOAD_HOST
- 覆盖用于下载 Chromium 的 URL 的主机部分。PUPPETEER_CHROMIUM_REVISION
- 在安装步骤中指定一个你喜欢 puppeteer 使用的特定版本的 Chromium。PUPPETEER_EXECUTABLE_PATH
- 指定一个 Chrome 或者 Chromium 的可执行路径,会被用于puppeteer.launch
。具体关于可执行路径参数的意义,可参考puppeteer.launch([options])
。
NOTE 在使用
puppeteer-core
时,上述环境变量中以 PUPPETEER_* 开头的会被忽略.
Error handling
如果 Puppeteer 方法无法执行一个请求,就会抛出一个错误。例如,page.waitForSelector(selector[, options]) 选择器如果在给定的时间范围内无法匹配节点,就会失败。
对于某些类型的错误,Puppeteer 使用特定的错误类处理。这些类可以通过 require('puppeteer/Errors')
获得。
支持的类列表:
一个处理超时错误的例子:
const {TimeoutError} = require('puppeteer/Errors');
// ...
try {
await page.waitForSelector('.foo');
} catch (e) {
if (e instanceof TimeoutError) {
// 如果超时,做一些处理。
}
}
Working with Chrome Extensions
Puppeteer 可以用来测试 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();
})();
注意 目前还无法测试扩展弹出窗口或内容脚本。
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();
});
puppeteer.connect(options)
options
<Object>browserWSEndpoint
<string> 一个 浏览器 websocket 端点链接。ignoreHTTPSErrors
<boolean> 是否在导航期间忽略 HTTPS 错误. 默认是false
。defaultViewport
<?Object> 为每个页面设置一个默认视口大小。默认是 800x600。如果为null
的话就禁用视图口。slowMo
<number> 将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。
- returns: <Promise<Browser>>
此方法将 Puppeteer 添加到已有的 Chromium 实例。
puppeteer.createBrowserFetcher([options])
options
<Object>- returns: <BrowserFetcher>
puppeteer.defaultArgs([options])
Chromium 启动时使用的默认参数。
puppeteer.executablePath()
- returns: <string> Puppeteer 希望找到绑定的 Chromium 的路径。 如果使用
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
跳过下载,则 Chromium 可能不存在。
puppeteer.launch([options])
options
<Object> 在浏览器上设置的一组可配置选项。 有以下字段:ignoreHTTPSErrors
<boolean> 是否在导航期间忽略 HTTPS 错误. 默认是false
。headless
<boolean> 是否以 无头模式 运行浏览器。默认是true
,除非devtools
选项是true
。executablePath
<string> 可运行 Chromium 或 Chrome 可执行文件的路径,而不是绑定的 Chromium。如果executablePath
是一个相对路径,那么他相对于 当前工作路径 解析。slowMo
<number> 将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。defaultViewport
<?Object> 为每个页面设置一个默认视口大小。默认是 800x600。如果为null
的话就禁用视图口。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个步骤:
1、使用 puppeteer.defaultArgs()
作为一组默认值来启动 Chromium。
2、启动浏览器并根据 executablePath
,handleSIGINT
,dumpio
和其他选项开始管理它的进程。
3、创建一个 Browser 类的实例,并根据 defaultViewport
,slowMo
和 ignoreHTTPSErrors
初始化它。
ignoreDefaultArgs
选项可用于自定义(1)步骤的行为。 例如,要从参数中过滤掉 --mute-audio
:
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--mute-audio']
});
NOTE Puppeteer 也可以用来控制 Chrome 浏览器, 但它与绑定的 Chromium 版本在一起使用效果最好。不能保证它可以与任何其他版本一起使用。谨慎地使用
executablePath
选项。如果 Google Chrome(而不是Chromium)是首选,一个 Chrome Canary 或 Dev Channel 版本是建议的。
在上面的 puppeteer.launch([options]) 中,任何提及的 Chromium 同样也适用于 Chrome。
class: BrowserFetcher
BrowserFetcher 可以用来下载和管理不同版本的 Chromium。
BrowserFetcher 操作一个修订版本字符串,修订版本字符串指定了一个 Chromium 的确定版本,例如 "533271"
。修订版本字符串可以从 omahaproxy.appspot.com 获取。
看下面这个例子,他将告诉你如何使用 BrowserFetcher 下载一个指定版本的 Chromium:
const browserFetcher = puppeteer.createBrowserFetcher();
const revisionInfo = await browserFetcher.download('533271');
const browser = await puppeteer.launch({executablePath: revisionInfo.executablePath})
注意 BrowserFetcher 不适用于与共享下载目录的其他实例同时运行。
browserFetcher.canDownload(revision)
该方法将会发起一个 HEAD 请求来检查该修订版本是否有效。
browserFetcher.download(revision[, progressCallback])
revision
<string> 下载的修订版本。progressCallback
<function(number, number)> 一个函数, 调用时将会传入两个参数:- returns: <Promise<Object>> Resolves with revision information when the revision is downloaded and extracted
该方法将会发起一个 GET 请求来从主机下载该修订版本。
browserFetcher.localRevisions()
browserFetcher.platform()
- returns: <string> 返回
mac
,linux
,win32
或win64
之一。
browserFetcher.remove(revision)
revision
<string> 想要移除的修订版本,如果指定的修订版本还没有被下载,该方法将抛出一个错误- returns: <Promise> Resolves when the revision has been removed.
browserFetcher.revisionInfo(revision)
class: Browser
- 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();
});
event: 'disconnected'
当 Puppeteer 从 Chromium 实例断开连接时被触发。原因可能如下:
- Chromium 关闭或崩溃
- 调用
browser.disconnect
方法
event: 'targetchanged'
- <Target>
当目标的 url 改变时被触发
注意 这包括匿名浏览器上下文中的目标更改。
event: 'targetcreated'
- <Target>
当目标被创建时被触发,例如当通过 window.open
或 browser.newPage
打开一个新的页面。
注意 这包括匿名浏览器上下文中的目标创建。
event: 'targetdestroyed'
- <Target>
当目标被销毁时被触发,例如当一个页面被关闭时。
注意 这包括匿名浏览器上下文中的目标销毁。
browser.browserContexts()
- returns: <Array<BrowserContext>>
返回一个包含所有打开的浏览器上下文的数组。在新创建的浏览器中,这将返回 BrowserContext 的单一实例。
browser.close()
- returns: <Promise>
关闭 Chromium 及其所有页面(如果页面被打开的话)。Browser 对象本身被认为是处理过的并不能再被使用。
browser.createIncognitoBrowserContext()
- returns: <Promise<BrowserContext>>
创建一个匿名的浏览器上下文。这将不会与其他浏览器上下文分享 cookies/cache。
const browser = await puppeteer.launch();
// 创建一个匿名的浏览器上下文
const context = await browser.createIncognitoBrowserContext();
// 在一个原生的上下文中创建一个新页面
const page = await context.newPage();
// 做一些事情
await page.goto('https://example.com');
browser.defaultBrowserContext()
- returns: <BrowserContext>
返回一个默认的浏览器上下文。这个上下文不能被关闭。
browser.disconnect()
断开 Puppeteer 和浏览器的连接,但 Chromium 进程仍然在运行。在调用 disconnect
之后,Browser 对象本身被认为是处理过的并不能再被使用。
browser.newPage()
返回一个新的 Page 对象。Page 在一个默认的浏览器上下文中被创建。
browser.pages()
- returns: <Promise<Array<Page>>> 返回一个包含所有打开的页面的数组。页面不可见的,比如
"background_page"
将不会列在这。不过你可以通过 target.page() 找到它们。
返回一个浏览器中所有页面的数组。 在多个浏览器上下文的情况下, 该方法将返回一个包含所有浏览器上下文中所有页面的数组。
browser.process()
- returns: <?ChildProcess> 产生浏览器的进程。如果浏览器实例是由
puppeteer.connect
方法创建的则返回null。
browser.target()
- returns: <Target>
返回浏览器相关的目标对象。
browser.targets()
浏览器内所有活动目标组成的数组。在多个浏览器上下文的情况下,该方法将返回一个包含所有浏览器上下文中的所有目标的数组。
browser.userAgent()
注意 页面可以使用 page.setUserAgent 覆盖浏览器的 user-agent
browser.version()
- returns: <Promise<string>> 对于无头的 Chromium,这类似于
HeadlessChrome/61.0.3153.0
. 对于非无头的Chromium, 这类似于Chrome/61.0.3153.0。
注意 browser.version() 的格式可能在未来版本的 Chromium 中发生变化。
browser.wsEndpoint()
- returns: <string> 返回浏览器 websocket 的地址
puppeteer.connect 可以将浏览器 websocket 端作为一个参数。其格式为 ws://${host}:${port}/devtools/browser/<id>
。
你可以从 http://${host}:${port}/json/version
找到 webSocketDebuggerUrl
。了解更多有关 devtools protocol 和 browser endpoint 的信息。
class: Page
- 继承:
EventEmitter
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);
event: 'close'
当页面关闭时触发。
event: 'console'
当页面js代码调用了 console
的某个方法,比如 console.log
,或者 console.dir
的时候触发。(如果不监听这个事件,js源码的console语句不会输出)。当页面抛出一个错误或者经过的时候也会触发。
js源码中传给 console.log
的参数,会传给 console
事件的监听器。
一个监听 console
事件的例子:
page.on('console', msg => {
for (let i = 0; i < msg.args().length; ++i)
console.log(`${i}: ${msg.args()[i]}`); // 译者注:这句话的效果是打印到你的代码的控制台
});
page.evaluate(() => console.log('hello', 5, {foo: 'bar'})); // 这个代码表示在页面实例中执行了console.log。如果没有监听console事件,这里的输出不会出现在你的控制台
event: 'dialog'
- <Dialog>
当js对话框出现的时候触发,比如alert
, prompt
, confirm
或者 beforeunload
。Puppeteer可以通过Dialog's accept 或者 dismiss来响应弹窗。
event: 'domcontentloaded'
当页面的 DOMContentLoaded
事件被触发时触发。
event: 'error'
- <Error>
当页面崩溃时触发。
注意
error
在node
中有特殊的意义, 点击 error events 查看详情。
event: 'frameattached'
- <Frame>
当 iframe
加载的时候触发。
event: 'framedetached'
- <Frame>
当 iframe
从页面移除的时候触发。
event: 'framenavigated'
- <Frame>
当 iframe
导航到新的 url 时触发。
event: 'load'
当页面的 load
事件被触发时触发。
event: 'metrics'
当页面js代码调用了 console.timeStamp
方法时触发。page.metrics
章节有描述所有的 metrics。
event: 'pageerror'
- <Error> 异常信息
当发生页面js代码没有捕获的异常时触发。
event: 'request'
- <Request>
当页面发送一个请求时触发。参数 request 对象是只读的。
如果需要拦截并且改变请求,参考 page.setRequestInterception
章节。
event: 'requestfailed'
- <Request>
当页面的请求失败时触发。比如某个请求超时了。
event: 'requestfinished'
- <Request>
当页面的某个请求成功完成时触发。
event: 'response'
- <Response>
当页面的某个请求接收到对应的 response 时触发。
event: 'workercreated'
- <Worker>
当页面生成相应的 WebWorker 时触发。
event: 'workerdestroyed'
- <Worker>
当页面终止相应的 WebWorker 时触发。
page.$(selector)
selector
<string> 选择器- 返回: <Promise<?ElementHandle>>
此方法在页面内执行 document.querySelector
。如果没有元素匹配指定选择器,返回值是 null
。
page.mainFrame().$(selector) 的简写。
page.$$(selector)
selector
<string> 选择器- 返回: <Promise<Array<ElementHandle>>>
此方法在页面内执行 document.querySelectorAll
。如果没有元素匹配指定选择器,返回值是 []
。
page.mainFrame().$$(selector) 的简写。
page.$$eval(selector, pageFunction[, ...args])
selector
<string> 一个框架选择器pageFunction
<function> 在浏览器实例上下文中要执行的方法...args
<...Serializable|JSHandle> 要传给pageFunction
的参数。(比如你的代码里生成了一个变量,在页面中执行方法时需要用到,可以通过这个args
传进去)- 返回: <Promise<Serializable>> Promise对象,完成后是
pageFunction
的返回值
此方法在页面内执行 Array.from(document.querySelectorAll(selector))
,然后把匹配到的元素数组作为第一个参数传给 pageFunction
。
如果 pageFunction
返回的是 Promise,那么此方法会等 promise 完成后返回其返回值。
示例:
const divsCounts = await page.$$eval('div', divs => divs.length);
page.$eval(selector, pageFunction[, ...args])
selector
<string> 选择器pageFunction
<function> 在浏览器实例上下文中要执行的方法...args
<...Serializable|JSHandle> 要传给pageFunction
的参数。(比如你的代码里生成了一个变量,在页面中执行方法时需要用到,可以通过这个args
传进去)- 返回: <Promise<Serializable>> Promise对象,完成后是
pageFunction
的返回值
此方法在页面内执行 document.querySelector
,然后把匹配到的元素作为第一个参数传给 pageFunction
。
如果 pageFunction
返回的是 Promise,那么此方法会等 promise 完成后返回其返回值。
示例:
const searchValue = await page.$eval('#search', el => el.value);
const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
const html = await page.$eval('.main-container', e => e.outerHTML);
page.mainFrame().$eval(selector, pageFunction) 的简写。
page.$x(expression)
expression
<string> XPath表达式,参考: evaluate.- 返回: <Promise<Array<ElementHandle>>>
此方法解析指定的XPath表达式。
page.mainFrame().$x(expression) 的简写。
page.accessibility
- returns: <Accessibility>
page.addScriptTag(options)
options
<Object>- 返回: <Promise<ElementHandle>> Promise对象,即注入完成的tag标签。当 script 的 onload 触发或者代码被注入到 frame。
注入一个指定src(url)或者代码(content)的 script
标签到当前页面。
page.mainFrame().addScriptTag(options) 的简写。
page.addStyleTag(options)
options
<Object>- 返回: <Promise<ElementHandle>> Promise对象,即注入完成的tag标签。当style的onload触发或者代码被注入到frame。
添加一个指定link(url)的 <link rel="stylesheet">
标签。
或者添加一个指定代码(content)的 <style type="text/css">
标签。
page.mainFrame().addStyleTag(options) 的简写。
page.authenticate(credentials)
为HTTP authentication 提供认证凭据 。
传 null
禁用认证。
page.bringToFront()
- returns: <Promise>
相当于多个tab时,切换到某个tab。
page.browser()
- returns: <Browser>
得到当前 page 实例所属的 browser 实例。
page.click(selector[, options])
selector
<string> 要点击的元素的选择器。 如果有多个匹配的元素, 点击第一个。options
<Object>button
<string>left
,right
, 或者middle
, 默认是left
。clickCount
<number> 默认是 1. 查看 UIEvent.detail。delay
<number>mousedown
和mouseup
之间停留的时间,单位是毫秒。默认是0
- 返回: <Promise> Promise对象,匹配的元素被点击。 如果没有元素被点击,Promise对象将被rejected。
此方法找到一个匹配 selector
选择器的元素,如果需要会把此元素滚动到可视,然后通过 page.mouse 点击它。
如果选择器没有匹配任何元素,此方法将会报错。
要注意如果 click()
触发了一个跳转,会有一个独立的 page.waitForNavigation()
Promise对象需要等待。
正确的等待点击后的跳转是这样的:
const [response] = await Promise.all([
page.waitForNavigation(waitOptions),
page.click(selector, clickOptions),
]);
page.mainFrame().click(selector[, options]) 的简写。
page.close([options])
options
<Object>runBeforeUnload
<boolean> 默认false
. 是否执行 before unload
- 返回: <Promise>
page.close()
在 beforeunload 处理之前默认不执行
注意 如果
runBeforeUnload
设置为true,可能会弹出一个beforeunload
对话框。 这个对话框需要通过页面的 'dialog' 事件手动处理。
page.content()
返回页面的完整 html 代码,包括 doctype。
page.cookies([...urls])
如果不指定任何 url,此方法返回当前页面域名的 cookie。 如果指定了 url,只返回指定的 url 下的 cookie。
page.coverage
- returns: <Coverage>
page.deleteCookie(...cookies)
page.emulate(options)
根据指定的参数和 user agent 生成模拟器。此方法是和下面两个方法效果相同:
为了支持模拟器,puppeteer 提供了一些设备的参数选项,可以通过 require('puppeteer/DeviceDescriptors')
命令引入。
下面是通过 puppeteer 生成 iPhone 6 模拟器的例子:
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto('https://www.google.com');
// 其他操作...
await browser.close();
});
支持的设备可以在这里找到: DeviceDescriptors.js。
page.emulateMedia(mediaType)
page.evaluate(pageFunction[, ...args])
pageFunction
<function|string> 要在页面实例上下文中执行的方法...args
<...Serializable|JSHandle> 要传给pageFunction
的参数- 返回: <Promise<Serializable>>
pageFunction
执行的结果
如果pageFunction返回的是Promise,page.evaluate
将等待promise完成,并返回其返回值。
如果pageFunction返回的是不能序列化的值,将返回undefined
给pageFunction
传参数示例:
const result = await page.evaluate(x => {
return Promise.resolve(8 * x);
}, 7); // (译者注: 7 可以是你自己代码里任意方式得到的值)
console.log(result); // 输出 "56"
也可以传一个字符串:
console.log(await page.evaluate('1 + 2')); // 输出 "3"
const x = 10;
console.log(await page.evaluate(`1 + ${x}`)); // 输出 "11"
ElementHandle 实例 可以作为参数传给 page.evaluate
:
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose();
page.mainFrame().evaluate(pageFunction, ...args) 的简写。
page.evaluateHandle(pageFunction[, ...args])
pageFunction
<function|string> 要在页面实例上下文中执行的方法...args
<...Serializable|JSHandle> 要传给pageFunction
的参数- 返回: <Promise<JSHandle>>
pageFunction
执行的结果 页内类型(JSHandle)
此方法和 page.evaluate
的唯一区别是此方法返回的是页内类型(JSHandle)
如果传给此方法的方法(参数)返回的是Promise对象,将等待promise完成并返回其返回值
也可以传一个字符串替代方法:
const aHandle = await page.evaluateHandle('document'); // 'document'对象
JSHandle 实例可以作为 page.evaluateHandle
的参数:
const aHandle = await page.evaluateHandle(() => document.body);
const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue());
await resultHandle.dispose();
page.mainFrame().executionContext().evaluateHandle(pageFunction, ...args) 的简写。
page.evaluateOnNewDocument(pageFunction[, ...args])
pageFunction
<function|string> 要在页面实例上下文中执行的方法...args
<...Serializable> 要传给pageFunction
的参数- 返回: <Promise>
添加一个方法,在以下某个场景被调用:
- 页面导航完成后
- 页面的iframe加载或导航完成。这种场景,指定的函数被调用的上下文是新加载的iframe。
指定的函数在所属的页面被创建并且所属页面的任意 script 执行之前被调用。常用于修改页面js环境,比如给 Math.random
设定种子
下面是在页面加载前重写 navigator.languages
属性的例子:
// preload.js
// 重写 `languages` 属性,使其用一个新的get方法
Object.defineProperty(navigator, "languages", {
get: function() {
return ["en-US", "en", "bn"];
}
});
// 假设 preload.js 和当前的代码在同一个目录
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
await page.evaluateOnNewDocument(preloadFile);
page.exposeFunction(name, puppeteerFunction)
此方法添加一个命名为 name
的方法到页面的 window
对象
当调用 name
方法时,在 node.js
中执行 puppeteerFunction
,并且返回 Promise 对象,解析后返回 puppeteerFunction
的返回值
如果 puppeteerFunction
返回的是 Promise 对象,此方法会等其解析后再返回
注意 通过
page.exposeFunction
挂载到页面的方法在多次跳转后扔有用 (原文:> NOTE Functions installed viapage.exposeFunction
survive navigations.)
添加md5()到页面的例子:
const puppeteer = require('puppeteer');
const crypto = require('crypto');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
page.on('console', msg => console.log(msg.text()));
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
await page.evaluate(async () => {
// 使用 window.md5 计算哈希
const myString = 'PUPPETEER';
const myHash = await window.md5(myString);
console.log(`md5 of ${myString} is ${myHash}`);
});
await browser.close();
});
添加 readfile() 到页面的例子:
const puppeteer = require('puppeteer');
const fs = require('fs');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
page.on('console', msg => console.log(msg.text()));
await page.exposeFunction('readfile', async filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, text) => {
if (err)
reject(err);
else
resolve(text);
});
});
});
await page.evaluate(async () => {
// 使用 window.readfile 读取文件内容
const content = await window.readfile('/etc/hosts');
console.log(content);
});
await browser.close();
});
page.focus(selector)
selector
<string> 要给焦点的元素的选择器selector。如果有多个匹配的元素,焦点给第一个元素。- 返回: <Promise> Promise对象,当
selector
选择器匹配的元素获得焦点后resolve。如果没有元素匹配指定选择器,将会rejected。
此方法找到一个匹配selector
的元素,并且把焦点给它。
如果没有匹配的元素,此方法将报错。
page.mainFrame().focus(selector) 的简写。
page.frames()
page.goBack([options])
options
<Object> 导航配置,可选值:timeout
<number> 跳转等待时间,单位是毫秒, 默认是30秒, 传0
表示无限等待。可以通过page.setDefaultNavigationTimeout(timeout)方法修改默认值waitUntil
<string|Array<string>> 满足什么条件认为页面跳转完成,默认是load
事件触发时。指定事件数组,那么所有事件触发后才认为是跳转完成。事件包括:load
- 页面的load事件触发时domcontentloaded
- 页面的DOMContentLoaded
事件触发时networkidle0
- 不再有网络连接时触发(至少500毫秒后)networkidle2
- 只有2个网络连接时触发(至少500毫秒后)
- 返回: <Promise<?Response>> Promise对象resolve后是主要的请求的响应。如果有多个跳转, resolve后是最后一次跳转的响应. 如果不能回退,解析后是null
导航到页面历史的前一个页面。
page.goForward([options])
options
<Object> 导航配置,可选值:timeout
<number> 跳转等待时间,单位是毫秒, 默认是30秒, 传0
表示无限等待。可以通过page.setDefaultNavigationTimeout(timeout)方法修改默认值waitUntil
<string|Array<string>> 满足什么条件认为页面跳转完成,默认是load
事件触发时。指定事件数组,那么所有事件触发后才认为是跳转完成。事件包括:load
- 页面的load事件触发时domcontentloaded
- 页面的DOMContentLoaded
事件触发时networkidle0
- 不再有网络连接时触发(至少500毫秒后)networkidle2
- 只有2个网络连接时触发(至少500毫秒后)
- 返回: <Promise<?Response>> Promise对象resolve后是主要的请求的响应. 如果有多个跳转, resolve后是最后一次跳转的响应. 如果不能向前,resolve后是null
导航到页面历史的后一个页面。
page.goto(url[, options])
url
<string> 导航到的地址. 地址应该带有http协议, 比如https://
.options
<Object> 导航配置,可选值:timeout
<number> 跳转等待时间,单位是毫秒, 默认是30秒, 传0
表示无限等待。可以通过page.setDefaultNavigationTimeout(timeout)方法修改默认值waitUntil
<string|Array<string>> 满足什么条件认为页面跳转完成,默认是load
事件触发时。指定事件数组,那么所有事件触发后才认为是跳转完成。事件包括:load
- 页面的load事件触发时domcontentloaded
- 页面的DOMContentLoaded
事件触发时networkidle0
- 不再有网络连接时触发(至少500毫秒后)networkidle2
- 只有2个网络连接时触发(至少500毫秒后)
referer
<string> Referer header value. If provided it will take preference over the referer header value set by page.setExtraHTTPHeaders().
- 返回: <Promise<?Response>> Promise对象resolve后是主要的请求的响应。如果有多个跳转, resolve后是最后一次跳转的响应
以下情况此方法将报错:
- 发生了 SSL 错误 (比如有些自签名的https证书).
- 目标地址无效
- 超时
- 主页面不能加载
- the main resource failed to load.
注意
page.goto
抛出或返回主页面的响应。唯一的例外是导航到about:blank
或导航到具有不同散列的相同URL,这将成功并返回null
。
注意 无头模式不支持打开 PDF 文件。查看 upstream issue。
快捷方式 page.mainFrame().goto(url, options)
page.hover(selector)
selector
<string> 要hover的元素的选择器。如果有多个匹配的元素,hover第一个。- 返回: <Promise> Promise对象,当匹配的元素成功被hover后resolve。如果没有匹配的元素,将会rejected。
此方法使用 selector 匹配元素。如有必要,会将匹配到的元素滚动至可视区域内,然后使用 page.mouse 将鼠标悬停在元素的中心位置。如果 selector 没有匹配到元素,则抛出一个错误。
page.mainFrame().hover(selector) 的简写。
page.isClosed()
- returns: <boolean>
表示页面是否被关闭。
page.keyboard
- returns: <Keyboard>
page.mainFrame()
- 返回: <Frame> 返回页面的主frame
保证页面一直有有一个主 frame
page.metrics()
- 返回: <Promise<Object>> 包含指标数据的键值对:
Timestamp
<number> 时间点(when the metrics sample was taken)Documents
<number> 页面的documents数量。Frames
<number> 页面的iframe数量。JSEventListeners
<number> 页面的js事件数量。Nodes
<number> 页面的dom节点数量。LayoutCount
<number> 整页面或部分页面的布局数量。RecalcStyleCount
<number> 页面样式重新计算数量。LayoutDuration
<number> 页面布局总时间。RecalcStyleDuration
<number> 页面样式重新计算总时间。ScriptDuration
<number> 页面js代码执行总时间。TaskDuration
<number> 页面任务执行总时间。JSHeapUsedSize
<number> 页面占用堆内存大小。JSHeapTotalSize
<number> 总的页面堆内存大小。
注意 All timestamps are in monotonic time: monotonically increasing time in seconds since an arbitrary point in the past.
page.mouse
- returns: <Mouse>
page.pdf([options])
options
<Object> 可以有以下配置项:path
<string> pdf文件保存的路径。如果是相对路径,则相对当前路径。如果不指定路径,将不保存到硬盘。scale
<number> 页面渲染的缩放。默认是1。缩放值必须介于0.1到2之间。displayHeaderFooter
<boolean> 显示页眉和页脚。默认是不显示headerTemplate
<string> 页眉的html模板,可以有这些变量:date
格式化的日期title
网页标题url
网页地址pageNumber
当前页码totalPages
总页数
footerTemplate
<string> 页脚的html模板。和页眉模板变量相同。printBackground
<boolean> 是否打印背景图. 默认是false
。landscape
<boolean> 页面横向(?Paper orientation). 默认为false
.pageRanges
<string> 要输出的页码范围, 比如, '1-5, 8, 11-13'。默认是空字符串,表示全部页码。format
<string> 页面格式。如果设置了,将覆盖width
和height
配置. 默认是 'Letter'。width
<string> 页面宽度, 接受带单位的字符串。height
<string> 页面高度, 接受带单位的字符串。margin
<Object> 页面空白白边配置,默认是空preferCSSPageSize
<boolean> 给页面优先级声明的任何CSS@page
大小超过width
和height
或format
选项中声明的大小。 默认为false
,它将缩放内容以适合纸张大小。
- 返回: <Promise<Buffer>> Promise对象,resolve后是pdf buffer。
注意 目前仅支持无头模式的 Chrome
page.pdf()
生成当前页面的pdf格式,带着 pring
css media。如果要生成带着 screen
media的pdf,在page.pdf()
前面先调用 page.emulateMedia('screen')
注意 默认情况下,
page.pdf()
生成一个带有修改颜色的 pdf 用于打印。 使用[-webkit-print-color-adjust
](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust)属性强制渲染精确的颜色。
// 生成 'screen' media 格式的pdf.
await page.emulateMedia('screen');
await page.pdf({path: 'page.pdf'});
width
, height
, 和 margin
接受带单位的字符串. 不带单位的默认是像素(px)
几个例子:
page.pdf({width: 100})
- pdf将是 100 pixels宽page.pdf({width: '100px'})
- pdf将是 100 pixels宽page.pdf({width: '10cm'})
- pdf将是 10 厘米宽.
支持的单位包括:
px
- 像素in
- 英寸cm
- 厘米mm
- 毫米
format
可选值:
Letter
: 8.5in x 11inLegal
: 8.5in x 14inTabloid
: 11in x 17inLedger
: 17in x 11inA0
: 33.1in x 46.8inA1
: 23.4in x 33.1inA2
: 16.5in x 23.4inA3
: 11.7in x 16.5inA4
: 8.27in x 11.7inA5
: 5.83in x 8.27inA6
: 4.13in x 5.83in
注意
headerTemplate
和footerTemplate
有下面的限制:
- js脚本不会被执行
- 页面的样式对模板内无效
page.queryObjects(prototypeHandle)
prototypeHandle
<JSHandle> A handle to the object prototype.- returns: <Promise<JSHandle>> Promise which resolves to a handle to an array of objects with this prototype.
此方法遍历js堆栈,找到所有带有指定原型的对象
// 创建 Map 对象
await page.evaluate(() => window.map = new Map());
// 获取 Map 对象的原型
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// 查询所有的 map 实例,存储为一个数组
const mapInstances = await page.queryObjects(mapPrototype);
// 计算堆栈中 map 对象的数量
const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose();
await mapPrototype.dispose();
page.mainFrame().executionContext().queryObjects(prototypeHandle) 的简写
page.reload([options])
options
<Object> 导航配置,可选值:timeout
<number> 跳转等待时间,单位是毫秒, 默认是30秒, 传0
表示无限等待。可以通过page.setDefaultNavigationTimeout(timeout)方法修改默认值waitUntil
<string|Array<string>> 满足什么条件认为页面跳转完成,默认是load
事件触发时。指定事件数组,那么所有事件触发后才认为是跳转完成。事件包括:load
- 页面的load事件触发时domcontentloaded
- 页面的DOMContentLoaded
事件触发时networkidle0
- 不再有网络连接时触发(至少500毫秒后)networkidle2
- 只有2个网络连接时触发(至少500毫秒后)
- 返回: <Promise<?Response>> Promise对象解析后是主要的请求的响应. 如果有多个跳转, 解析后是最后一次跳转的响应
page.screenshot([options])
options
<Object> 可选配置:path
<string> 截图保存路径。截图图片类型将从文件扩展名推断出来。如果是相对路径,则从当前路径解析。如果没有指定路径,图片将不会保存到硬盘。type
<string> 指定截图类型, 可以是jpeg
或者png
。默认 'png'.quality
<number> 图片质量, 可选值 0-100.png
类型不适用。fullPage
<boolean> 如果设置为true,则对完整的页面(需要滚动的部分也包含在内)。默认是falseclip
<Object> 指定裁剪区域。需要配置:omitBackground
<boolean> 隐藏默认的白色背景,背景透明。默认不透明encoding
<string> 图像的编码可以是base64
或binary
。 默认为“二进制”。
- 返回: <Promise<[Buffer|String]>> Promise对象,resolve后是截图的buffer
备注 在OS X上 截图需要至少1/6秒。查看讨论:https://crbug.com/741689。
page.select(selector, ...values)
selector
<string> 要查找的选择器...values
<...string> 查找的配置项。如果选择器有多个属性,所有的值都会查找,否则只有第一个元素被找到。(翻译不一定准确,具体要实验)- 返回: <Promise<Array<string>>> 所有符合的元素
当提供的选择器完成选中后,触发change
和input
事件
如果没有元素匹配指定选择器,将报错。
page.select('select#colors', 'blue'); // 单选择器
page.select('select#colors', 'red', 'green', 'blue'); // 多选择器
page.setBypassCSP(enabled)
设置绕过页面的安全政策
注意 CSP 发生在 CSP 初始化而不是评估阶段。也就是说应该在导航到这个域名前设置
page.setCacheEnabled([enabled])
-- enabled
<boolean> 设置缓存的 enabled
状态
- 返回: <Promise>
设置每个请求忽略缓存。默认是启用缓存的。
page.setContent(html[, options])
await page.setCookie(cookieObject1, cookieObject2);
page.setCookie(...cookies)
await page.setCookie(cookieObject1, cookieObject2);
page.setDefaultNavigationTimeout(timeout)
timeout
<number> 最多等待时间,单位是毫秒
此方法会改变下面几个方法的默认30秒等待时间:
- page.goto(url, options)
- page.goBack(options)
- page.goForward(options)
- page.reload(options)
- page.waitForNavigation(options)
page.setExtraHTTPHeaders(headers)
当前页面发起的每个请求都会带上这些请求头
注意 此方法不保证请求头的顺序
page.setGeolocation(options)
options
- returns: <Promise>
Sets the page's geolocation.
await page.setGeolocation({latitude: 59.95, longitude: 30.31667});
注意 考虑使用 browserContext.overridePermissions 授予页面权限去读取地址位置。
page.setJavaScriptEnabled(enabled)
注意 改变这个值不会影响已经执行的js。下一个跳转会完全起作用。
page.setOfflineMode(enabled)
page.setRequestInterception(value)
启用请求拦截器,会激活 request.abort
, request.continue
和 request.respond
方法。这提供了修改页面发出的网络请求的功能。
一旦启用请求拦截,每个请求都将停止,除非它继续,响应或中止。 通过请求拦截器取消所有图片请求:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', interceptedRequest => {
if (interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg'))
interceptedRequest.abort();
else
interceptedRequest.continue();
});
await page.goto('https://example.com');
await browser.close();
});
注意 启用请求拦截器会禁用页面缓存。
page.setUserAgent(userAgent)
userAgent
<string> Specific user agent to use in this page- returns: <Promise> Promise which resolves when the user agent is set.
page.setViewport(viewport)
注意 在大部分情况下,改变 viewport 会重新加载页面以设置
isMobile
或者hasTouch
如果是一个浏览器多个页面的情况,每个页面都可以有单独的viewport
page.tap(selector)
此方法找到一个匹配的元素,如果需要会把此元素滚动到可视,然后通过 page.touchscreen 来点击元素的中间位置 如果没有匹配的元素,此方法会报错
page.mainFrame().tap(selector) 的简写
page.target()
- returns: <Target> a target this page was created from.
page.title()
page.touchscreen
- returns: <Touchscreen>
page.tracing
- returns: <Tracing>
page.type(selector, text[, options])
selector
<string> 要输入内容的元素选择器。如果有多个匹配的元素,输入到第一个匹配的元素。text
<string> 要输入的内容options
<Object>delay
<number> 每个字符输入的延迟,单位是毫秒。默认是 0。
- 返回: <Promise>
每个字符输入后都会触发 keydown
, keypress
/input
和 keyup
事件
要点击特殊按键,比如 Control
或 ArrowDown
,用 keyboard.press
page.type('#mytextarea', 'Hello'); // 立即输入
page.type('#mytextarea', 'World', {delay: 100}); // 输入变慢,像一个用户
page.mainFrame().type(selector, text[, options]) 的简写
page.url()
- returns: <string>
page.viewport()
- 返回: <?Object>
page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])
selectorOrFunctionOrTimeout
<string|number|function> 选择器, 方法 或者 超时时间options
<Object> 可选的等待参数...args
<...Serializable|JSHandle> 传给pageFunction
的参数- returns: <Promise<JSHandle>> Promise which resolves to a JSHandle of the success value
此方法根据第一个参数的不同有不同的结果:
- 如果
selectorOrFunctionOrTimeout
是string
, 那么认为是 css 选择器或者一个xpath, 根据是不是'//'开头, 这时候此方法是 page.waitForSelector 或 page.waitForXPath的简写 - 如果
selectorOrFunctionOrTimeout
是function
, 那么认为是一个predicate,这时候此方法是page.waitForFunction()的简写 - 如果
selectorOrFunctionOrTimeout
是number
, 那么认为是超时时间,单位是毫秒,返回的是Promise对象,在指定时间后resolve - 否则会报错
// wait for selector
await page.waitFor('.foo');
// wait for 1 second
await page.waitFor(1000);
// wait for predicate
await page.waitFor(() => !!document.querySelector('.foo'));
将 node.js 中的参数传递给 page.waitFor
函数:
const selector = '.foo';
await page.waitFor(selector => !!document.querySelector(selector), {}, selector);
page.mainFrame().waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])的简写
page.waitForFunction(pageFunction[, options[, ...args]])
pageFunction
<function|string> 要在浏览器实例上下文执行的方法options
<Object> 可选的等待参数:polling
<string|number> An interval at which thepageFunction
is executed, defaults toraf
. Ifpolling
is a number, then it is treated as an interval in milliseconds at which the function would be executed. Ifpolling
is a string, then it can be one of the following values:raf
- to constantly executepageFunction
inrequestAnimationFrame
callback. This is the tightest polling mode which is suitable to observe styling changes.mutation
- to executepageFunction
on every DOM mutation.
timeout
<number> 最长时间,单位是毫秒. 默认30000
(30 seconds). 传0
表示不会超时。
...args
<...Serializable|JSHandle> 传给pageFunction
的参数- returns: <Promise<JSHandle>> Promise 对象,当
pageFunction
返回等于true的结果时resolve, resolves 为结果的 JSHandle 类型
waitForFunction
可以用来监控页面的大小变化:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
const watchDog = page.waitForFunction('window.innerWidth < 100');
await page.setViewport({width: 50, height: 50});
await watchDog;
await browser.close();
});
将 node.js 中的参数传递给 page.waitForFunction
函数:
const selector = '.foo';
await page.waitForFunction(selector => !!document.querySelector(selector), {}, selector);
page.mainFrame().waitForFunction(pageFunction[, options[, ...args]]) 的简写
page.waitForNavigation([options])
options
<Object> 导航配置,可选值:timeout
<number> 跳转等待时间,单位是毫秒, 默认是30秒, 传0
表示无限等待. 可以通过page.setDefaultNavigationTimeout(timeout)方法修改默认值waitUntil
<string|Array<string>> 满足什么条件认为页面跳转完成,默认是load
事件触发时。指定事件数组,那么所有事件触发后才认为是跳转完成。事件包括:load
- 页面的load事件触发时domcontentloaded
- 页面的DOMContentLoaded
事件触发时networkidle0
- 不再有网络连接时触发(至少500毫秒后)networkidle2
- 只有2个网络连接时触发(至少500毫秒后)
- 返回: <Promise<[?Response]>> Promise对象resolve后是主要的请求的响应。如果有多个跳转, resolve后是最后一次跳转的响应。如果由于使用 History API 而导航到不同的锚点或导航,导航将以
null
解析。
此方法在页面跳转到一个新地址或重新加载时解析,如果你的代码会间接引起页面跳转,这个方法比较有用: 比如这个例子:
const [response] = await Promise.all([
page.waitForNavigation(), // The promise resolves after navigation has finished
page.click('a.my-link'), // 点击该链接将间接导致导航(跳转)
]);
注意 通过 History API 改变地址会认为是一次跳转。
快捷方式 page.mainFrame().waitForNavigation(options)。
page.waitForRequest(urlOrPredicate[, options])
urlOrPredicate
<string|Function> A URL or predicate to wait for.options
<Object> Optional waiting parameterstimeout
<number> Maximum wait time in milliseconds, defaults to 30 seconds, pass0
to disable the timeout.
- returns: <Promise<Request>> Promise which resolves to the matched request.
const firstRequest = await page.waitForRequest('http://example.com/resource');
const finalRequest = await page.waitForRequest(request => request.url() === 'http://example.com' && request.method() === 'GET');
return firstRequest.url();
page.waitForResponse(urlOrPredicate[, options])
urlOrPredicate
<string|Function> A URL or predicate to wait for.options
<Object> Optional waiting parameterstimeout
<number> Maximum wait time in milliseconds, defaults to 30 seconds, pass0
to disable the timeout.
- returns: <Promise<Response>> Promise which resolves to the matched response.
const firstResponse = await page.waitForResponse('https://example.com/resource');
const finalResponse = await page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
return finalResponse.ok();
page.waitForSelector(selector[, options])
selector
<string> 要等待的元素选择器options
<Object> 可选参数:- 返回: <Promise<ElementHandle>> Promise对象,当指定选择器匹配的元素添加到dom中时resolve
等待指定的选择器匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,那么此方法立即返回。 如果指定的选择器在超时时间后扔不出现,此方法会报错。
此方法在页面跳转时仍然有效:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
let currentURL;
page
.waitForSelector('img')
.then(() => console.log('First URL with image: ' + currentURL));
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
await page.goto(currentURL);
await browser.close();
});
page.mainFrame().waitForSelector(selector[, options]) 的简写
page.waitForXPath(xpath[, options])
xpath
<string> 要等待的元素的xpathoptions
<Object> 可选参数:- 返回: <Promise<ElementHandle>> Promise对象,当指定xpath匹配的元素添加到dom中时resolve
等待指定的xpath匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,那么此方法立即返回。 如果指定的xpath在超时时间后扔不出现,此方法会报错。
此方法在页面跳转时仍然有效:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
let currentURL;
page
.waitForXPath('//img')
.then(() => console.log('First URL with image: ' + currentURL));
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
await page.goto(currentURL);
await browser.close();
});
page.mainFrame().waitForXPath(xpath[, options]) 的简写
page.workers()
- returns: <Array<Worker>> 该方法返回所有与页面关联的 WebWorkers
备注 这不包含 ServiceWorkers
class: Worker
Worker 类表示一个 WebWorker。在页面对象上 workercreated
和 workerdestroyed
事件被触发,以标识 worker 的生命周期。
page.on('workercreated', worker => console.log('Worker created: ' + worker.url()));
page.on('workerdestroyed', worker => console.log('Worker destroyed: ' + worker.url()));
console.log('Current workers:');
for (const worker of page.workers())
console.log(' ' + worker.url());
worker.evaluate(pageFunction, ...args)
pageFunction
<function|string> Function to be evaluated in the worker context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
如果传递给 worker.evaluate
的函数返回一个 Promise,那么 worker.evaluate
将等待解析并返回它的值。
如果传递给 worker.evaluate
的函数返回一个 非[序列化]的值,那么 worker.evaluate
解析为 undefined
。
(await worker.executionContext()).evaluate(pageFunction, ...args) 的快捷链接。
worker.evaluateHandle(pageFunction, ...args)
pageFunction
<function|string> Function to be evaluated in the page context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<JSHandle>> Promise which resolves to the return value of
pageFunction
as in-page object (JSHandle)
worker.evaluate
和 worker.evaluateHandle
之间的唯一区别是 worker.evaluateHandle
返回页内对象(JSHandle)。
如果传递给 worker.evaluateHandle
的函数返回一个 Promise,那么 worker.evaluateHandle
将等待解析并返回它的值。
(await worker.executionContext()).evaluateHandle(pageFunction, ...args) 的快捷链接。
worker.executionContext()
- returns: <Promise<ExecutionContext>>
worker.url()
- returns: <string>
class: Accessibility
The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as screen readers.
Accessibility is a very platform-specific thing. On different platforms, there are different screen readers that might have wildly different output.
Blink - Chrome's rendering engine - has a concept of "accessibility tree", which is than translated into different platform-specific APIs. Accessibility namespace gives users access to the Blink Accessibility Tree.
Most of the accessibility tree gets filtered out when converting from Blink AX Tree to Platform-specific AX-Tree or by screen readers themselves. By default, Puppeteer tries to approximate this filtering, exposing only the "interesting" nodes of the tree.
accessibility.snapshot([options])
options
<Object>interestingOnly
<boolean> Prune uninteresting nodes from the tree. Defaults totrue
.
- returns: <Promise<Object>> Returns an AXNode object with the following properties:
role
<string> The role.name
<string> A human readable name for the node.value
<string|number> The current value of the node.description
<string> An additional human readable description of the node.keyshortcuts
<string> Keyboard shortcuts associated with this node.roledescription
<string> A human readable alternative to the role.valuetext
<string> A description of the current value.disabled
<boolean> Whether the node is disabled.expanded
<boolean> Whether the node is expanded or collapsed.focused
<boolean> Whether the node is focused.modal
<boolean> Whether the node is modal.multiline
<boolean> Whether the node text input supports multiline.multiselectable
<boolean> Whether more than one child can be selected.readonly
<boolean> Whether the node is read only.required
<boolean> Whether the node is required.selected
<boolean> Whether the node is selected in its parent node.checked
<boolean|"mixed"> Whether the checkbox is checked, or "mixed".pressed
<boolean|"mixed"> Whether the toggle button is checked, or "mixed".level
<number> The level of a heading.valuemin
<number> The minimum value in a node.valuemax
<number> The maximum value in a node.autocomplete
<string> What kind of autocomplete is supported by a control.haspopup
<string> What kind of popup is currently being shown for a node.invalid
<string> Whether and in what way this node's value is invalid.orientation
<string> Whether the node is oriented horizontally or vertically.children
<Array<Object>> Child AXNodes of this node, if any.
Captures the current state of the accessibility tree. The returned object represents the root accessible node of the page.
NOTE The Chromium accessibility tree contains nodes that go unused on most platforms and by most screen readers. Puppeteer will discard them as well for an easier to process tree, unless
interestingOnly
is set tofalse
.
An example of dumping the entire accessibility tree:
const snapshot = await page.accessibility.snapshot();
console.log(snapshot);
An example of logging the focused node's name:
const snapshot = await page.accessibility.snapshot();
const node = findFocusedNode(snapshot);
console.log(node && node.name);
function findFocusedNode(node) {
if (node.focused)
return node;
for (const child of node.children || []) {
const foundNode = findFocusedNode(child);
return foundNode;
}
return null;
}
class: Keyboard
Keyboard 提供一个接口来管理虚拟键盘. 高级接口为 keyboard.type
, 其接收原始字符, 然后在你的页面上生成对应的 keydown, keypress/input, 和 keyup 事件.
为了更精细的控制(虚拟键盘), 你可以使用 keyboard.down
, keyboard.up
和 keyboard.sendCharacter
来手动触发事件, 就好像这些事件是由真实的键盘生成的.
持续按下 Shift
来选择一些字符串并且删除的例子:
await page.keyboard.type('Hello World!');
await page.keyboard.press('ArrowLeft');
await page.keyboard.down('Shift');
for (let i = 0; i < ' World'.length; i++)
await page.keyboard.press('ArrowLeft');
await page.keyboard.up('Shift');
await page.keyboard.press('Backspace');
// 结果字符串最终为 'Hello!'
按下 A
的例子:
await page.keyboard.down('Shift');
await page.keyboard.press('KeyA');
await page.keyboard.up('Shift');
注意 在 MacOS 上,
⌘ A
-> 选择全部等键盘快捷键不工作. 另见 #1313
keyboard.down(key[, options])
key
<string> 按下的键名, 比如ArrowLeft
. 一个包含所有键名的列表见 USKeyboardLayout.options
<Object> -text
<string> 如果指定,则使用此文本生成输入事件.- returns: <Promise>
会分发一个 keydown
事件。
如果 key
是一个单独字符并且没有除了 Shift
的其他修饰符键正在被按下, 一个 keypress
/input
事件也将被生成. 可以指定 text
选项来强制生成输入事件。
如果 key
是一个修饰键, Shift
, Meta
, Control
, 或者是 Alt
, 随后的按键将与该修饰符一起发送. 要释放修饰键, 请使用 keyboard.up
。
在键被按下一次之后(译者注: 按下之后没有被释放, 一般会持续的触发该按键), 随后将持续调用 keyboard.down
, 事件对象的 repeat 将被设置为 true. 要释放该键, 请使用 keyboard.up
.
注意 修饰键会影响
keyboard.down
, 持续按下Shift
键将以大写形式输入文本。
keyboard.press(key[, options])
key
<string> 按下的键名, 比如ArrowLeft
. 一个包含所有键名的列表见 USKeyboardLayout。options
<Object> -text
<string> 如果指定,则使用此文本生成输入事件。 -delay
<number> 在keydown
和keyup
间隔的时间, 以毫秒为单位. 默认为 0。- returns: <Promise>
如果 key
是一个单独字符并且没有除了 Shift
的其他修饰符键正在被按下, 一个 keypress
/input
事件也将被生成。可以指定 text
选项来强制生成输入事件。
注意 修饰键会影响
keyboard.press
, 持续按下Shift
键将已大写形式输入文本。
keyboard.down
和 keyboard.up
的快捷方式。
keyboard.sendCharacter(char)
分发一个 keypress
和 input
事件。该方法不会发送 keydown
或 keyup
事件。
page.keyboard.sendCharacter('嗨');
注意 修饰键不会影响
keyboard.sendCharacter
。持续按下Shift
键将不会已大写形式输入文本。
keyboard.type(text, options)
text
<string> 要输入到焦点元素中的文本。options
<Object> -delay
<number> 按键间隔的时间, 以毫秒为单位. 默认为 0。- returns: <Promise>
为文本中的每个字符发送一个keydown
, keypress
/input
和 keyup
事件。
要按下一个特别的键, 像 Control
或 ArrowDown
. 请使用keyboard.press
page.keyboard.type('Hello'); // 立即输入
page.keyboard.type('World', {delay: 100}); // 更缓慢的输入, 像一个用户
注意 修饰键不会影响
keyboard.type
。持续按下Shift
键将不会已大写形式输入文本。
keyboard.up(key)
key
<string> 要释放的键的键名, 例如ArrowLeft
。一个包含所有键名的列表见 USKeyboardLayout。- returns: <Promise>
分发一个 keyup
事件。
class: Mouse
Mouse 类在相对于视口左上角的主框架 CSS 像素中运行。
每个 page
对象都有它自己的 Mouse 对象,使用见 page.mouse
。
// 使用 ‘page.mouse’ 追踪 100x100 的矩形。
await page.mouse.move(0, 0);
await page.mouse.down();
await page.mouse.move(0, 100);
await page.mouse.move(100, 100);
await page.mouse.move(100, 0);
await page.mouse.move(0, 0);
await page.mouse.up();
mouse.click(x, y, [options])
x
<number>y
<number>options
<Object>button
<string>left
,right
或middle
,默认是left
。clickCount
<number> 默认是 1。见 UIEvent.detail。delay
<number> 在毫秒内且在mousedown
和mouseup
之间等待的时间。 默认为0。
- returns: <Promise>
mouse.move
,mouse.down
和 mouse.up
的快捷方式。
mouse.down([options])
options
<Object>button
<string>left
,right
或middle
,默认是left
。clickCount
<number> 默认是 1。见 UIEvent.detail。
- returns: <Promise>
触发一个 mousedown
事件。
mouse.move(x, y, [options])
触发一个 mousemove
事件。
mouse.up([options])
options
<Object>button
<string>left
,right
,或middle
,默认是left
。clickCount
<number> 默认是 1。见 UIEvent.detail。
- returns: <Promise>
触发一个 mouseup
事件。
class: Touchscreen
touchscreen.tap(x, y)
触发 touchstart 和 touchend 事件。
class: Tracing
你可以使用 tracing.start
和 tracing.stop
创建一个可以在 Chrome DevTools or timeline viewer 中打开的跟踪文件。
await page.tracing.start({path: 'trace.json'});
await page.goto('https://www.google.com');
await page.tracing.stop();
tracing.start(options)
每个浏览器一次只能激活一条跟踪。
tracing.stop()
class: Dialog
一个使用 Dialog
类的例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
page.on('dialog', async dialog => {
console.log(dialog.message());
await dialog.dismiss();
await browser.close();
});
page.evaluate(() => alert('1'));
});
dialog.accept([promptText])
promptText
<string> 提示中输入的文本。 如果对话框的类型
不提示,不会产生任何影响。- returns: <Promise> Promise which resolves when the dialog has been accepted.
dialog.defaultValue()
- returns: <string> 如果对话框出现提示,则返回默认提示值。 否则,返回空字符串。
dialog.dismiss()
- returns: <Promise> Promise which resolves when the dialog has been dismissed.
dialog.message()
- returns: <string> 显示在对话框中的信息。
dialog.type()
- returns: <string> 对话框类型,可以是
alert
,beforeunload
,confirm
或prompt
中的一个。
class: ConsoleMessage
ConsoleMessage 对象由页面通过 'console' 事件分发。
consoleMessage.args()
consoleMessage.text()
- returns: <string>
consoleMessage.type()
- returns: <string>
以下值之一:'log'
, 'debug'
, 'info'
, 'error'
, 'warning'
, 'dir'
, 'dirxml'
, 'table'
, 'trace'
, 'clear'
, 'startGroup'
, 'startGroupCollapsed'
, 'endGroup'
, 'assert'
, 'profile'
, 'profileEnd'
, 'count'
, 'timeEnd'
。
class: Frame
在每一个时间点,页面通过 page.mainFrame() 和 frame.childFrames() 方法暴露当前框架的细节。
Frame 对象的生命周期由 3 个事件控制,它们通过 page 对象监听:
'frameattached' - 当框架被页面加载时触发。一个框架只会被加载一次。
'framenavigated' - 当框架改变URL时触发。
'framedetached' - 当框架被页面分离时触发。一个框架只会被分离一次。
一个获得框架树的例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.google.com/chrome/browser/canary.html');
dumpFrameTree(page.mainFrame(), '');
await browser.close();
function dumpFrameTree(frame, indent) {
console.log(indent + frame.url());
for (let child of frame.childFrames())
dumpFrameTree(child, indent + ' ');
}
});
一个从 iframe 元素中获取文本的例子:
const frame = page.frames().find(frame => frame.name() === 'myframe');
const text = await frame.$eval('.selector', element => element.textContent);
console.log(text);
frame.$(selector)
selector
<string> Selector to query frame forreturns: <Promise<?ElementHandle>> Promise which resolves to ElementHandle pointing to the frame element.
这个方法在框架中查询指定的选择器。如果在框架中没有匹配的元素会返回 null
frame.$$(selector)
selector
<string> Selector to query frame for- returns: <Promise<Array<ElementHandle>>> Promise which resolves to ElementHandles pointing to the frame elements.
这个方法会在框架中执行 document.querySelectorAll
方法。如果没有元素匹配会返回 []
frame.$$eval(selector, pageFunction[, ...args])
selector
<string> A selector to query frame forpageFunction
<function> Function to be evaluated in browser context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
这个方法会在框架中执行 Array.from(document.querySelectorAll(selector))
方法,然后将返回值传给 pageFunction
函数的第一个参数。
如果 pageFunction
返回了一个Promise,那么 frame.$$eval
将会等待Promise resolve之后返回它的值。
例子:
const divsCounts = await frame.$$eval('div', divs => divs.length);
frame.$eval(selector, pageFunction[, ...args])
selector
<string> A selector to query frame forpageFunction
<function> Function to be evaluated in browser context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
这个方法会在框架中执行 document.querySelector
方法,然后将返回值传给 pageFunction
函数的第一个参数。如果没有匹配到任何元素,则会抛出一个错误。
如果 pageFunction
返回了一个 Promise,那么 frame.$eval
将会等待 Promise 并解析后返回它的值。
例如:
const searchValue = await frame.$eval('#search', el => el.value);
const preloadHref = await frame.$eval('link[rel=preload]', el => el.href);
const html = await frame.$eval('.main-container', e => e.outerHTML);
frame.$x(expression)
expression
<string> Expression to evaluate.- returns: <Promise<Array<ElementHandle>>>
这个方法用来执行 XPath 表达式。
frame.addScriptTag(options)
options
<Object>url
<string> URL of a script to be added.path
<string> Path to the JavaScript file to be injected into frame. Ifpath
is a relative path, then it is resolved relative to current working directory.content
<string> Raw JavaScript content to be injected into frame.type
<string> Script type. Use 'module' in order to load a Javascript ES6 module. See script for more details.
- returns: <Promise<ElementHandle>> which resolves to the added tag when the script's onload fires or when the script content was injected into frame.
将 url 或脚本内容添加到 <script>
标签中。
frame.addStyleTag(options)
options
<Object>url
<string> URL of the<link>
tag.path
<string> Path to the CSS file to be injected into frame. Ifpath
is a relative path, then it is resolved relative to current working directory.content
<string> Raw CSS content to be injected into frame.
- returns: <Promise<ElementHandle>> which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame.
根据样式路径或内容往页面中添加 <link rel="stylesheet">
或 <style type="text/css">
样式标签。
frame.childFrames()
frame.click(selector[, options])
selector
<string> A selector to search for element to click. If there are multiple elements satisfying the selector, the first will be clicked.options
<Object>button
<string>left
,right
, ormiddle
, defaults toleft
.clickCount
<number> defaults to 1. See UIEvent.detail.delay
<number> Time to wait betweenmousedown
andmouseup
in milliseconds. Defaults to 0.
- returns: <Promise> Promise which resolves when the element matching
selector
is successfully clicked. The Promise will be rejected if there is no element matchingselector
.
这个方法选择传入的元素,如果必要的话会将元素滚动到可视区域,之后使用 page.mouse 点击元素的内容。如果没有匹配到元素,会抛出异常。
注意:如果 click()
触发了导航事件,那么就会有一个由 page.waitForNavigation()
产生的 promise 要被解析,你可能会得到一个 promise 的竞争状态。正确的处理 click 和 wait for navigation 的方式如下:
const [response] = await Promise.all([
page.waitForNavigation(waitOptions),
frame.click(selector, clickOptions),
]);
frame.content()
获取框架完整的HTML内容,包括 doctype。
frame.evaluate(pageFunction, ...args)
pageFunction
<function|string> Function to be evaluated in browser context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
如果传给 frame.evaluate
的函数返回了一个 promise,那么 frame.evaluate
将会等到 promise resolve 时返回它的值。
如果传给 frame.evaluate
的函数返回了一个非序列化的值,那么 frame.evaluate
将返回 undefined
const result = await frame.evaluate(() => {
return Promise.resolve(8 * 7);
});
console.log(result); // 输出 "56"
也可以给函数传递字符串。
console.log(await frame.evaluate('1 + 2')); // 输出 "3"
ElementHandle 实例也可以作为 frame.evaluate
的参数:
const bodyHandle = await frame.$('body');
const html = await frame.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose();
frame.evaluateHandle(pageFunction, ...args)
pageFunction
<function|string> Function to be evaluated in the page context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<JSHandle>> Promise which resolves to the return value of
pageFunction
as in-page object (JSHandle)
frame.evaluate
和 frame.evaluateHandle
唯一的不同是 frame.evaluateHandle
返回页面对象(JSHandle)。
如果传给 frame.evaluateHandle
的函数返回了一个 Promise,那么 frame.evaluateHandle
将会等到 promise resolve 时返回它的值。
const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window));
aWindowHandle; // Handle for the window object.
也可以向函数传递字符串。
const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'.
JSHandle 实例也可以作为 frame.evaluateHandle
的参数:
const aHandle = await frame.evaluateHandle(() => document.body);
const resultHandle = await frame.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue());
await resultHandle.dispose();
frame.executionContext()
- returns: <Promise<ExecutionContext>>
返回解析为框架的默认执行上下文的 promise。
frame.focus(selector)
selector
<string> 一个选择器元素。A selector of an element to focus. If there are multiple elements satisfying the selector, the first will be focused.- returns: <Promise> Promise which resolves when the element matching
selector
is successfully focused. The promise will be rejected if there is no element matchingselector
.
这个方法选择传入的元素并且使之获得焦点。如果没有匹配到元素,会抛出异常。
frame.goto(url, options)
url
<string> URL to navigate frame to. The url should include scheme, e.g.https://
.options
<Object> Navigation parameters which might have the following properties:timeout
<number> Maximum navigation time in milliseconds, defaults to 30 seconds, pass0
to disable timeout. The default value can be changed by using the page.setDefaultNavigationTimeout(timeout) method.waitUntil
<string|Array<string>> When to consider navigation succeeded, defaults toload
. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:load
- consider navigation to be finished when theload
event is fired.domcontentloaded
- consider navigation to be finished when theDOMContentLoaded
event is fired.networkidle0
- consider navigation to be finished when there are no more than 0 network connections for at least500
ms.networkidle2
- consider navigation to be finished when there are no more than 2 network connections for at least500
ms.
referer
<string> Referer header value. If provided it will take preference over the referer header value set by page.setExtraHTTPHeaders().
- returns: <Promise<?Response>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
如果存在下面的情况 frame.goto
将会抛出错误:
- SSL 错误 (e.g. in case of self-signed certificates).
- 目标 URL 不可用。
- 导航过程中
timeout
被触发。 - 主资源加载失败。
注意
frame.goto
抛出或返回一个主资源响应。 唯一的例外是导航到about:blank
或导航到具有不同 hash 的相同URL,这将成功并返回null
。
注意 无头模式将不支持导航到一个 PDF 文档。具体见 upstream issue.
frame.hover(selector)
selector
<string> A selector to search for element to hover. If there are multiple elements satisfying the selector, the first will be hovered.- returns: <Promise> Promise which resolves when the element matching
selector
is successfully hovered. Promise gets rejected if there's no element matchingselector
.
这个方法选择传入的元素,如果必要的话会滚动到视野区域中,然后使用 page.mouse 方法将鼠标悬浮在元素的中心。
如果没有匹配到元素,会抛出异常。
frame.isDetached()
- returns: <boolean>
如果框架不被加载了返回 true
,否则返回 false
。
frame.name()
- returns: <string>
返回框架在标签中指定的 name 属性。
如果 name 为空,返回 id。
注意 这个值在框架创建的时侯就就计算好了,如果之后修改属性的话不会更新。
frame.parentFrame()
- returns: <?Frame> Returns parent frame, if any. Detached frames and main frames return
null
.
frame.select(selector, ...values)
selector
<string> A selector to query frame for...values
<...string> Values of options to select. If the<select>
has themultiple
attribute, all values are considered, otherwise only the first one is taken into account.- returns: <Promise<Array<string>>> Returns an array of option values that have been successfully selected.
下拉框一旦选择了所提供的选项,change
和 input
事件将会被触发。
如果没有匹配到下拉框,会抛出异常。
frame.select('select#colors', 'blue'); // 单选
frame.select('select#colors', 'red', 'green', 'blue'); // 多选
frame.setContent(html)
frame.tap(selector)
selector
<string> A selector to search for element to tap. If there are multiple elements satisfying the selector, the first will be tapped.- returns: <Promise>
这个方法选择传入的元素,如果必要的话会滚动到视野区域中,然后使用 page.touchscreen 方法单击元素中心。
如果没有匹配到元素,会抛出异常。
frame.title()
frame.type(selector, text[, options])
selector
<string> A selector of an element to type into. If there are multiple elements satisfying the selector, the first will be used.text
<string> A text to type into a focused element.options
<Object>delay
<number> Time to wait between key presses in milliseconds. Defaults to 0.
- returns: <Promise>
对于每一个文本中的字符执行 keydown
、keypress
/ input
, 和 keyup
事件
如果要输入特殊按键,比如 Control
或者 ArrowDown
,使用 keyboard.press
。
frame.type('#mytextarea', 'Hello'); // 立即输入
frame.type('#mytextarea', 'World', {delay: 100}); // 延迟输入, 操作更像用户
frame.url()
- returns: <string>
返回框架的 url。
frame.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])
selectorOrFunctionOrTimeout
<string|number|function> A selector, predicate or timeout to wait foroptions
<Object> Optional waiting parameters...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<JSHandle>> Promise which resolves to a JSHandle of the success value
这个方法根据第一个参数类型的不同起到不同的作用:
- 如果
selectorOrFunctionOrTimeout
是string
,那么第一个参数会被当作 selector 或者 xpath,取决于是不是以//
开头的,这是 frame.waitForSelector 或 frame.waitForXPath 的快捷方式。 - 如果
selectorOrFunctionOrTimeout
是function
,那么第一个参数会当作条件等待触发,这是 frame.waitForFunction() 的快捷方式。 - 如果
selectorOrFunctionOrTimeout
是number
,那么第一个参数会被当作毫秒为单位的时间,方法会在超时之后返回 promise。 - 其他类型,将会抛出错误。
// wait for selector
await page.waitFor('.foo');
// wait for 1 second
await page.waitFor(1000);
// wait for predicate
await page.waitFor(() => !!document.querySelector('.foo'));
将 node.js 中的参数传递给 page.waitFor
函数:
const selector = '.foo';
await page.waitFor(selector => !!document.querySelector(selector), {}, selector);
frame.waitForFunction(pageFunction[, options[, ...args]])
pageFunction
<function|string> Function to be evaluated in browser contextoptions
<Object> Optional waiting parameterspolling
<string|number> An interval at which thepageFunction
is executed, defaults toraf
. Ifpolling
is a number, then it is treated as an interval in milliseconds at which the function would be executed. Ifpolling
is a string, then it can be one of the following values:raf
- to constantly executepageFunction
inrequestAnimationFrame
callback. This is the tightest polling mode which is suitable to observe styling changes.mutation
- to executepageFunction
on every DOM mutation.
timeout
<number> maximum time to wait for in milliseconds. Defaults to30000
(30 seconds). Pass0
to disable timeout.
...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<JSHandle>> Promise which resolves when the
pageFunction
returns a truthy value. It resolves to a JSHandle of the truthy value.
waitForFunction
可以用来观察可视区域大小是否改变。
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100');
page.setViewport({width: 50, height: 50});
await watchDog;
await browser.close();
});
将 node.js 中的参数传递给 page.waitForFunction
函数:
const selector = '.foo';
await page.waitForFunction(selector => !!document.querySelector(selector), {}, selector);
frame.waitForNavigation(options)
options
<Object> Navigation parameters which might have the following properties:timeout
<number> Maximum navigation time in milliseconds, defaults to 30 seconds, pass0
to disable timeout. The default value can be changed by using the page.setDefaultNavigationTimeout(timeout) method.waitUntil
<string|Array<string>> When to consider navigation succeeded, defaults toload
. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:load
- consider navigation to be finished when theload
event is fired.domcontentloaded
- consider navigation to be finished when theDOMContentLoaded
event is fired.networkidle0
- consider navigation to be finished when there are no more than 0 network connections for at least500
ms.networkidle2
- consider navigation to be finished when there are no more than 2 network connections for at least500
ms.
- returns: <Promise<[?Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will resolve with
null
.
当框架导航到新 URL 时将被解析。它在运行代码时很有用。这将间接导致框架进行导航。看下这个例子:
const [response] = await Promise.all([
frame.waitForNavigation(), // The navigation promise resolves after navigation has finished
frame.click('a.my-link'), // Clicking the link will indirectly cause a navigation
]);
注意 使用 History API 去改变 URL 将会被认为是导航。
frame.waitForSelector(selector[, options])
selector
<string> A selector of an element to wait foroptions
<Object> Optional waiting parametersvisible
<boolean> wait for element to be present in DOM and to be visible, i.e. to not havedisplay: none
orvisibility: hidden
CSS properties. Defaults tofalse
.hidden
<boolean> wait for element to not be found in the DOM or to be hidden, i.e. havedisplay: none
orvisibility: hidden
CSS properties. Defaults tofalse
.timeout
<number> maximum time to wait for in milliseconds. Defaults to30000
(30 seconds). Pass0
to disable timeout.
- returns: <Promise<ElementHandle>> Promise which resolves when element specified by selector string is added to DOM.
等待被选择等待元素出现在页面中。如果调用时选择的元素已存在,则立即返回。如果在设定的毫秒时间之后还没有出现,则抛出异常。
这个方法可以在切换导航时使用:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
let currentURL;
page.mainFrame()
.waitForSelector('img')
.then(() => console.log('First URL with image: ' + currentURL));
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
await page.goto(currentURL);
await browser.close();
});
frame.waitForXPath(xpath[, options])
xpath
<string> A xpath of an element to wait foroptions
<Object> Optional waiting parametersvisible
<boolean> wait for element to be present in DOM and to be visible, i.e. to not havedisplay: none
orvisibility: hidden
CSS properties. Defaults tofalse
.hidden
<boolean> wait for element to not be found in the DOM or to be hidden, i.e. havedisplay: none
orvisibility: hidden
CSS properties. Defaults tofalse
.timeout
<number> maximum time to wait for in milliseconds. Defaults to30000
(30 seconds). Pass0
to disable timeout.
- returns: <Promise<ElementHandle>> Promise which resolves when element specified by xpath string is added to DOM.
等待 xpath
出现在页面中。如果在调用函数的时候 xpath
已经存在,会立即返回。如果在设定的毫秒时间之后还没有出现,则抛出异常。
这个方法可以在切换导航时使用:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
let currentURL;
page.mainFrame()
.waitForXPath('//img')
.then(() => console.log('First URL with image: ' + currentURL));
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
await page.goto(currentURL);
await browser.close();
});
class: ExecutionContext
该类表示一个 JavaScript 执行的上下文。 Page 可能有许多执行上下文:
- 每个 frame 都有 "默认" 的执行上下文,它始终在将帧附加到 DOM 后创建。该上下文由
frame.executionContext()
方法返回。 - Extensions 的内容脚本创建了其他执行上下文。
除了页面,执行上下文可以在 workers 中找到。
executionContext.evaluate(pageFunction, ...args)
pageFunction
<function|string> Function to be evaluated inexecutionContext
...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
如果传递给 executionContext.evaluate
的函数返回一个Promise,那么 executionContext.evaluate
将等待承诺解析并返回它的值。
const executionContext = await page.mainFrame().executionContext();
const result = await executionContext.evaluate(() => Promise.resolve(8 * 7));
console.log(result); // 输出 "56"
入参可以是一个字符串,但不能是函数。
console.log(await executionContext.evaluate('1 + 2')); // 输出 "3"
JSHandle 实例可以作为参数传递给 executionContext.evaluate
:
const oneHandle = await executionContext.evaluateHandle(() => 1);
const twoHandle = await executionContext.evaluateHandle(() => 2);
const result = await executionContext.evaluate((a, b) => a + b, oneHandle, twoHandle);
await oneHandle.dispose();
await twoHandle.dispose();
console.log(result); // 输出 '3'
executionContext.evaluateHandle(pageFunction, ...args)
pageFunction
<function|string> 函数在executionContext
中被运行...args
<...Serializable|JSHandle> 传递给pageFunction
的参数- returns: <Promise<JSHandle>> Promise which resolves to the return value of
pageFunction
as in-page object (JSHandle)
executionContext.evaluate
和 executionContext.evaluateHandle
唯一的区别在于executionContext.evaluateHandle
会返回页内对象(JSHandle)。
如果传递给 executionContext.evaluateHandle
的函数返回一个 Promise,那么executionContext.evaluateHandle
将等待承诺解析并返回它的值。
const context = await page.mainFrame().executionContext();
const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
aHandle; // 处理全局对象
入参可以是一个字符串,但不能是函数。
const aHandle = await context.evaluateHandle('1 + 2'); // 处理'3'对象
JSHandle 实例可以作为参数传递给 executionContext.evaluateHandle
:
const aHandle = await context.evaluateHandle(() => document.body);
const resultHandle = await context.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue()); // 输出 body 的 innerHTML
await aHandle.dispose();
await resultHandle.dispose();
executionContext.frame()
- returns: <?Frame> 与此执行上下文相关的框架。
注意 并非每个执行的上下文都与框架有关系。 例如,workers 和扩展程序具有与框架无关的执行上下文。
executionContext.queryObjects(prototypeHandle)
该方法重复查找 JavaScript 堆,找到具有给定原型的所有对象。
// 创建一个 Map 对象
await page.evaluate(() => window.map = new Map());
// 获取 Map 对象原型的句柄
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// 将所有映射实例查询到一个数组中
const mapInstances = await page.queryObjects(mapPrototype);
// 计算堆中映射对象的数量
const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose();
await mapPrototype.dispose();
class: JSHandle
JSHandle 表示页面内的 JavaScript 对象。 JSHandles 可以使用 page.evaluateHandle 方法创建。
const windowHandle = await page.evaluateHandle(() => window);
// ...
JSHandle 可防止引用的 JavaScript 对象被垃圾收集,除非是句柄 disposed。 当原始框架被导航或父上下文被破坏时,JSHandles 会自动处理。
JSHandle 实例可以使用在 page.$eval()
,page.evaluate()
和 page.evaluateHandle
方法。
jsHandle.asElement()
- returns: <?ElementHandle>
如果对象句柄是 ElementHandle 的一个实例,则返回 null
或对象句柄本身。
jsHandle.dispose()
- returns: <Promise> Promise which resolves when the object handle is successfully disposed.
jsHandle.dispose
方法停止引用元素句柄。
jsHandle.executionContext()
- returns: ExecutionContext
返回句柄所属的执行上下文。
jsHandle.getProperties()
该方法返回一个包含属性名称作为键的映射和属性值的 JSHandle 实例。
const handle = await page.evaluateHandle(() => ({window, document}));
const properties = await handle.getProperties();
const windowHandle = properties.get('window');
const documentHandle = properties.get('document');
await handle.dispose();
jsHandle.getProperty(propertyName)
从引用的对象中获取单个属性。
jsHandle.jsonValue()
返回对象的 JSON 表示。如果对象又一个 toJSON
函数, 它 将不会被调用。
注意 如果引用的对象不可字符串化,该方法将返回一个空的 JSON 对象。 如果对象具有循环引用,它将引发一个错误。
class: ElementHandle
注意 ElementHandle 类继承自 JSHandle。
ElementHandle 表示一个页内的 DOM 元素。ElementHandles 可以通过 page.$ 方法创建。
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://google.com');
const inputElement = await page.$('input[type=submit]');
await inputElement.click();
// ...
});
除非处理了句柄 disposed,否则 ElementHandle 会阻止垃圾收集中的 DOM 元素。 ElementHandles 在其原始帧被导航时将会自动处理。
ElementHandle 实例可以在 page.$eval()
和 page.evaluate()
方法中作为参数。
elementHandle.$(selector)
selector
<string> 用于选取页面 DOM 元素的 CSS Selector- returns: <Promise<?ElementHandle>>
该方法在页面内运行 element.querySelector
。 如果没有元素匹配选择器,则返回值为 null
。
elementHandle.$$(selector)
selector
<string> 用于选取页面 DOM 元素的 CSS Selector- returns: <Promise<Array<ElementHandle>>>
该方法在页面内运行 element.querySelectorAll
。 如果没有元素匹配选择器,则返回值为 []
。
elementHandle.$eval(selector, pageFunction, ...args)
selector
<string> 用于选取页面 DOM 元素的 CSS SelectorpageFunction
<function> 在浏览器上下文中执行的函数...args
<...Serializable|JSHandle> 传递给pageFunction
的参数- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
这个方法在元素中运行 document.querySelector
并将它作为第一个参数传递给 pageFunction
。 如果没有与 selector
匹配的元素,则该方法将抛出个错误。
如果 pageFunction
返回一个 Promise,那么 frame.$eval
将等待承诺解析并返回它的值。
例子:
const tweetHandle = await page.$('.tweet');
expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100');
expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10');
elementHandle.$$eval(selector, pageFunction, ...args)
selector
<string> 用于选取页面 DOM 元素的 CSS SelectorpageFunction
<function> Function to be evaluated in browser context...args
<...Serializable|JSHandle> Arguments to pass topageFunction
- returns: <Promise<Serializable>> Promise which resolves to the return value of
pageFunction
该方法在元素内运行 document.querySelectorAll
,并将其作为第一个参数传递给 pageFunction
。 如果没有与 selector
匹配的元素,则该方法将抛出一个错误。
如果 pageFunction
返回 Promise,那么frame.$$eval
将等待 promise 解析并返回其值。
例子:
<div class="feed">
<div class="tweet">Hello!</div>
<div class="tweet">Hi!</div>
</div>
const feedHandle = await page.$('.feed');
expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText)).toEqual(['Hello!', 'Hi!']);
elementHandle.$x(expression)
expression
<string> Expression to evaluate.- returns: <Promise<Array<ElementHandle>>>
该方法计算相对于 elementHandle 的 XPath 表达式。 如果不存在这样的元素,该方法将解析为一个空的数组。
elementHandle.asElement()
- returns: <ElementHandle>
elementHandle.boundingBox()
此方法返回元素的边界框(相对于主框架),如果元素不可见,则返回 null
。
elementHandle.boxModel()
- returns: <Promise<?Object>>
- content <Array<Object>> Content box, represented as an array of {x, y} points.
- padding <Array<Object>> Padding box, represented as an array of {x, y} points.
- border <Array<Object>> Border box, represented as an array of {x, y} points.
- margin <Array<Object>> Margin box, represented as an array of {x, y} points.
- width <number> 元素的宽度.
- height <number> 元素的高度.
改方法返回元素的盒模型,如果元素不可见,则返回 null
。 盒模型被表示为一组点;每个 Point 都是一个对象 {x,y}
。 盒模型的点按顺时针排序。
elementHandle.click([options])
options
<Object>button
<string>left
,right
, 或middle
, 默认是left
。clickCount
<number> 默认是 1. 见 UIEvent.detail.delay
<number>mousedown
和mouseup
之间等待的时间。 默认是 0。
- returns: <Promise> Promise which resolves when the element is successfully clicked. Promise gets rejected if the element is detached from DOM.
如果需要,此方法将元素滚动到视野中,然后使用 page.mouse 单击元素的中心。 如果该元素从 DOM 中分离,则该方法将引发错误。
elementHandle.contentFrame()
elementHandle.dispose()
- returns: <Promise> Promise which resolves when the element handle is successfully disposed.
elementHandle.dispose
方法用于停止引用元素的句柄。
elementHandle.executionContext()
- returns: ExecutionContext
elementHandle.focus()
- returns: <Promise>
在元素上调用 focus。
elementHandle.getProperties()
该方法返回一个包含属性名称作为键的映射和属性值的 JSHandle 实例。
const listHandle = await page.evaluateHandle(() => document.body.children);
const properties = await listHandle.getProperties();
const children = [];
for (const property of properties.values()) {
const element = property.asElement();
if (element)
children.push(element);
}
children; // body持有 elementHandles 给 document.body 的所有子项。
elementHandle.getProperty(propertyName)
从 objectHandle 中获取一个属性。
elementHandle.hover()
- returns: <Promise> Promise which resolves when the element is successfully hovered.
如果需要,此方法将元素滚动到视野中,然后使用 page.mouse 将鼠标悬停在元素的中心。 如果元素从 DOM 中分离(不存在),则该方法将抛出一个错误。
elementHandle.isIntersectingViewport()
elementHandle.jsonValue()
返回对象的JSON表示。 JSON是通过对页面上的对象运行 JSON.stringify
生成的,因此 JSON.parse
在puppeteer中。
注意 如果引用的对象不可字符串化,该方法将抛出(一个错误)。
elementHandle.press(key[, options])
key
<string> 按键的名称,例如ArrowLeft
。 见 USKeyboardLayout 以获取所有键名称的列表。options
<Object>- returns: <Promise>
聚焦元素,然后使用 keyboard.down
和 keyboard.up
。
如果 key
是一个单独的字符,并且除了 Shift
之外没有(其他)修饰键被按下,keypress
/ input
事件也会被生成。 可以指定 text
选项来强制生成输入事件。
注意 修饰键 DO 会影响
elementHandle.press
。 按住 Shift 键将以大写形式输入文本。
elementHandle.screenshot([options])
options
<Object> 与 page.screenshot 选项相同。- returns: <Promise<Buffer>> Promise which resolves to buffer with captured screenshot.
如果需要,此方法将元素滚动到视图中,然后使用 page.screenshot 截取元素的屏幕截图。 如果该元素从 DOM 中分离,则该方法将抛出一个错误。
elementHandle.tap()
- returns: <Promise> Promise which resolves when the element is successfully tapped. Promise gets rejected if the element is detached from DOM.
如果需要,此方法将元素滚动到视野中,然后使用 touchscreen.tap 在元素的中心点击。 如果该元素从 DOM 中分离,则该方法将抛出一个错误。
elementHandle.toString()
- returns: <string>
elementHandle.type(text[, options])
聚焦元素,然后为文本中的每个字符发送 keydown
,keypress
/ input
和 keyup
事件。
按一个特殊的键,像 Control
或 ArrowDown
,使用 elementHandle.press
。
elementHandle.type('Hello'); // 立即输入
elementHandle.type('World', {delay: 100}); // 慢点输入,像一个用户
键入文本字段然后提交表单的例子:
const elementHandle = await page.$('input');
await elementHandle.type('some text');
await elementHandle.press('Enter');
elementHandle.uploadFile(...filePaths)
这个方法期望 elementHandle
指向一个 输入元素。
class: Request
每当页面发送一个请求,例如网络请求,以下事件会被 puppeteer 页面触发:
- 'request' 当请求发起后页面会触发这个事件。
- 'response' 请求收到响应的时候触发。
- 'requestfinished' 请求完成并且响应体下载完成时触发
如果某些时候请求失败,后续不会触发 'requestfinished' 事件(可能也不会触发 'response' 事件),而是触发 'requestfailed' 事件
如果请求得到一个重定向的响应,请求会成功地触发 'requestfinished' 事件,并且对重定向的 url
发起一个新的请求
request.abort([errorCode])
errorCode
<string> 可选的错误码。默认为failed
,可以是以下值:aborted
- 操作被取消 (因为用户的行为)accessdenied
- 访问资源权限不足(非网络原因)addressunreachable
- 找不到IP地址 这通常意味着没有路由通向指定主机或者网络blockedbyclient
- 客户端选择阻止请求blockedbyresponse
- 请求失败,因为响应是与未满足的要求一起传递出去的(例如,'X-Frame-Options' 和'Content-Security-Policy' 祖先检查)connectionaborted
- 未收到数据发送的ACK信号导致的连接超时connectionclosed
- 连接关闭(对应 TCP FIN 包)connectionfailed
- 尝试连接失败。connectionrefused
- 尝试连接拒绝。connectionreset
- 连接被重置 (对应 TCP RST 包)。internetdisconnected
- 网络连接丢失。namenotresolved
- 主机名字无法被解析。timedout
- 操作超时。failed
- 发生通用错误。
- returns: <Promise>
想要中断请求,应该使用 page.setRequestInterception
来开启请求拦截,如果请求拦截没有开启会立即抛出异常。
request.continue([overrides])
想要用可选的请求覆写选项继续请求,应该使用 page.setRequestInterception
来开启请求拦截,如果请求拦截没有开启会立即抛出异常
request.failure()
requestfailed
事件触发后,在没有请求失败的情况下,这个方法会返回 null
。
输出所有失败请求示例:
page.on('requestfailed', request => {
console.log(request.url() + ' ' + request.failure().errorText);
});
request.frame()
request.headers()
- returns: <Object> 该请求的 http 头对象。所有头都采用小写的命名方式
request.isNavigationRequest()
- returns: <boolean>
这个请求是否正在驱动框架在导航。
request.method()
- returns: <string> 请求方法 ( GET,POST,等。)
request.postData()
- returns: <string> 请求提交的数据。
request.redirectChain()
redirectChain
是一条获取资源的请求链
- 如果没有被重定向而且请求成功的话, 链路将会被置空
- 如果服务器至少响应了一次重定向, 那么这条链路将会包含所有重定向请求
redirectChain
会共享相同链路上的所有请求。
举个例子,如果网站 http://example.com
重定向一次到
https://example.com
,那么这条链就会包含一个请求:
const response = await page.goto('http://example.com');
const chain = response.request().redirectChain();
console.log(chain.length); // 1
console.log(chain[0].url()); // 'http://example.com'
如果网站 https://google.com
没有重定向,那么链(数组)就会被置空:
const response = await page.goto('https://google.com');
const chain = response.request().redirectChain();
console.log(chain.length); // 0
request.resourceType()
- returns: <string>
包含渲染引擎识别出的请求资源类型
资源类型为以下值中的一个:document
,stylesheet
,image
,media
,font
,script
,texttrack
,xhr
,fetch
,eventsource
,websocket
,manifest
,other
。
request.respond(response)
完成请求后会返回一个响应。可以通过开启 page.setRequestInterception
选项来使用请求拦截,如果请求拦截没有开启则会抛出异常。
下面例子中,所有执行完成的请求都会返回 404 响应体
await page.setRequestInterception(true);
page.on('request', request => {
request.respond({
status: 404,
contentType: 'text/plain',
body: 'Not Found!'
});
});
注意
request.respond
不支持模拟响应dataURL
请求。 对dataURL
请求使用request.respond
并不会起任何作用。
request.response()
- returns: <?Response> 相应的 Response 对象,如果没有收到响应则是
null
。
request.url()
- returns: <string> 请求的 URL。
class: Response
Response 类表示页面接收的响应。
response.buffer()
- returns: <Promise<Buffer>> Promise which resolves to a buffer with response body.
response.frame()
response.fromCache()
- returns: <boolean>
如果响应来自浏览器的磁盘缓存或内存缓存,则为 true。
response.fromServiceWorker()
- returns: <boolean>
如果响应是由 service worker 提供的,则为 true。
response.headers()
- returns: <Object> 具有与响应关联的 HTTP 头对象。 所有标题名称都是小写。
response.json()
- returns: <Promise<Object>> Promise which resolves to a JSON representation of response body.
如果响应主体无法进行 JSON.parse
解析,则此方法将抛出错误。
response.ok()
- returns: <boolean>
包含一个布尔值,说明响应是否成功(状态范围为200-299)。
response.remoteAddress()
response.request()
response.securityDetails()
- returns: <?SecurityDetails> 如果通过安全连接接收到响应,则为安全细节,否则为
null
。
response.status()
- returns: <number>
包含响应的状态代码(例如,200成功)。
response.statusText()
- returns: <string>
包含响应的状态文本(例如,通常成功的 "OK")。
response.text()
response.url()
- returns: <string>
包含响应的 URL。
class: SecurityDetails
SecurityDetails 类表示通过安全连接收到响应时的安全性详细信息。
securityDetails.issuer()
- returns: <string> 具有证书颁发者名称的字符串。
securityDetails.protocol()
- returns: <string> 带安全协议的字符串,例如:"TLS 1.2"。
securityDetails.subjectName()
- returns: <string> 证书颁发给的主体的名称。
securityDetails.validFrom()
securityDetails.validTo()
class: Target
target.browser()
- returns: <Browser>
获取目标所属的浏览器。
target.browserContext()
- returns: <BrowserContext>
目标所属的浏览器上下文。
target.createCDPSession()
- returns: <Promise<CDPSession>>
创建一个 Chrome Devtools 协议会话至目标。
target.opener()
- returns: <?Target>
获取打开此目标的目标。 顶级目标返回null
。
target.page()
如果目标不是 "page"
或 "background_page"
类型,则返回 null
。
target.type()
- returns: <string>
确定目标是怎么样的类型。 可以是 "page"
,"background_page"
,"service_worker"
,"browser"
或 "其他"
。
target.url()
- returns: <string>
class: CDPSession
- extends:
EventEmitter
CDPSession
实例用于与 Chrome Devtools 协议的原生通信:
- 协议方法可以用
session.send
方法调用。 - 协议事件可以通过
session.on
方法订阅。
DevTools Protocol 的文档具体见这里: DevTools Protocol Viewer.
const client = await page.target().createCDPSession();
await client.send('Animation.enable');
client.on('Animation.animationCreated', () => console.log('Animation created!'));
const response = await client.send('Animation.getPlaybackRate');
console.log('playback rate is ' + response.playbackRate);
await client.send('Animation.setPlaybackRate', {
playbackRate: response.playbackRate / 2
});
cdpSession.detach()
- returns: <Promise>
从目标中分离 cdpSession。 一旦分离,cdpSession 对象将不会触发任何事件并且不能用于发送消息。
cdpSession.send(method[, params])
method
<string> protocol method nameparams
<Object> Optional method parameters- returns: <Promise<Object>>
class: Coverage
Coverage 收集相关页面使用的 JavaScript 和 CSS 部分的信息。
使用 JavaScript 和 CSS 覆盖率来获取初始百分比的例子 执行代码:
// 启用 JavaScript 和 CSS 覆盖
await Promise.all([
page.coverage.startJSCoverage(),
page.coverage.startCSSCoverage()
]);
// 导航至页面
await page.goto('https://example.com');
// 禁用 JavaScript 和 CSS 覆盖
const [jsCoverage, cssCoverage] = await Promise.all([
page.coverage.stopJSCoverage(),
page.coverage.stopCSSCoverage(),
]);
let totalBytes = 0;
let usedBytes = 0;
const coverage = [...jsCoverage, ...cssCoverage];
for (const entry of coverage) {
totalBytes += entry.text.length;
for (const range of entry.ranges)
usedBytes += range.end - range.start - 1;
}
console.log(`Bytes used: ${usedBytes / totalBytes * 100}%`);
使用 Istanbul 输出一个覆盖率表格,见 puppeteer-to-istanbul.
coverage.startCSSCoverage(options)
options
<Object> 覆盖范围的配置项resetOnNavigation
<boolean> 是否重置每个导航的覆盖范围。默认是true
。
- returns: <Promise> Promise that resolves when coverage is started
coverage.startJSCoverage(options)
注意 匿名脚本指的是没有关联 URL 的脚本。 它们是使用
eval
或new Function
在页面上动态创建的脚本。如果reportAnonymousScripts
设置为true
,匿名脚本将使用__puppeteer_evaluation_script__
作为其URL。
coverage.stopCSSCoverage()
- returns: <Promise<Array<Object>>> Promise that resolves to the array of coverage reports for all stylesheets
注意 CSS Coverage 不包含没有 sourceURL 的动态注入式样式标签。
coverage.stopJSCoverage()
- returns: <Promise<Array<Object>>> Promise that resolves to the array of coverage reports for all non-anonymous scripts
注意 JavaScript Coverage 默认情况下不包含匿名脚本。 但是,具有 sourceURL 的脚本将被上报。
class: TimeoutError
- extends: Error
每当某些操作因超时而终止时,就会触发 TimeoutError。例如 page.waitForSelector(selector[, options]) 或者 puppeteer.launch([options])。