木偶:如何处理多个标签?

场景:用于开发人员应用程序注册的Web表单,具有两部分工作stream程。

第1页:填写开发人员的应用程序的详细信息,并点击button,以创build应用程序ID,它打开,在一个新的标签…

第2页:App ID页面。 我需要从这个页面复制应用程序ID,然后closures该选项卡并返回到第1页并填写App ID(从第2页保存),然后提交表单。

我了解基本用法 – 如何打开页面1并单击打开页面的button – 但是如何在新页面打开时获得页面上的句柄?

例:

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

  • Browser.pages的工作已完成并合并
  • 修复当新的选项卡创build#386和请求:browser.currentPage()或类似的方式来访问页#443 时,发出新的页面对象 。

仍然在寻找一个很好的使用示例。

这将在最新的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 

一定要使用最后的木偶版本(从Github主分支)通过设置package.json依赖

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

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

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

编辑:

一个例子,如何获得一个新的页面的JSON值打开为“目标:_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 

从理论上讲,你可以重写window.open函数,在你的当前页面上总是打开“新标签”,并通过历史导航。

您的工作stream程将是:

  1. 覆盖window.open函数:

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

     await page.goto(PAGE1_URL) // ... do stuff on page 1 
  3. 点击button导航到您的第二页,并在那里执行一些操作:

     await page.click('#button_that_opens_page_2') await page.waitForNavigation() // ... do stuff on page 2, extract any info required on page 1 // eg 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并不是一件容易的事情。