class: Frame

在每一个时间点,页面通过 page.mainFrame()frame.childFrames() 方法暴露当前框架的细节。

[Frame]对象的生命周期由 3 个事件控制,通过 page 对象监听:

一个获得框架树的例子:

  1. const puppeteer = require('puppeteer');
  2. puppeteer.launch().then(async browser => {
  3. const page = await browser.newPage();
  4. await page.goto('https://www.google.com/chrome/browser/canary.html');
  5. dumpFrameTree(page.mainFrame(), '');
  6. await browser.close();
  7. function dumpFrameTree(frame, indent) {
  8. console.log(indent + frame.url());
  9. for (let child of frame.childFrames())
  10. dumpFrameTree(child, indent + ' ');
  11. }
  12. });

frame.$(selector)

  • selector <[string]> Selector to query page for

  • returns: <[Promise]<?[ElementHandle]>> Promise which resolves to ElementHandle pointing to the frame element.

这个方法在框架中查询指定的选择器。如果在框架中没有匹配的元素会返回null

frame.$$(selector)

  • selector <[string]> Selector to query page 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 for
  • pageFunction <[function]> Function to be evaluated in browser context
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of pageFunction

这个方法会在框架中执行document.querySelectorAll方法,然后将返回值传给pageFunction函数的第一个参数。

如果pageFunction返回了一个[Promise],那么frame.$$eval将会等待Promise resolve之后返回它的值。

例子:

  1. const divsCounts = await frame.$$eval('div', divs => divs.length);

frame.$eval(selector, pageFunction[, …args])

  • selector <[string]> A [selector] to query frame for
  • pageFunction <[function]> Function to be evaluated in browser context
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of pageFunction

这个方法会在框架中执行document.querySelector方法,然后将返回值传给pageFunction函数的第一个参数。如果没有匹配到任何元素,则会抛出一个错误。

如果pageFunction返回了一个[Promise],那么frame.$eval将会等待 Promise resolve 之后返回它的值。

例如:

  1. const searchValue = await frame.$eval('#search', el => el.value);
  2. const preloadHref = await frame.$eval('link[rel=preload]', el => el.href);
  3. 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. If path 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. If path 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()

  • returns: <[Array]<[Frame]>>

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, or middle, defaults to left.
    • clickCount <[number]> defaults to 1. See [UIEvent.detail].
    • delay <[number]> Time to wait between mousedown and mouseup 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 matching selector.

这个方法选择传入的元素,如果必要的话会将元素滚动到可视区域,之后使用 page.mouse 点击元素的内容。如果没有匹配到元素,会抛出异常。

注意:如果click()触发了导航事件,那么就会有一个由page.waitForNavigation()产生的 promise 要被 resolved ,你可能会得到一个promise竞争态。正确的处理 click 和 wait for navigation 的方式如下:

  1. const [response] = await Promise.all([
  2. page.waitForNavigation(waitOptions),
  3. frame.click(selector, clickOptions),
  4. ]);

frame.content()

  • returns: <[Promise]<[String]>>

获取框架完整的HTML内容,包括 doctype。

frame.evaluate(pageFunction, …args)

  • pageFunction <[function]|[string]> Function to be evaluated in browser context
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of pageFunction

如果传给frame.evaluate的函数返回了一个 promise,那么frame.evaluate将会等到 promise resolve 时返回它的值。

如果传给frame.evaluate的函数返回了一个非序列化的值,那么frame.evaluate将返回undefined

  1. const result = await frame.evaluate(() => {
  2. return Promise.resolve(8 * 7);
  3. });
  4. console.log(result); // prints "56"

也可以给函数传递字符串。

  1. console.log(await frame.evaluate('1 + 2')); // prints "3"

[ElementHandle] 实例也可以作为frame.evaluate的参数:

  1. const bodyHandle = await frame.$('body');
  2. const html = await frame.evaluate(body => body.innerHTML, bodyHandle);
  3. await bodyHandle.dispose();

frame.evaluateHandle(pageFunction, …args)

  • pageFunction <[function]|[string]> Function to be evaluated in the page context
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of pageFunction as in-page object (JSHandle)

frame.evaluateframe.evaluateHandle唯一的不同是frame.evaluateHandle返回页面对象(JSHandle)。

如果传给frame.evaluateHandle的函数返回了一个[Promise],那么frame.evaluateHandle将会等到 promise resolve 时返回它的值。

  1. const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window));
  2. aWindowHandle; // Handle for the window object.

也可以向函数传递字符串。

  1. const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'.

[JSHandle] 实例也可以作为frame.evaluateHandle的参数:

  1. const aHandle = await frame.evaluateHandle(() => document.body);
  2. const resultHandle = await frame.evaluateHandle(body => body.innerHTML, aHandle);
  3. console.log(await resultHandle.jsonValue());
  4. await resultHandle.dispose();

frame.executionContext()

  • returns: <[Promise]<[ExecutionContext]>> Execution context associated with this frame.

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 matching selector.

这个方法选择传入的元素并且使之获得焦点。如果没有匹配到元素,会抛出异常。

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 matching selector.

这个方法选择传入的元素,如果必要的话会滚动到视野区域中,然后使用 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 the multiple 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.

下拉框一旦选择了所提供的选项,changeinput事件将会被触发。

如果没有匹配到下拉框,会抛出异常。

  1. frame.select('select#colors', 'blue'); // 单选
  2. frame.select('select#colors', 'red', 'green', 'blue'); // 多选

frame.setContent(html)

  • html <[string]> HTML markup to assign to the page.
  • returns: <[Promise]>

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()

  • returns: <[Promise]<[string]>> Returns page’s 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]>

对于每一个文本中的字符执行keydownkeypress / input, 和keyup事件

如果要输入特殊按键,比如Control或者ArrowDown,使用keyboard.press

  1. frame.type('#mytextarea', 'Hello'); // 立即输入
  2. 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 for
  • options <[Object]> Optional waiting parameters
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[JSHandle]>> Promise which resolves to a JSHandle of the success value

这个方法根据第一个参数类型的不同发挥不同的作用:

  • 如果selectorOrFunctionOrTimeoutstring,那么第一个参数会被当作[selector] 或者 [xpath],取决于是不是以//开头的,这是frame.waitForSelectorframe.waitForXPath 的快捷方式。

  • 如果selectorOrFunctionOrTimeoutfunction,那么第一个参数会当作条件等待触发,这是 frame.waitForFunction() 的快捷方式。

  • 如果selectorOrFunctionOrTimeoutnumber,那么第一个参数会被当作毫秒为单位的时间,方法会在超时之后返回 promise。

  • 其他类型,将会抛出错误。

frame.waitForFunction(pageFunction[, options[, …args]])

  • pageFunction <[function]|[string]> Function to be evaluated in browser context
  • options <[Object]> Optional waiting parameters
    • polling <[string]|[number]> An interval at which the 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. If polling is a string, then it can be one of the following values:
      • raf - to constantly execute pageFunction in requestAnimationFrame callback. This is the tightest polling mode which is suitable to observe styling changes.
      • mutation - to execute pageFunction on every DOM mutation.
    • timeout <[number]> maximum time to wait for in milliseconds. Defaults to 30000 (30 seconds). Pass 0 to disable timeout.
  • ...args <…[Serializable]|[JSHandle]> Arguments to pass to pageFunction
  • returns: <[Promise]<[JSHandle]>> Promise which resolves when the pageFunction returns a truthy value. It resolves to a JSHandle of the truthy value.

waitForFunction可以用来观察可视区域大小是否改变。

  1. const puppeteer = require('puppeteer');
  2. puppeteer.launch().then(async browser => {
  3. const page = await browser.newPage();
  4. const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100');
  5. page.setViewport({width: 50, height: 50});
  6. await watchDog;
  7. await browser.close();
  8. });

frame.waitForSelector(selector[, options])

  • selector <[string]> A [selector] of an element to wait for
  • options <[Object]> Optional waiting parameters
    • visible <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have display: none or visibility: hidden CSS properties. Defaults to false.
    • hidden <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have display: none or visibility: hidden CSS properties. Defaults to false.
    • timeout <[number]> maximum time to wait for in milliseconds. Defaults to 30000 (30 seconds). Pass 0 to disable timeout.
  • returns: <[Promise]<[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM.

等待被选择等待元素出现在页面中。如果调用时选择的元素已存在,会立即返回。如果在设定的毫秒时间之后没有出现,则抛出异常。

这个方法可以在切换导航时使用:

  1. const puppeteer = require('puppeteer');
  2. puppeteer.launch().then(async browser => {
  3. const page = await browser.newPage();
  4. let currentURL;
  5. page.mainFrame()
  6. .waitForSelector('img')
  7. .then(() => console.log('First URL with image: ' + currentURL));
  8. for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
  9. await page.goto(currentURL);
  10. await browser.close();
  11. });

frame.waitForXPath(xpath[, options])

  • xpath <[string]> A [xpath] of an element to wait for
  • options <[Object]> Optional waiting parameters
    • visible <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have display: none or visibility: hidden CSS properties. Defaults to false.
    • hidden <[boolean]> wait for element to not be found in the DOM or to be hidden, i.e. have display: none or visibility: hidden CSS properties. Defaults to false.
    • timeout <[number]> maximum time to wait for in milliseconds. Defaults to 30000 (30 seconds). Pass 0 to disable timeout.
  • returns: <[Promise]<[ElementHandle]>> Promise which resolves when element specified by xpath string is added to DOM.

等待xpath出现在页面中。如果在调用函数的时候xpath已经存在,会立即返回。如果在设定的毫秒时间之后没有出现,则抛出异常。

这个方法可以在切换导航时使用:

  1. const puppeteer = require('puppeteer');
  2. puppeteer.launch().then(async browser => {
  3. const page = await browser.newPage();
  4. let currentURL;
  5. page.mainFrame()
  6. .waitForXPath('//img')
  7. .then(() => console.log('First URL with image: ' + currentURL));
  8. for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
  9. await page.goto(currentURL);
  10. await browser.close();
  11. });