web-dev-qa-db-fra.com

Marionnettiste: Comment gérer plusieurs onglets?

Scénario: formulaire Web pour l'enregistrement d'une application pour développeur avec un flux de travail en deux parties.

Page 1: renseignez les informations relatives à l'application pour les développeurs et cliquez sur le bouton pour créer l'ID de l'application, qui s'ouvre dans un nouvel onglet ...

Page 2: La page d'identification de l'application. Je dois copier l'ID de l'application à partir de cette page, puis fermer l'onglet, revenir à la page 1, saisir l'ID de l'application (enregistré à partir de la page 2), puis envoyer le formulaire.

Je comprends l’utilisation de base - comment ouvrir la page 1 et cliquer sur le bouton qui ouvre la page 2 - mais comment puis-je obtenir une poignée sur la page 2 lorsqu’elle s’ouvre dans un nouvel onglet?

Exemple:

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

Mise à jour 2017-10-25 

Je cherche toujours un bon exemple d'utilisation.

19
nilsw

Cela fonctionnera pour vous dans la dernière branche 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

Veillez à utiliser la dernière version de marionnettiste (de la branche principale de Github) en définissant la dépendance package.json sur 

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

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

10
rhon

Un nouveau patch a été validé il y a deux jours et vous pouvez maintenant utiliser browser.pages() pour accéder à toutes les pages du navigateur actuel. Fonctionne bien, essayé moi-même hier :)

Modifier:

Voici un exemple d'obtention de la valeur JSON d'une nouvelle page ouverte en tant que lien "cible: _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
5
kaiak

Selon le Documentation officielle :

browser.pages ()

  • renvoie: <Promise<Array<Page>>> Promesse qui se résout en un tableau de toutes les pages ouvertes. Les pages non visibles, telles que "background_page", ne seront pas répertoriées ici. Vous pouvez les trouver en utilisant target.page() .

Un tableau de toutes les pages du navigateur. Dans le cas de plusieurs contextes de navigateur, la méthode renverra un tableau avec toutes les pages dans tous les contextes de navigateur.

Exemple d'utilisation:

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

Vous pouvez supprimer le besoin de changer de page au cas où cela serait causé par l'attribut target="_blank" - en définissant target="_self"

Exemple:

element = page.$(selector)

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

element.click()
1
Giovanni Bitliner

En théorie, vous pouvez remplacer la fonction window.open pour toujours ouvrir les "nouveaux onglets" sur votre page actuelle et naviguer dans l'historique.

Votre flux de travail serait alors:

  1. Remplacez la fonction window.open:

    await page.evaluateOnNewDocument(() => {
      window.open = (url) => {
        top.location = url
      }
    })
    
  2. Accédez à votre première page et effectuez certaines actions:

    await page.goto(PAGE1_URL)
    // ... do stuff on page 1
    
  3. Accédez à votre deuxième page en cliquant sur le bouton et effectuez certaines actions à cet endroit:

    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. Retournez à votre première page:

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

Cette approche a évidemment des inconvénients, mais je trouve qu'elle simplifie considérablement la navigation à plusieurs onglets, ce qui est particulièrement utile si vous exécutez déjà des tâches parallèles sur plusieurs onglets. Malheureusement, les API actuelles ne facilitent pas la tâche.

1
krukid

Si votre action de clic émet un chargement de page, tous les scripts en cours d'exécution sont perdus. Pour contourner cela, vous devez déclencher l'action (un clic dans ce cas) mais pas await pour elle. Au lieu de cela, attendez le chargement de page:

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

Cela permettra à votre script d'attendre effectivement le prochain événement pageload avant de poursuivre d'autres actions.

0
griffith_joel

Vous ne pouvez pas actuellement - Suivre https://github.com/GoogleChrome/puppeteer/issues/386 pour savoir quand la capacité est ajoutée à marionnettiste (j'espère bientôt)

0
Thomas Walpole