最近用到了 Puppeteer 这个库,既然用到了这个东西,顺便也就把它的 API给看了一遍,为了加深印象,在看的同时也就顺便翻译了一下,不过这API文档的内容量还是蛮大的,花费了好些时间才看完,有些地方不知道怎么翻译比较好,所以也就没翻译,有的地方可能官方说得不怎么详细,我也加了一点主观意见。
- Overview
- Environment Variables
- class: Puppeteer
* puppeteer.connect(options)
* puppeteer.createBrowserFetcher([options])
* puppeteer.defaultArgs()
* puppeteer.executablePath()
* puppeteer.launch([options])
- class: BrowserFetcher
* browserFetcher.canDownload(revision)
* browserFetcher.download(revision[, progressCallback])
* browserFetcher.localRevisions()
* browserFetcher.platform()
* browserFetcher.remove(revision)
* browserFetcher.revisionInfo(revision)
- class: Browser
* event: ‘disconnected’
* event: ‘targetchanged’
* event: ‘targetcreated’
* event: ‘targetdestroyed’
* browser.browserContexts()
* browser.close()
* browser.createIncognitoBrowserContext()
* browser.disconnect()
* browser.newPage()
* browser.pages()
* browser.process()
* browser.targets()
* browser.userAgent()
* browser.version()
* browser.wsEndpoint()
- class: BrowserContext
* event: ‘targetchanged’
* event: ‘targetcreated’
* event: ‘targetdestroyed’
* browserContext.browser()
* browserContext.close()
* browserContext.isIncognito()
* browserContext.newPage()
* browserContext.targets()
- class: Page
* event: ‘close’
* event: ‘console’
* event: ‘dialog’
* event: ‘domcontentloaded’
* event: ‘error’
* event: ‘frameattached’
* event: ‘framedetached’
* event: ‘framenavigated’
* event: ‘load’
* event: ‘metrics’
* event: ‘pageerror’
* event: ‘request’
* event: ‘requestfailed’
* event: ‘requestfinished’
* event: ‘response’
* event: ‘workercreated’
* event: ‘workerdestroyed’
* page.$(selector)
* page.
Puppeteer是一个通过 DevTools Protocol 来控制 Chromium 或者 Chrome的 Node库,并提供了一些高级API。
这些API层级分明,并能提现出浏览器的自身结构。
NOTE 在下面这个图例中,浅色实体代表的结构尚未在 Puppeteer中实现。
Puppeteer
使用 DevTools Protocol与浏览器进行通信。Browser
浏览器实例可以包含多个浏览器上下文。BrowserContext
用于保持浏览器session,一个浏览器上下文可以包含多个页面。Page
一个Page最起码包含一个frame,即 main frame,允许存在其他的 frame,这些frame可以用 [iframe]创建。Frame
一个 Frame最起码有一个 Javascript执行上下文环境,即默认的执行上下文环境。Frame允许存在额外附加的上下文环境Worker
存在唯一的上下文环境,并可与 WebWorkers相互协作。(图例来源: link)
Puppeteer 需要明确的 environment variables 来协助其完成一系列操作,如果 Puppeteer没有在打钱执行环境中发现这些环境变量,那么将会直接从 npm config搜寻(忽略大小写)。
HTTP_PROXY
, HTTPS_PROXY
, NO_PROXY
- 定义了 HTTP proxy的相关配置,常用于下载或启动 Chromium。PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
- 用于指示 Puppeteer不要在安装的过程中下载 Chromium安装包。PUPPETEER_DOWNLOAD_HOST
- 用于覆写下载 Chromium安装包的地址url。PUPPETEER_CHROMIUM_REVISION
- 在安装阶段,用于明确指示 Puppeteer下载安装哪个版本的 Chromium。Puppeteer模块提供了一个用于启动一个Chromium实例的方法。
下面的代码展示了一种使用 Puppeteer来启动 Chromium实例的典型例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.google.com');
// other actions...
await browser.close();
});
options
此方法将会为 Puppeteer 附加上一个 Chromium 实例。
options
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
阶段 Chromium包被跳过下载,那么此包也有可能是不存在的。options
此方法根据给定的参数来启动一个浏览器实例,此浏览器实例将会在其 node.js主进程关闭时被销毁。
NOTE Puppeteer 也可以直接用于控制 Chrome浏览器, 不过,只有当其控制的 Chrome浏览器的版本和其本身绑定的 Chromium版本一致时才能最大程度地发挥作用,如果版本不一致,可能无法正常运行, 特别是当你使用了
executablePath
选项的时候。如果你更想使用 Google Chrome (而不是Chromium) 的话, a Chrome Canary or Dev Channel build is suggested.
在上面的 puppeteer.launch([options]) 选项中, 所有提及到 Chromium 的地方同样适用于 Chrome。
你可以在这篇文章中找到 Chromium 与 Chrome之间的不同之处,
这篇文章
则介绍了一些在 Linux平台上的差异。
BrowserFetcher 能够下载和管理不同版本的 Chromium。
BrowserFetcher 的方法可以接收一个 版本号字符串,此版本号指定精确的 Chromium版本,例如 "533271"
,版本号列表可以在 omahaproxy.appspot.com获取。
下面这里例子展示了如何通过 BrowserFetcher来下载一个特定版本的 Chromium,以及使用 Puppeteer来启动这个 Chromium。
const browserFetcher = puppeteer.createBrowserFetcher();
const revisionInfo = await browserFetcher.download('533271');
const browser = await puppeteer.launch({executablePath: revisionInfo.executablePath})
NOTE BrowserFetcher无法与其他使用相同下载目录的 BrowserFetcher实例同时运行。
revision
true
。此方法通过发起一个 HEAD request来检查目标版本是否可用。
revision
progressCallback
downloadedBytes
totalBytes
revision
folderPath
executablePath
url
local
此方法通过发起一个 GET请求来从目标 host下载指定版本的浏览器。
mac
, linux
, win32
、 win64
中的其中一个。revision
revision
returns:
revision
folderPath
executablePath
url
local
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 => {
// Store the endpoint to be able to reconnect to Chromium
const browserWSEndpoint = browser.wsEndpoint();
// Disconnect puppeteer from Chromium
browser.disconnect();
// Use the endpoint to reestablish a connection
const browser2 = await puppeteer.connect({browserWSEndpoint});
// Close Chromium
await browser2.close();
});
当 Puppeteer被从 Chromium实例上断开时被触发,包括如下几种情形:
- Chromium 被关闭或崩溃
- The browser.disconnect
方法被调用
当目标 url改变时触发。
NOTE 包括在匿名浏览器上下文中目标URL改变。
当目标被创建时触发, 例如,当一个新页面通过 window.open
或者 browser.newPage
被打开时。
NOTE 包括在匿名浏览器上下文中目标的创建。
目标被销毁时触发, 例如,当一个页面关闭时。
NOTE 包括在匿名浏览器上下文中目标的销毁。
返回一个包含所有已经被打开的浏览器上下文的数组。 在一个最新被创建的浏览器中,将会返回一个唯一的BrowserContext的实例。
关闭 Chromium以及它所有的页面(如果存在被打开的页面的话)。Browser 对象将会被销毁,并且不再可用。
创建一个新的匿名浏览器上下文,这个匿名浏览器上下文不会与其他浏览器上下文共享 cookies/cache。
const browser = await puppeteer.launch();
// Create a new incognito browser context.
const context = await browser.createIncognitoBrowserContext();
// Create a new page in a pristine context.
const page = await context.newPage();
// Do stuff
await page.goto('https://example.com');
Disconnects Puppeteer from the browser, but leaves the Chromium process running. After calling disconnect
, the Browser object is considered disposed and cannot be used anymore.
断开 Puppeteer与 浏览器之间的连接,不过 Chromium进程依旧继续运行。当调用了disconnect
方法之后,Browser 对象将会被销毁,并且不再可用。
返回一个新的 Page Promise对象,Page将在一个默认的浏览器上下文中创建。
"background_page"
, 将不会包含在此数组中,你可以使用 target.page()方法来获取到(不可见页面)。An array of all active targets inside the Browser. In case of multiple browser contexts,
the method will return an array with all the targets in all browser contexts.
返回Browser实例中包含的所有的有效targets的一个数组,由于可能存在多个浏览器上下文,所以此方法将会返回一个由所有浏览器上下文中的所有 targets梭组成的数组。
NOTE 可以使用 page.setUserAgent来改变浏览器的 user agent。
HeadlessChrome/61.0.3153.0
的字符串。 对于non-headless 浏览器来说, 将返回一个类似于 Chrome/61.0.3153.0
的字符串。NOTE 此方法返回的字符串格式可能会在将来的版本中发生变化。
此方法返回的 浏览器 websoket端口字符串格式如:ws://${host}:${port}/devtools/browser/
,此字符串可作为puppeteer.connect方法的一个参数传入。
You can find the webSocketDebuggerUrl
from http://${host}:${port}/json/version
. Learn more about the devtools protocol and the browser endpoint.
EventEmitter
BrowserContexts提供了一种操作多个独立浏览器session的方法。当启动一个浏览器的时候,将会同时产生一个BrowserContext,并且在这个 BrowserContext中,browser.newPage()
方法将会创建一个新页面。
如果使用例如 window.open
的方法创建了另外的页面, the popup 将隶属于父页面的浏览器上下文。
Puppeteer允许通过 browser.createIncognitoBrowserContext()
方法来创建匿名浏览器上下文,匿名浏览器上下文不会向磁盘中记录任何浏览的内容。
// 创建匿名浏览器上下文
const context = await browser.createIncognitoBrowserContext();
// 在上下文中创建页面
const page = await context.newPage();
// ... do stuff with page ...
await page.goto('https://example.com');
// Dispose context once it's no longer needed.
await context.close();
当浏览器上下文中的某个target url改变时触发。
当浏览器上下文中创建了一个新target时触发,例如,当使用 window.open
或 browserContext.newPage
方法创建一个新页面的时候。
当浏览器上下文中的某个target 被销毁时触发,例如当一个页面被关闭时。
浏览器上下文归属的浏览器实例。
关闭浏览器上下文。所有属于此浏览器上下文的target都将会一同销毁。
NOTE 只有匿名浏览器上下文可以被关闭(也就是只有通过
createIncognitoBrowserContext
方法创建的匿名浏览器才可以使用此方法)。
NOTE 浏览器的默认浏览器上下文是不可关闭的。
在浏览器上下文中创建新页面。
浏览器上下文中的所有有效target(例如Page页面)组成的一个数组。
EventEmitter
Page提供了一些能让你操作 Chromium中标签页的方法。一个 Browser实例中可能包含多个 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();
});
使用 Node模块EventEmitter
的一些方法,我们能够控制 Page类触发的一些事件,例如 on
once
或者 removeListener
等。
下面的例子展示了如何监听页面的 load
事件。
page.once('load', () => console.log('Page loaded!'));
使用 removeListener
方法来移除监听事件:
function logRequest(interceptedRequest) {
console.log('A request was made:', interceptedRequest.url());
}
page.on('request', logRequest);
// Sometime later...
page.removeListener('request', logRequest);
当页面关闭的时候触发。
当页面上的Javascript脚本调用一些类似于 console.log
或 console.dir
的 console API时触发,除此之外,如果页面上的脚本抛出错误或者警告同样也会触发。
The arguments passed into console.log
appear as arguments on the event handler.
下面是一个监听 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'}));
当页面上弹出 JavaScript对话框的时候触发,例如 alert
, prompt
, confirm
或者 beforeunload
。Puppeteer能够通过 Dialog的 accept 或者 dismiss 方法来对此事件作出回应。
当 JavaScript 的DOMContentLoaded
事件被触发时触发。
当页面崩溃时触发。
NOTE
error
事件在 Node中具有特殊的含义,具体细节参见 error events 。
当一个 frame 被附加到主页面上时触发。
当一个 frame 从主页面上分离(删除)时触发。
当一个 frame 的url被定向到一个新的url上时触发。
当 JavaScript 的load
事件被触发时触发。
title
console.timeStamp
的 titlemetrics
当页面上的JavaScript脚本调用 cnosole.timeStamp
时触发。metrics的可选列表可见 page.metrics
。
当页面上出现未捕获的异常时触发。
当页面上发起一个请求的时候触发。request对象是只读的,如果你想拦截并改造请求,参照 page.setRequestInterception
。
当请求失败时触发,例如,请求超时。
当请求完成时触发。
当页面收到请求的响应时触发。
当页面上产生一个新的 WebWorker线程时触发。
当页面上有 WebWorker线程结束时触发。
selector
selector
此方法在页面上使用了 document.querySelectorAll
。如果选择器没有匹配到元素,将会返回 []
。
page.mainFrame().$$(selector)的快捷方法。
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数pageFunction
返回的结果。此方法在页面上使用了 Array.from(document.querySelectorAll(selector))
,并将获取到的结果当做 pageFunction
的第一个参数传递进去。
如果 pageFunction
返回的结果是一个 Promise,则page.$$eval
将会等到前者 resolve回一个结果后,才会继续返回自己的值。
例子:
const divsCounts = await page.$$eval('div', divs => divs.length);
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数pageFunction
返回的结果。此方法在页面上使用了 document.querySelector
,并将获取到的结果当做 pageFunction
的第一个参数传递进去。如果选择器没有匹配到元素,则将抛出一个错误。
如果 pageFunction
返回的结果是一个 Promise,则page.$eval
将会等到前者 resolve回一个结果后,才会继续返回自己的值。
例子:
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
- returns:
根据给定的 Xpath表达式获取 DOM元素。
page.mainFrame().$x(expression)的快捷方法。
options
url
path
path
是相对路径, 则其是相对于 current working directory。content
type
向页面中增加指定 url或者 脚本内容的 script
标签。
page.mainFrame().addScriptTag(options)的快捷方法。
options
url
path
path
是相对路径, 则其是相对于 current working directory。content
向页面中添加一个 带有指定 url的标签,或者一个带有内容的
标签。
page.mainFrame().addStyleTag(options)的快捷方法。
credentials
Brings page to front (activates tab).
获取页面所属的 browser实例。
selector
options
button
left
, right
, or middle
, 默认是 left
(即使用左键、右键还是中键进行点击操作)clickCount
delay
mousedown
和 mouseup
事件之间的时间间隔. 默认为 0.此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.mouse方法点击匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
需要注意的是,如果所点击的元素会触发页面跳转,并且还调用了page.waitForNavigation()
方法,那么你可能不会得到期望的结果,正确的做法如下:
const [response] = await Promise.all([
page.waitForNavigation(waitOptions),
page.click(selector, clickOptions),
]);
page.mainFrame().click(selector[, options])的快捷方法。
options
runBeforeUnload
false
. 是否在关闭前调用 page.close()
方法默认不调用 beforeunload句柄。
(这个方法的意思是,如果页面上注册了 onbeforeunload方法,那么在关闭页面时,将会调用这个onbeforeunload方法,如果 puppeteer.launch
的 headless
参数设置为 true
,那么你将看到页面在关闭时,弹出了一个询问是否离开页面的对话框)。
NOTE 如果
runBeforeUnload
为 true, 页面在关闭时可能会弹出beforeunload
对话框,
并且这个对话框可以被 page的 ‘dialog’事件捕获到.
获取页面上包括 doctype在内的所有 HTML内容。
...urls
<…string>name
value
domain
path
expires
httpOnly
secure
session
sameSite
"Strict"
or "Lax"
.如果没有提供 URLs,则此方法将会返回当前页面URL的 cookies。
如果指定了URLs,则只有这些指定URLS上的cookies才会被返回。
...cookies
<…Object> name
url
domain
path
secure
options
viewport
width
height
deviceScaleFactor
1
.isMobile
meta viewport
tag is taken into account. Defaults to false
.hasTouch
false
isLandscape
false
.userAgent
Emulates given device metrics and user agent. This method is a shortcut for calling two methods:
- page.setUserAgent(userAgent)
- page.setViewport(viewport)
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');
// other actions...
await browser.close();
});
所有能够模拟的设备可以在DeviceDescriptors.js中找到。
mediaType
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
如果传递给 page.evaluate
的 pageFunction
函数返回一个 Promise,则page.evaluate
将会等待得到resolve后,才会返回它自己的值。
如果传递给 page.evaluate
的 pageFunction
函数返回一个 non-Serializable的值,则page.evaluate
将会返回 undefined
。
给 pageFunction
传递参数:
const result = await page.evaluate(x => {
return Promise.resolve(8 * x);
}, 7);
console.log(result); // prints "56"
可以传递一个字符串作为 pageFunction
:
console.log(await page.evaluate('1 + 2')); // prints "3"
const x = 10;
console.log(await page.evaluate(`1 + ${x}`)); // prints "11"
可以传递一个ElementHandle 作为 pageFunction
参数:
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose();
page.mainFrame().evaluate(pageFunction, …args)的快捷方法。
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
as in-page object (JSHandle)。page.evaluate
和 page.evaluateHandle
之间唯一的差别是,page.evaluateHandle
返回的结果是 in-page object (JSHandle)。
(可能指的是此方法只返回页面元素的句柄,即此方法可以看作一个元素选择器)
如果传入 page.evaluateHandle
的函数 返回的值是一个 Promise,则page.evaluateHandle
将会等待这个 Promise到达resolve时才会返回自己的值。
可以传递一个 字符串作为 pageFunction
:
const aHandle = await page.evaluateHandle('document'); // Handle for the 'document'
JSHandle instances也可以作为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)的快捷方法。
pageFunction
...args
<…Serializable> 传递给 pageFunction
的参数pageFunction
可能会在以下情况下呗调用:
Adds a function which would be invoked in one of the following scenarios:
- 页面重定向
- 子frame重定向或者增加新的子frame。在这种情况下,pageFunction
将会在子frame中执行。
pageFunction
会在文档(document)加载完毕后以及页面上JS脚本执行之前被调用,This is useful to amend the JavaScript environment, e.g. to seed Math.random
.
下面是一个在页面加载之前重写 navigator.languages属性的例子:
// preload.js
// overwrite the `languages` property to use a custom getter
Object.defineProperty(navigator, "languages", {
get: function() {
return ["en-US", "en", "bn"];
}
});
// In your puppeteer script, assuming the preload.js file is in same folder of our script
const preloadFile = fs.readFileSync('./preload.js', 'utf8');
await page.evaluateOnNewDocument(preloadFile);
name
puppeteerFunction
此方法将会在 window
对象中添加一个 名为 name
的函数。
当被调用时,其将会在 node.js
中执行 puppeteerFunction
,并且返回一个 Promise,此Promise会 resolve
回 puppeteerFunction
的返回结果。
如果puppeteerFunction
返回的结果是一个 Promise,则此方法将会等到前者 Promise resolve之后,才会返回自己的 Promise。
NOTE Functions installed via
page.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 () => {
// use window.md5 to compute hashes
const myString = 'PUPPETEER';
const myHash = await window.md5(myString);
console.log(`md5 of ${myString} is ${myHash}`);
});
await browser.close();
});
下面是一个在页面中添加 window.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 () => {
// use window.readfile to read contents of a file
const content = await window.readfile('/etc/hosts');
console.log(content);
});
await browser.close();
});
selector
此方法将 focus给定 selector匹配到的元素。
如果根据给定的 selector没有匹配到任何元素,将会抛出异常。
page.mainFrame().focus(selector)的快捷方法。
options
timeout
0
则表示禁用此选项。 此值也可以被 page.setDefaultNavigationTimeout(timeout) 方法修改。waitUntil
load
。如果给定的值是一个事件名称组成的数组,那么只有当数组中的所有事件全部被触发后才会认为 navigation成功,可选的事件列表如下:load
- consider navigation to be finished when the load
event is fired.domcontentloaded
- consider navigation to be finished when the DOMContentLoaded
event is fired.networkidle0
- 如果在 500ms
内发起的http请求数为0,则认为导航结束。networkidle2
- 如果在 500ms
内发起的http请求数为不超过 2条,则认为导航结束。options
timeout
0
则表示禁用此选项。 此值也可以被 page.setDefaultNavigationTimeout(timeout) 方法修改。waitUntil
load
。如果给定的值是一个事件组成的数组,那么只有当数组中的所有事件全部被触发后才会认为 navigation成功,可选的事件列表如下:load
- consider navigation to be finished when the load
event is fired.domcontentloaded
- consider navigation to be finished when the DOMContentLoaded
event is fired.networkidle0
- 如果在 500ms
内发起的http请求数为0,则认为导航结束。networkidle2
- 如果在 500ms
内发起的http请求数为不超过 2条,则认为导航结束。url
https://
。options
timeout
0
则表示禁用此选项。 此值也可以被 page.setDefaultNavigationTimeout(timeout) 方法修改。waitUntil
load
。如果给定的值是一个事件组成的数组,那么只有当数组中的所有事件全部被触发后才会认为 navigation成功,可选的事件列表如下:load
- 当 load
事件触发时,则认为 navigation导航结束。domcontentloaded
- 当 DOMContentLoaded
事件触发时,则认为 navigation导航结束。networkidle0
- 如果在 500ms
内发起的http请求数为0,则认为导航结束。networkidle2
- 如果在 500ms
内发起的http请求数为不超过 2条,则认为导航结束。selector
此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.mouse方法 hover匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
page.mainFrame().hover(selector)的快捷方法。
页面是否被关闭。
navigations过程中,Page一直存在一个 main frame。
Timestamp
Documents
Frames
JSEventListeners
Nodes
LayoutCount
RecalcStyleCount
LayoutDuration
RecalcStyleDuration
ScriptDuration
TaskDuration
JSHeapUsedSize
JSHeapTotalSize
NOTE All timestamps are in monotonic time: monotonically increasing time in seconds since an arbitrary point in the past.
options
path
path
是一个相对路径,则它是相对于current working directory. 如果没有提供此值项值, 将不会保存PDF。scale
1
.displayHeaderFooter
false
.headerTemplate
date
formatted print datetitle
文档标题url
文档urlpageNumber
当前页码totalPages
总页数footerTemplate
headerTemplate
.printBackground
false
.landscape
false
.pageRanges
format
width
or height
options. Defaults to ‘Letter’.width
height
margin
top
right
bottom
left
NOTE 生成pdf的操作只有Chrome浏览器才有效。
page.pdf()
以 print
的 css media生成pdf,如果想生成一个 screen
media的PDF,请在使用 page.pdf()
之前调用page.emulateMedia(‘screen’)方法。
// Generates a PDF with 'screen' media type.
await page.emulateMedia('screen');
await page.pdf({path: 'page.pdf'});
width
, height
, 和 margin
属性接受的值应该明确带上相应的单位,否则将会被默认为 px
单位。
一些例子:
- page.pdf({width: 100})
- 宽度为100px
- page.pdf({width: '100px'})
- 宽度为100px
- page.pdf({width: '10cm'})
- 宽度为 10厘米
所有可选的单位:
- px
- pixel
- in
- inch
- cm
- centimeter
- mm
- millimeter
format
属性的可选值:
- Letter
: 8.5in x 11in
- Legal
: 8.5in x 14in
- Tabloid
: 11in x 17in
- Ledger
: 17in x 11in
- A0
: 33.1in x 46.8in
- A1
: 23.4in x 33.1in
- A2
: 16.5in x 23.4in
- A3
: 11.7in x 16.5in
- A4
: 8.27in x 11.7in
- A5
: 5.83in x 8.27in
- A6
: 4.13in x 5.83in
NOTE
headerTemplate
以及footerTemplate
的标签有以下限制:
1. Script tags inside templates are not evaluated.
2. Page styles are not visible inside templates.
prototypeHandle
此方法迭代给定的JavaScript堆的prototype,返回prototype上的所有对象
// Create a Map object
await page.evaluate(() => window.map = new Map());
// Get a handle to the Map object prototype
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// Query all map instances into an array
const mapInstances = await page.queryObjects(mapPrototype);
// Count amount of map objects in heap
const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose();
await mapPrototype.dispose();
page.mainFrame().executionContext().queryObjects(prototypeHandle)的快捷方法。
options
timeout
0
表示禁用此属性。也可以使用page.setDefaultNavigationTimeout(timeout) 方法来改变此值。waitUntil
load
。如果给定的值是一个事件组成的数组,那么只有当数组中的所有事件全部被触发后才会认为 navigation成功,可选的事件列表如下:load
- consider navigation to be finished when the load
event is fired.domcontentloaded
- consider navigation to be finished when the DOMContentLoaded
event is fired.networkidle0
- 如果在 500ms
内发起的http请求数为0,则认为导航结束。networkidle2
- 如果在 500ms
内发起的http请求数不超过 2条,则认为导航结束。options
path
path
是相对路径,则其应当是相对于 current working directory.。如果没有提供此属性值,则将不会保存截图。type
jpeg
和 png
。默认为 ‘png’。quality
png
图片。fullPage
true
的话,则将截取包括可滚动区域在内的所有页面。默认为 false
.clip
x
y
width
height
omitBackground
false
.encoding
base64
或者 binary
。默认为 binary
.NOTE 在OS X系统上,截图操作最少需要 1/6秒的时间。参见 https://crbug.com/741689 。
selector
...values
<…string> 选择的值。如果
标签具有 multiple
属性, 所有的指定值都是有效值, 否则只会考虑第一个值。当所有提供的 values
值的选项(option)全被选中后会触发 change
以及 input
事件。
如果根据所指定的选择器selector
没有匹配到一个 元素,将会抛出错误。
(这个方法就是用于控制 select的选择)
page.select('select#colors', 'blue'); // 单选
page.select('select#colors', 'red', 'green', 'blue'); // 多选
Shortcut for page.mainFrame().select()
enabled
控制是否绕过页面的Content-Security-Policy(内容安全策略)。
NOTE 绕过CSP的操作应该发生在CSP的初始化阶段而不是执行阶段。也就是说,在 navigating向目标主机之前就应该调用
page.setBypassCSP
方法。
enabled
enabled
state of the cache.是否使用资源缓存,默认启用缓存。
Toggles ignoring cache for each request based on the enabled state. By default, caching is enabled.
html
...cookies
<…Object> name
value
url
domain
path
expires
httpOnly
secure
sameSite
"Strict"
or "Lax"
.timeout
此方法可以改变以下方法默认 30s的超时时间。
- page.goto(url, options)
- page.goBack(options)
- page.goForward(options)
- page.reload(options)
- page.waitForNavigation(options)
headers
这些额外的 header头将会被页面发出的所有请求链接携带上。
NOTE page.setExtraHTTPHeaders 无法保证请求header的顺序。
enabled
NOTE 改变此值无法影响到那些已经执行的 JS代码。不过会在下次导航 navigation中完全起作用。
enabled
true
时, 将会启用页面的离线模式。value
启用请求拦截将会使request.abort
, request.continue
以及 request.respond
方法可用。这提供了能够修改页面请求的能力。
下面的例子展示如何拦截请求并断掉(abort)掉所有的图片请求:
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();
});
NOTE 启用请求拦截将会禁用页面缓存(也就是请求不再使用页面缓存)。
userAgent
viewport
width
height
deviceScaleFactor
1
.isMobile
meta viewport
标签。 默认为 false
.hasTouch
false
isLandscape
false
.NOTE 在某些的情况下,设置 viewportin 将会导致页面 reload 以便让
isMobile
或者hasTouch
属性生效。
如果一个浏览器中开启了多个页面,则每个页面都有其自己的 viewport大小。
selector
此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.touchscreen方法tap匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
page.mainFrame().tap(selector)的快捷方法。
page.mainFrame().title()的快捷方法。
selector
text
options
delay
Sends a keydown
, keypress
/input
, and keyup
event for each character in the text.
为了按下一些特殊按键,例如 Control
或 ArrowDown
,请使用keyboard.press
。
page.type('#mytextarea', 'Hello'); // Types instantly
page.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
page.mainFrame().type(selector, text[, options])的快捷方法。
page.mainFrame().url()的快捷方法。
width
height
deviceScaleFactor
1
.isMobile
meta viewport
标签。默认为 false
.hasTouch
false
isLandscape
false
.selectorOrFunctionOrTimeout
options
...args
<…Serializable|JSHandle> pageFunction
的参数。根据第一个参数的不同,此方法可实现的场景如下:
- 如果 selectorOrFunctionOrTimeout
是一个 string
, 那么它如果是以 ‘//’开头, 就是xpath,否则就是 selector,此方法是
page.waitForSelector 或者 page.waitForXPath方法的快捷方法。
- 如果 selectorOrFunctionOrTimeout
是一个 function
, then the first argument is treated as a predicate to wait for and the method is a shortcut for page.waitForFunction().
- 如果 selectorOrFunctionOrTimeout
是一个 number
, 那么它就会被当做是等待时间(ms),超过等到时间后将会resolve。
- 如果不是以上三种情况中的任何一个,那么将会抛出错误。
[page.mainFrame().waitFor(selectorOrFunctionOrTimeout[, options[, …args]])](#framewaitforselectororfunctionortimeout-options-args)的快捷方法。
pageFunction
options
polling
pageFunction
is executed, defaults to raf
. If polling
is a number, then it is treated as an interval in milliseconds at which the function would be executed. 如果 polling
取值类型是 string, 那么只能是以下两个之一:raf
- 在 requestAnimationFrame
的回调函数中不断地执行 pageFunction
。 这是最紧凑的轮询模式,适合于观察样式的变化。mutation
- 当任意 DOM发生变化的时候执行 pageFunction
timeout
pageFunction
函数执行的最大等待时间(ms)。。默认是 30000
(30 秒)。如果取值为 0
,则表示禁用此选项。...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数。pageFunction
函数返回 truthy value (true或者可以转化为 true的值)时,将会resolve。 It resolves to a JSHandle of the truthy value.下面是一个使用此方法来监控 viewport 尺寸改变的例子:
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();
});
[page.mainFrame().waitForFunction(pageFunction[, options[, …args]])](#framewaitforfunctionpagefunction-options-args)的快捷方法。
options
timeout
0
则表示禁用此选项。也可以使用 page.setDefaultNavigationTimeout(timeout) 方法来改变默认值。waitUntil
load
. 如果给定的值是一个事件名称组成的数组,那么只有当数组中的所有事件全部被触发后才会认为 navigation成功,可选的事件列表如下:load
- 当 load
事件触发时,则认为 navigation导航结束。domcontentloaded
- 当 DOMContentLoaded
事件触发时,则认为 navigation导航结束。networkidle0
- 如果在 500ms
内发起的http请求数为0,则认为导航结束。networkidle2
- 如果在 500ms
内发起的http请求数为不超过 2条,则认为导航结束。适应于当页面重定向到一个新的url或者reload的场景,例如,当执行了一段可能间接导致页面跳转的代码:
const navigationPromise = page.waitForNavigation();
await page.click('a.my-link'); // 点击此链接将会间接导致页面跳转
await navigationPromise; // 当页面跳转完毕后,将会 resolve
NOTE 使用 History API 方法改变 URL也会被当成是一个 navigation。
selector
options
visible
display: none
或者 visibility: hidden
CSS 属性。默认是 false
。hidden
display: none
或者 visibility: hidden
CSS 属性。默认是 false
.timeout
30000
(30 秒)。取值为的 0
则表示禁用此参数。等到 selector
选择器选择的元素出现在页面中,如果在调用此方法的同时选择器选取的元素就已经存在于页面中了,
则此方法将会立即返回结果,如果超过了最大等待时间 timeout
之后,选择器还没有匹配到元素,则将会抛出错误。
此方法即便是在页面跳转(across navigations)的时候依旧有效:
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])的快捷方法。
xpath
options
visible
display: none
或者 visibility: hidden
CSS 属性。默认是 false
。hidden
display: none
或者 visibility: hidden
CSS 属性。默认是 false
.timeout
30000
(30 秒)。取值为的 0
则表示禁用此参数。等到匹配 xpath的元素出现在页面中,如果在调用此方法的同时匹配 xpath的元素就已经存在于页面中了,
则此方法将会立即返回结果,如果超过了最大等待时间 timeout
之后,还没有出现匹配 xpath的元素,则将会抛出错误。
此方法即便是在页面跳转(across navigations)的时候依旧有效:
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])的快捷方法。
NOTE 不包括 ServiceWorkers。
The Worker class represents a WebWorker.
workercreated
和 workerdestroyed
事件将会被当做 worker
的生命周期,在 page实例中被触发。
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());
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
函数的返回值。如果pageFunction
返回的值是一个 Promise,则 worker.evaluate
方法将会等到前者 resolve
后,才会返回它自己的值。
如果pageFunction
返回的值是一个 non-Serializable 的值, 则 worker.evaluate
将会 resolves undefined
。
(await worker.executionContext()).evaluate(pageFunction, …args)的快捷方法。
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
函数的参数。pageFunction
as in-page object (JSHandle)worker.evaluate
和 worker.evaluateHandle
之间唯一的区别在于,worker.evaluateHandle
返回一个 in-page object (JSHandle)
如果pageFunction
返回的值是一个 Promise,则 worker.evaluateHandle
方法将会等到前者 resolve
后,才会返回它自己的值。
(await worker.executionContext()).evaluateHandle(pageFunction, …args)的快捷方法。
Keyboard提供了一些用于操纵虚拟键盘的api。高级api是keyboard.type
,此api可自动根据场景整合keydown, keypress/input, 以及 keyup事件。
为了得到更细致的控制,你也可以使用keyboard.down
, keyboard.up
, and 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');
NOTE 在MacOS系统上,一些键盘快捷键,例如 全选 的快捷键
⌘ A
将不起作用。更多参见 #1313
key
ArrowLeft
. 参见 USKeyboardLayout 获取按键名称列表。options
text
触发 keydown
事件。
如果 key
值是一个单个字母,并且没有除了 Shift
之外的修饰按键被按下,那么将会继续触发 keypress
/input
事件。可以指定 ‘text’选项以强制生成输入事件。
如果 key
值是一个修饰按键,例如 Shift
, Meta
, Control
, 或者 Alt
,随后按下的按键将会与前者组合形成组合键,如果想要释放修饰按键,可以使用 keyboard.up
方法。
After the key is pressed once, subsequent calls to keyboard.down
will have repeat set to true. To release the key, use keyboard.up
.
NOTE 修饰键将会影响
keyboard.down
的效果。如果你按住Shift
键,然后再按其他的字母键,则你将输入一个大写的字母。
key
ArrowLeft
. 更多按键名称列表参见 USKeyboardLayout 。options
text
text
进行按键操作。delay
keydown
和 keyup
之间的时间间隔(ms). 默认是 0.如果 key
值是一个单个字母,并且没有除了 Shift
之外的修饰按键被按下,那么将会继续触发 keypress
/input
事件。可以指定 ‘text’选项以强制生成输入事件。
NOTE 修饰键将会影响
keyboard.press
的效果。如果你按住Shift
键,然后再按其他的字母键,则你将输入一个大写的字母。
keyboard.down
和 keyboard.up
的快捷方法。
char
触发 keypress
和 input
事件,不会触发 keydown
或者 keyup
事件。
page.keyboard.sendCharacter('嗨');1
NOTE 修饰键将会影响
keyboard.sendCharacter
的效果。如果你按住Shift
键,然后再按其他的字母键,则你将输入一个大写的字母。
text
options
delay
输入文本的时候,每个字符都会触发 keydown
, keypress
/input
, 以及 keyup
事件。
如果想要输按下特殊字符,例如Control
以及 ArrowDown
,参见keyboard.press
。
page.keyboard.type('Hello'); // 快速输入
page.keyboard.type('World', {delay: 100}); // 模拟真实输入
NOTE 修饰键不会影响
keyboard.type
的效果。也就是说,调用此方法时,就算你已经按住了Shift
键,也不会将你想要输入的文本全都强制变成大写的。
key
ArrowLeft
. 更多按键名称列表参见 USKeyboardLayout。触发 keyup
事件。
x
y
options
button
left
, right
, 或者 middle
, 默认是 left
。(意思是用鼠标的哪个按键进行点击操作,左键、右键或者中键)clickCount
delay
mousedown
和 mouseup
之间的时间间隔(ms).默认是 0.mouse.move
, mouse.down
以及 mouse.up
的联合方法。
options
button
left
, right
, 或者 middle
, 默认是 left
。(意思是用鼠标的哪个按键进行点击操作,左键、右键或者中键)clickCount
触发 mousedown
事件。
x
y
options
steps
mousemove
events.触发 mousemove
事件。
options
button
left
, right
, 或者 middle
, 默认是 left
。clickCount
触发 mouseup
事件。
x
y
Dispatches a touchstart
and touchend
event.
你可以使用 tracing.start
以及 tracing.stop
来创建一个跟踪文件,此跟踪文件可以被 Chrome DevTools 或者 timeline viewer打开。
await page.tracing.start({path: 'trace.json'});
await page.goto('https://www.google.com');
await page.tracing.stop();
options
path
screenshots
categories
每个浏览器一次只能执行一个跟踪任务。
Dialog objects are dispatched by page via the ‘dialog’ event.
下面是一个 使用Dialog
class的例子:
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'));
});
promptText
alert
, beforeunload
, confirm
or prompt
.ConsoleMessage objects are dispatched by page via the ‘console’ event.
允许以下值: 'log'
, 'debug'
, 'info'
, 'error'
, 'warning'
, 'dir'
, 'dirxml'
, 'table'
, 'trace'
, 'clear'
, 'startGroup'
, 'startGroupCollapsed'
, 'endGroup'
, 'assert'
, 'profile'
, 'profileEnd'
, 'count'
, 'timeEnd'
。
无论在哪个时间点,都能够通过page.mainFrame() 和 frame.childFrames()方法来获取的页面当前的 frame tree。
Frame对象的生命周期,由三个事件组成:
- ‘frameattached’ - 当frame attach到page上时触发。一个 Frame只能 attach到页面上一次。
- ‘framenavigated’ - 当Frame重定向到一个新的 URL时触发.
- ‘framedetached’ - 当Frame从页面上 detach时触发。一个 Frame只能从页面上 detach一次。
An example of dumping frame tree:
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 + ' ');
}
});
selector
selector
此方法使用了 document.querySelectorAll
,如果没有匹配到任何元素,则resolve回 []
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数pageFunction
此方法使用了 Array.from(document.querySelectorAll(selector))
,并将其返回的结果作为 pageFunction
函数的第一个参数传递进去。
如果 pageFunction
返回的结果是一个 Promise,则 frame.$$eval
将会等到前者成功resolve,然后再返回自己的值。
Examples:
const divsCounts = await frame.$$eval('div', divs => divs.length);
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数pageFunction
此方法使用了 document.querySelector
,并将其返回的结果作为 pageFunction
函数的第一个参数传递进去。如果没有匹配到任何元素,则将抛出错误。
如果 pageFunction
返回的结果是一个 Promise,则 frame.$eval
将会等到前者成功resolve,然后再返回自己的值。
例子:
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);
expression
此方法用于执行给定的 XPath 表达式。
options
url
path
path
是相对路径, 则其是相对于 current working directory。content
type
向frame中增加指定 url或者 脚本内容的 script
标签。
options
url
path
path
是相对路径, 则其是相对于 current working directory。content
向页面中添加一个 带有指定 url的标签,或者一个带有内容的
标签。
selector
options
button
left
, right
, or middle
, 默认是 left
(即使用左键、右键还是中键进行点击操作)clickCount
delay
mousedown
和 mouseup
事件之间的时间间隔. 默认为 0.此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.mouse方法点击匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
需要注意的是,如果所点击的元素会触发页面跳转,并且还调用了page.waitForNavigation()
方法,那么你可能不会得到期望的结果,正确的做法如下:
const [response] = await Promise.all([
page.waitForNavigation(waitOptions),
frame.click(selector, clickOptions),
]);
获取frame包括doctype在内的完整HTML内容
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
如果传递给 frame.evaluate
的 pageFunction
函数返回一个 Promise,则frame.evaluate
将会等待得到resolve后,才会返回它自己的值。
如果传递给 frame.evaluate
的 pageFunction
函数返回一个 non-Serializable的值,则page.evaluate
将会返回 undefined
。
const result = await frame.evaluate(() => {
return Promise.resolve(8 * 7);
});
console.log(result); // prints "56"
可以传递一个字符串作为 pageFunction
:
console.log(await frame.evaluate('1 + 2')); // prints "3"
可以传递一个ElementHandle 作为 pageFunction
参数:
const bodyHandle = await frame.$('body');
const html = await frame.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose();
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
as in-page object (JSHandle)frame.evaluate
和 paframege.evaluateHandle
之间唯一的差别是,frame.evaluateHandle
返回的结果是 in-page object (JSHandle)。
(可能指的是此方法只返回页面元素的句柄,即此方法可以看作一个元素选择器)
如果传入 frame.evaluateHandle
的函数 返回的值是一个 Promise,则frame.evaluateHandle
将会等待这个 Promise到达resolve时才会返回自己的值。
const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window));
aWindowHandle; // window对象的handle.
可以传递一个 字符串作为 pageFunction
:
const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'.
JSHandle instances也可以作为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();
selector
此方法将 focus给定 selector匹配到的元素。
如果根据给定的 selector没有匹配到任何元素,将会抛出异常。
selector
此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.mouse方法 hover匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
如果 frame已经detached了,则返回 true
, 否则返回 false
返回 frame的name属性值。
如果name属性不存在或者为空字符串,则返回 id属性的值,如果 id属性也不存在或者为空字符串,则返回空字符串。
NOTE 此方法的返回值只会在frame被创建后计算一次,如果稍后frame的相关属性(name或者id)发生变化,此方法的返回值也不会改变。
selector
...values
<…string> 选择的值。如果
标签具有 multiple
属性, 所有的指定值都是有效值, 否则只会考虑第一个值。当所有提供的 values
值的选项(option)全被选中后会触发 change
以及 input
事件。
如果根据所指定的选择器selector
没有匹配到一个 元素,将会抛出错误。
(这个方法就是用于控制 select的选择)
frame.select('select#colors', 'blue'); // 单选
frame.select('select#colors', 'red', 'green', 'blue'); // 多选
html
selector
此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.touchscreen方法tap匹配到的元素的中心位置。
如果没有匹配到元素,则将抛出一个错误。
selector
text
options
delay
Sends a keydown
, keypress
/input
, and keyup
event for each character in the text.
为了按下一些特殊按键,例如 Control
或 ArrowDown
,请使用keyboard.press
。
frame.type('#mytextarea', 'Hello'); // 快速输入
frame.type('#mytextarea', 'World', {delay: 100}); // 减缓输入速度以模拟真实输入
返回 frame的url
selectorOrFunctionOrTimeout
options
...args
<…Serializable|JSHandle> pageFunction
的参数。根据第一个参数的不同,此方法可实现的场景如下:
- 如果 selectorOrFunctionOrTimeout
是一个 string
, 那么它如果是以 ‘//’开头, 就是xpath,否则就是 selector,此方法是
frame.waitForSelector 或者 frame.waitForXPath方法的快捷方法。
- 如果 selectorOrFunctionOrTimeout
是一个 function
, then the first argument is treated as a predicate to wait for and the method is a shortcut for frame.waitForFunction().
- 如果 selectorOrFunctionOrTimeout
是一个 number
, 那么它就会被当做是等待时间(ms),超过等到时间后将会resolve。
- 如果不是以上三种情况中的任何一个,那么将会抛出错误。
pageFunction
options
polling
pageFunction
is executed, defaults to raf
. If polling
is a number, then it is treated as an interval in milliseconds at which the function would be executed. 如果 polling
取值类型是 string, 那么只能是以下两个之一:raf
- 在 requestAnimationFrame
的回调函数中不断地执行 pageFunction
。 这是最紧凑的轮询模式,适合于观察样式的变化。mutation
- 当任意 DOM发生变化的时候执行 timeout
30000
(30 秒)。如果取值为 0
,则表示禁用此选项。...args
<…Serializable|JSHandle> 传递给 pageFunction
的额外参数。pageFunction
returns a truthy value. It resolves to a JSHandle of the truthy value.下面是一个使用此方法来监控 viewport 尺寸改变的例子:
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();
});
selector
options
visible
display: none
或者 visibility: hidden
CSS 属性。默认是 false
。hidden
display: none
或者 visibility: hidden
CSS 属性。默认是 false
.timeout
30000
(30 秒)。取值为的 0
则表示禁用此参数。等到 selector
选择器选择的元素出现在页面中,如果在调用此方法的同时选择器选取的元素就已经存在于页面中了,
则此方法将会立即返回结果,如果超过了最大等待时间 timeout
之后,选择器还没有匹配到元素,则将会抛出错误。
此方法即便是在页面跳转(across navigations)的时候依旧有效:
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();
});
xpath
options
visible
display: none
或者 visibility: hidden
CSS 属性。默认是 false
。hidden
display: none
或者 visibility: hidden
CSS 属性。默认是 false
.timeout
30000
(30 秒)。取值为的 0
则表示禁用此参数。等到匹配 xpath的元素出现在页面中,如果在调用此方法的同时匹配 xpath的元素就已经存在于页面中了,
则此方法将会立即返回结果,如果超过了最大等待时间 timeout
之后,还没有出现匹配 xpath的元素,则将会抛出错误。
此方法即便是在页面跳转(across navigations)的时候依旧有效:
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();
});
The class represents a context for JavaScript execution. Examples of JavaScript contexts are:
- 每个 frame 都有一个独立的JS执行上下文
- 所有类型的 workers 都有它们自己的上下文
pageFunction
executionContext
中执行的函数...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
函数的结果。如果pageFunction
函数的返回值是一个 Promise,则executionContext.evaluate
将会等到前者resolve后才会返回它自己的值。
const executionContext = await page.mainFrame().executionContext();
const result = await executionContext.evaluate(() => Promise.resolve(8 * 7));
console.log(result); // prints "56"
字符串也可以被当做pageFunction
:
console.log(await executionContext.evaluate('1 + 2')); // prints "3"
JSHandle instances 可以被当做 ...args
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); // prints '3'.
pageFunction
executionContext
中执行的函数...args
<…Serializable|JSHandle> 传递给 pageFunction
函数的参数。pageFunction
as in-page object (JSHandle)executionContext.evaluate
和 executionContext.evaluateHandle
之间唯一的区别在于,worker.evaluateHandle
返回一个 in-page object (JSHandle)
如果pageFunction
返回的值是一个 Promise,则 executionContext.evaluateHandle
方法将会等到前者 resolve
后,才会返回它自己的值。
const context = await page.mainFrame().executionContext();
const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
aHandle; // Handle for the global object.
字符串也可以被当做pageFunction
:
const aHandle = await context.evaluateHandle('1 + 2'); // Handle for the '3' object.
JSHandle instances 可以被当做 ...args
const aHandle = await context.evaluateHandle(() => document.body);
const resultHandle = await context.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue()); // prints body's innerHTML
await aHandle.dispose();
await resultHandle.dispose();
prototypeHandle
此方法迭代(iterates)遍历 JavaScript堆栈,获取给定 prototype下所有 object组成的数组。
// Create a Map object
await page.evaluate(() => window.map = new Map());
// Get a handle to the Map object prototype
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// Query all map instances into an array
const mapInstances = await page.queryObjects(mapPrototype);
// Count amount of map objects in heap
const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose();
await mapPrototype.dispose();
JSHandle represents an in-page JavaScript object. JSHandles 可以通过 page.evaluateHandle 方法来创建。
const windowHandle = await page.evaluateHandle(() => window);
// ...
JSHandle能够防止被引用的 JavaScript object 被垃圾回收机制给回收掉,除非 the handle被主动 disposed。JSHandles能够在源frame重定向或者父级上下文被销毁的时候,自动释放(auto-disposed)。
JSHandle instances 可以作为 page.$eval()
, page.evaluate()
以及 page.evaluateHandle
方法的参数。
此方法用于断开element handle的引用
返回 handle所在的执行上下文。
此方法返回一个由属性名称作为key和 JSHandle instances作为value组成的 map对象
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();
propertyName
从引用的object中获取给定 propertyName
对应的 property。
返回 object的 json。如果 object具有toJSON
函数方法,也不会调用此函数方法.
Returns a JSON representation of the object. If the object has a
NOTE 如果引用的object无法字符串化,则此方法将返回空 JSON对象。如果引用的object存在循环引用,则将抛出错误。
NOTE Class ElementHandle extends JSHandle.
ElementHandle represents an in-page DOM element. ElementHandles 可以通过 the 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();
// ...
});
ElementHandle 能够防止被引用的 DOM element 被垃圾回收机制给回收掉,除非 the handle被主动 disposed。ElementHandles 能够在源frame重定向的时候,自动释放(auto-disposed)。
ElementHandle instances 可以作为 page.$eval()
, page.evaluate()
以及 page.evaluate
方法的参数。
selector
selector
此方法将在页面上使用element.querySelectorAll
,如果没有匹配到任何元素,则将resolve 回[]
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
函数的返回值。此方法将在element上使用element.querySelectorAll
,并且将结果作为pageFunction
的第一个参数传入,如果没有匹配到任何元素,则抛出错误。
如果 pageFunction
返回的值是一个 Promise,则 elementHandle.$$eval
将等到前者 resolve回结果后,才返回它自己的值。
例子:
<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!']);
selector
pageFunction
...args
<…Serializable|JSHandle> 传递给 pageFunction
的参数pageFunction
函数的返回值。此方法将在 element上使用document.querySelector
,并且将结果作为pageFunction
的第一个参数传入,如果没有匹配到任何元素,则抛出错误。
如果 pageFunction
返回的值是一个 Promise,则 elementHandle.$eval
将等到前者 resolve回结果后,才返回它自己的值。
Examples:
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');
expression
The method evaluates the XPath expression relative to the elementHandle. If there are no such elements, the method will resolve to an empty array.
options
button
left
, right
, 或者 middle
, 默认是 left
。(意思是用鼠标的哪个按键进行点击操作,左键、右键或者中键)clickCount
delay
mousedown
和 mouseup
之间的时间间隔(ms).默认是 0.此方法将会根据给定的选择器匹配到元素,如果所匹配到的元素不在视界内,将会将其滚动到视界内,然后使用 page.mouse方法点击匹配到的元素的中心位置。
如果element 已经从DOM上 detach掉了,则将抛出一个错误。
此方法断开 element handle的引用
调用 element的focus 方法。
此方法返回一个由属性名称作为key和 JSHandle instances作为value组成的 map对象
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; // holds elementHandles to all children of document.body
key
ArrowLeft
. 更多按键名称列表参见 USKeyboardLayout。options
text
delay
keydown
和 keyup
之间的时间间隔(ms). 默认是 0.聚焦在 element上,然后使用 keyboard.down
以及 keyboard.up
方法。
如果 key
值是一个单个字母,并且没有除了 Shift
之外的修饰按键被按下,那么将会继续触发 keypress
/input
事件。可以指定 ‘text’选项以强制生成输入事件。
NOTE 修饰键将会影响
elementHandle.press
的效果。如果你按住Shift
键,然后再按其他的字母键,则你将输入一个大写的字母。
options
此方法将会在需要的时候将元素滚动到可视区域内,然后使用 page.screenshot方法来对 element进行截图操作。
如果 element 已经从DOM上 detach掉了,则此方法将抛出错误。
此方法将会在需要的时候将元素滚动到可视区域内,然后使用 touchscreen.tap来 tap element的中间位置。
如果 element 已经从DOM上 detach掉了,则将抛出错误。
text
options
delay
聚焦element,然后为每个输入的字符触发 keydown
, keypress
/input
, 以及 keyup
事件。
为了press一些特殊字符,例如 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');
...filePaths
<…string> Sets the value of the file input these paths. If some of the filePaths
are relative paths, then they are resolved relative to current working directory.This method expects elementHandle
to point to an input element.
当页面发起请求的时候,例如请求网络资源,下面这些事件都将会被触发:
- ‘request’ 当页面发起请求时触发。
- ‘response’ 当请求收到响应的时候触发。
- ‘requestfinished’ 当响应内容完全接受并且请求结束的时候触发。
如果请求动作在某个地方失败,那么 requestfinished
(也可能是 response
)事件会被 ‘requestfailed’所替代。
如果收到了重定向的响应指令,则当前请求结束,并触发 requestfinished
事件,然后会发起一个对新链接的获取请求。
errorCode
failed
, 允许以下值: aborted
- 某个操作 aborted (来源于 user)accessdenied
- 访问除网络之外的资源的权限被拒绝addressunreachable
- The IP address is unreachable. 这通常意味着没有路由到指定的主机或网络。connectionaborted
- 由于没有收到发送的数据的ACK,导致连接超时connectionclosed
- 连接被关闭 (corresponding to a TCP FIN).connectionfailed
- 连接请求失败.connectionrefused
- 连接请求被拒绝.connectionreset
- 连接请求被重置 (reset) (corresponding to a TCP RST).internetdisconnected
- 网络连接丢失(也就是没有网络了)namenotresolved
- 无法解析主机名。timedout
- 操作超时.failed
- 一个通用的故障发生Aborts request. To use this, 应确保请求拦截可用,使用 page.setRequestInterception
来设置。
如果未启用请求拦截,则将立即抛出异常。
overrides
url
method
GET
or POST
)postData
headers
拦截并改变请求参数。为了确保此方法可用,请使用 page.setRequestInterception
方法来保证请求拦截处于可用状态(enable)。
如果未启用请求拦截,则将立即抛出异常。
page.on('requestfailed', request => {
console.log(request.url() + ' ' + request.failure().errorText);
});
当前请求是否是一个 navigation的请求(即,当前请求是否会触发页面跳转或reload事件。)
A redirectChain
is a chain of requests initiated to fetch a resource.
- 如果没有重定向,并且请求成功,则返回 空数组 []
。
- If a server responds with at least a single redirect, then the chain will
contain all the requests that were redirected.
redirectChain
is shared between all the requests of the same chain.
例如,如果 http://example.com
有一个重定向到 https://example.com
的动作,则 redirectChain
将包含一个请求:
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
网站没有重定向的动作,则 redirectChain
将会是空数组:
const response = await page.goto('https://google.com');
const chain = response.request().redirectChain();
console.log(chain.length); // 0
包含所有被渲染引擎使用到的请求资源的类型,允许以下几种: document
, stylesheet
, image
, media
, font
, script
, texttrack
, xhr
, fetch
, eventsource
, websocket
, manifest
, other
.
response
status
200
。headers
contentType
Content-Type
body
用给定的响应来完成请求。 为了使此功能有效可用, 请设置 page.setRequestInterception
,以确保请求拦截可用。如果请求拦截不可用,则将抛出错误。
下面是一个给请求响应 404状态的例子:
await page.setRequestInterception(true);
page.on('request', request => {
request.respond({
status: 404,
contentType: 'text/plain',
body: 'Not Found!'
});
});
NOTE 不支持对 dataURL请求的模拟响应。
对一个 dataURL请求使用request.respond
将不会产生任何效果。
Response class represents responses which are received by page.
如果响应数据来自于磁盘或者内存,则返回 true
如果响应数据来自于 service worker,则返回 true
包含一个用于标记数据响应是否成功(状态码为 200-299)的布尔值。
包含响应状态码(例如,200,表示响应成功)
包含响应的 URL
SecurityDetails class represents responses which are received by page.
获取 target(可以认为是page) 隶属于的 browser。
The browser context the target belongs to.
Creates a Chrome Devtools Protocol session attached to the target.
返回 target的类型,可以是 "page"
, "background_page"
, "service_worker"
, "browser"
or "other"
EventEmitter
The CDPSession
instances are used to talk raw Chrome Devtools Protocol:
- protocol methods can be called with session.send
method.
- protocol events can be subscribed to with session.on
method.
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从 target上 detach掉,一旦cdpSession从 target上 detach掉了,则 the cdpSession object将不可再触发任何事件,也不再可以用于发送信息
method
params
Coverage用于收集记录页面使用了哪些 JavaScript 以及 CSS代码。
下面的例子展示了如何获取 页面在初始化的时候,用到了所加载得 JavaScript 以及 CSS文件多少比例的内容:
// Enable both JavaScript and CSS coverage
await Promise.all([
page.coverage.startJSCoverage(),
page.coverage.startCSSCoverage()
]);
// Navigate to page
await page.goto('https://example.com');
// Disable both JavaScript and CSS coverage
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}%`);
_To output coverage in a form consumable by Istanbul,
see puppeteer-to-istanbul._
options
resetOnNavigation
true
.options
resetOnNavigation
true
.url
text
ranges
start
end
NOTE CSS Coverage 不包括那些没有 sourceURLs的动态加载得 style标签。
url
text
ranges
start
end
NOTE JavaScript Coverage 不包括匿名脚本。但是,会包括带有sourceURLs的脚本。