木偶:如何处理多个标签?
场景:用于开发人员应用程序注册的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程将是:
-
覆盖
window.open
函数:await page.evaluateOnNewDocument(() => { window.open = (url) => { top.location = url } })
-
转到您的第一页并执行一些操作:
await page.goto(PAGE1_URL) // ... do stuff on page 1
-
点击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(() => { ... })
-
返回到您的首页:
await page.goBack() // or: await page.goto(PAGE1_URL) // ... do stuff on page 1, injecting info saved from page 2
显然,这种方法有其缺点,但我发现它大大简化了多标签导航,如果您已经在多个标签页上运行并行作业,这将特别有用。 不幸的是,目前的API并不是一件容易的事情。