web-dev-qa-db-ja.com

操り人形師:複数のタブを処理する方法は?

シナリオ:2部構成のワークフローを使用した開発者アプリ登録用のWebフォーム。

ページ1:開発者アプリの詳細を入力し、ボタンをクリックして、新しいタブで開くアプリケーションIDを作成します...

ページ2:アプリIDページ。このページからアプリIDをコピーし、タブを閉じてページ1に戻り、アプリID(ページ2から保存)を入力し、フォームを送信する必要があります。

私は基本的な使用法を理解しています-ページ1を開き、ページ2を開くボタンをクリックする方法-しかし、新しいタブでページ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を更新

良い使用例を探しています。

24
nilsw

これは、最新のアルファブランチで機能します。

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依存関係を

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

ソース:JoelEinbinder @ https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315

11
rhon

2日前に新しいパッチがコミットされました。現在、browser.pages()を使用して、現在のブラウザーのすべてのページにアクセスできます。うまく動作し、昨日自分で試しました:)

編集:

「target:_blank」リンクとして開かれた新しいページのJSON値を取得する方法の例。

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
10
kaiak

公式ドキュメント によると:

browser.pages()

  • 戻り値:<Promise<Array<- Page>>>に解決する約束開いているすべてのページの配列。 "background_page"などの非表示ページはここにリストされません。 target.page() を使用してそれらを見つけることができます。

ブラウザ内のすべてのページの配列。複数のブラウザコンテキストの場合、メソッドはすべてのブラウザコンテキストのすべてのページを含む配列を返します。

使用例:

let pages = await browser.pages();
await pages[0].evaluate(() => { /* ... */ });
await pages[1].evaluate(() => { /* ... */ });
await pages[2].evaluate(() => { /* ... */ });
5
Grant Miller

target="_blank"属性が原因である場合にページを切り替える必要性を削除するには、target="_self"を設定します。

例:

element = page.$(selector)

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

element.click()
2

理論的には、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. ボタンをクリックして2番目のページに移動し、そこでいくつかのアクションを実行します。

    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では簡単な作業ではありません。

2
krukid

クリックアクションがページロードを発行している場合、実行されている後続のスクリプトは事実上失われます。これを回避するには、アクション(この場合はクリック)をトリガーする必要がありますが、notawaitです。代わりに、ページの読み込みを待ちます:

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

これにより、スクリプトは次のページ読み込みイベントを効果的に待ってから、さらにアクションを進めることができます。

2
browserless

現在はできません-フォロー https://github.com/GoogleChrome/puppeteer/issues/386 puppeteerに機能が追加された時期を知るために(できればすぐに)

1
Thomas Walpole