Puppeteer:如何处理多个标签?

node.js automated-tests google-chrome-headless puppeteer

19144 观看

7回复

2628 作者的声誉

场景:用于开发人员应用注册的Web表单,包含两部分工作流程。

第1页:填写开发者应用程序详细信息,然后单击按钮以在新选项卡中创建应用程序ID,该ID将打开...

第2页:App ID页面。我需要从此页面复制App ID,然后关闭选项卡并返回到第1页并填写App ID(从第2页保存),然后提交表单。

我了解基本用法 - 如何打开第1页并单击打开第2页的按钮 - 但如何在新选项卡中打开第2页时如何处理?

例:

const puppeteer = require('puppeteer');

(async() => {
    const browser = await puppeteer.launch({headless: false, executablePath: '/Applications/Google Chrome.app'});
    const page = await browser.newPage();

    // go to the new bot registration page
    await page.goto('https://register.example.com/new', {waitUntil: 'networkidle'});

    // fill in the form info
    const form = await page.$('new-app-form');

    await page.focus('#input-appName');
    await page.type('App name here');

    await page.focus('#input-appDescription');
    await page.type('short description of app here');

    await page.click('.get-appId'); //opens new tab with Page 2

    // handle Page 2
    // get appID from Page 2
    // close Page 2

    // go back to Page 1
    await page.focus('#input-appId');
    await page.type(appIdSavedFromPage2);

    // submit the form
    await form.evaluate(form => form.submit());

    browser.close();
})();

2017-10-25更新

仍在寻找一个好的用法示例。

作者: nilsw 的来源 发布者: 2017 年 8 月 21 日

回应 (7)


1

33864 作者的声誉

你当前不能 - 按照https://github.com/GoogleChrome/puppeteer/issues/386来了解该功能何时添加到木偶操作员(希望很快)

作者: Thomas Walpole 发布者: 22.08.2017 07:40

11

123 作者的声誉

这将在最新的alpha分支中为您工作:

const newPagePromise = new Promise(x => browser.once('targetcreated', target => x(target.page())));
await page.click('my-link');
// handle Page 2: you can access new page DOM through newPage object
const newPage = await newPagePromise;
await newPage.waitForSelector('#appid');
const appidHandle = await page.$('#appid');
const appID = await page.evaluate(element=> element.innerHTML, appidHandle );
newPage.close()
[...]
//back to page 1 interactions

通过将package.json依赖项设置为,确保使用最后一个puppeteer版本(来自Github master分支)

"dependencies": {
    "puppeteer": "git://github.com/GoogleChrome/puppeteer"
},

资料来源:JoelEinbinder @ https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315

作者: rhon 发布者: 27.10.2017 09:44

6

379 作者的声誉

两天前已经提交了一个新补丁,现在您可以使用它browser.pages()来访问当前浏览器中的所有页面。工作正常,昨天尝试自己:)

编辑:

如何获取新页面的JSON值作为'target:_blank'链接打开的示例。

const page = await browser.newPage();
await page.goto(url, {waitUntil: 'load'});

// click on a 'target:_blank' link
await page.click(someATag);

// get all the currently open pages as an array
let pages = await browser.pages();

// get the last element of the array (third in my case) and do some 
// hucus-pocus to get it as JSON...
const aHandle = await pages[3].evaluateHandle(() => document.body);

const resultHandle = await pages[3].evaluateHandle(body => 
  body.innerHTML, aHandle);

// get the JSON value of the page.
let jsonValue = await resultHandle.jsonValue();

// ...do something with JSON
作者: kaiak 发布者: 03.11.2017 06:46

2

1936 作者的声誉

理论上,您可以覆盖该window.open功能以始终在当前页面上打开“新选项卡”并通过历史记录导航。

您的工作流程将是:

  1. 覆盖window.open功能:

    await page.evaluateOnNewDocument(() => {
      window.open = (url) => {
        top.location = url
      }
    })
    
  2. 转到第一页并执行一些操作:

    await page.goto(PAGE1_URL)
    // ... do stuff on page 1
    
  3. 单击按钮导航到第二页并在那里执行一些操作:

    await page.click('#button_that_opens_page_2')
    await page.waitForNavigation()
    // ... do stuff on page 2, extract any info required on page 1
    // e.g. const handle = await page.evaluate(() => { ... })
    
  4. 返回第一页:

    await page.goBack()
    // or: await page.goto(PAGE1_URL)
    // ... do stuff on page 1, injecting info saved from page 2
    

显然,这种方法有其缺点,但我发现它大大简化了多标签导航,如果您已经在多个标签上运行并行作业,这将特别有用。不幸的是,当前的API并不是一件容易的事。

作者: krukid 发布者: 17.11.2017 07:50

2

1291 作者的声誉

您可以删除切换页面的需要,以防它由target="_blank"属性 - 通过设置引起target="_self"

例:

element = page.$(selector)

await page.evaluateHandle((el) => {
        el.target = '_self';
 }, element)

element.click()
作者: Giovanni Bitliner 发布者: 30.12.2017 11:21

2

1126 作者的声誉

如果您的单击操作正在发出页面加载,则正在运行的任何后续脚本都将丢失。要解决此问题,您需要触发操作(在这种情况下单击)但不是 await为了它。相反,等待页面加载:

page.click('.get-appId');
await page.waitForNavigation();

这将允许您的脚本在继续执行进一步操作之前有效地等待下一个pageload事件。

作者: browserless 发布者: 30.05.2018 07:27

3

7843 作者的声誉

根据官方文件

browser.pages()

  • 返回:Promise,它解析为所有打开页面的数组。此处不会列出不可见的页面,例如。你可以找到它们。<Promise<Array<Page>>>"background_page"target.page()

浏览器中所有页面的数组。在多个浏览器上下文的情况下,该方法将返回包含所有浏览器上下文中的所有页面的数组。

用法示例:

let pages = await browser.pages();
await pages[0].evaluate(() => { /* ... */ });
await pages[1].evaluate(() => { /* ... */ });
await pages[2].evaluate(() => { /* ... */ });
作者: Grant Miller 发布者: 24.08.2018 11:18
32x32