Introduction à Puppeteer

Introduction au contrôle par programme de Chrome à partir de Node.js

Puppeteer est une bibliothèque de nœuds que nous pouvons utiliser pour contrôler unChrome sans têteexemple. Nous utilisons essentiellement Chrome, mais nous utilisons JavaScript par programmation.

En l'utilisant, nous pouvons:

  • gratter des pages Web
  • automatiser les soumissions de formulaires
  • effectuer tout type d'automatisation de navigateur
  • suivre les performances de chargement de la page
  • créer des versions rendues côté serveur d'applications à page unique
  • faire des captures d'écran
  • créer des tests automatisés
  • générer des PDF à partir de pages Web

Il est construit par Google. Il ne débloque rien de nouveau, en soi, mais il résume bon nombre des détails essentiels que nous aurions à traiter, sans l'utiliser.

Bref, cela rend les choses très faciles.

Puisqu'il lance une nouvelle instance Chrome lors de son initialisation, il se peut qu'il ne soit pas le plus performant. C'est le moyen le plus précis d'automatiser les tests avec Chrome, car il utilise lenavigateur actuelsous la capuche.

Pour être précis, il utilise Chromium, la partie open source de Chrome, ce qui signifie principalement que vous ne disposez pas des codecs propriétaires sous licence Google et ne peuvent pas être open source (MP3, AAC, H.264 ..) et vous n'ont pas l'intégration avec les services Google comme les rapports de plantage, la mise à jour de Google et plus, mais d'un point de vue programmatique, tout devrait être 100% similaire à Chrome (sauf pour la lecture multimédia, comme indiqué).

Installer Puppeteer

Commencez par l'installer en utilisant

npm install puppeteer

dans votre projet.

Cela téléchargera et regroupera la dernière version de Chromium.

Vous pouvez choisir de faire exécuter par marionnettiste l'installation locale de Chrome que vous avez déjà installée en installantpuppeteer-coreà la place, ce qui est utile dans certains cas particuliers (voirmarionnettiste vs marionnettiste-core). Habituellement, tu vas juste avecpuppeteer.

Utiliser Marionnettiste

Dans un fichier Node.js, exigez-le:

const puppeteer = require('puppeteer');

alors nous pouvons utiliser lelaunch()méthode pour créer une instance de navigateur:

(async () => {
  const browser = await puppeteer.launch()
})()

Nous pouvons également écrire comme ceci:

puppeteer.launch().then(async browser => {
  //...
})

Vous pouvez transmettre un objet avec des options àpuppeteer.launch(). Le plus courant est

puppeteer.launch({ headless:false })

pour afficher Chrome pendant que Puppeteer effectue ses opérations. Cela peut être agréable de voir ce qui se passe et de déboguer.

Nous utilisonsawait, et nous devons donc envelopper cet appel de méthode dans unfonction asynchrone, que nousinvoquer immédiatement.

Ensuite, nous pouvons utiliser lenewPage()méthode sur lebrowserobjet pour obtenir lepageobjet:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
})()

Ensuite, nous appelons legoto()méthode sur lepageobjet pour charger cette page:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
})()

Nous pourrions également utiliser des promesses au lieu de async / await, mais l'utilisation de ce dernier rend les choses beaucoup plus lisibles:

(() => {
  puppeteer.launch().then(browser => {
    browser.newPage().then(page => {
      page.goto('https://website.com').then(() => {
        //...
      })
    })
  })
})()

Obtenir le contenu de la page

Une fois que nous avons une page chargée avec une URL, nous pouvons obtenir la pageteneurappeler leevaluate()méthode depage:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">result</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">page</span>.<span style="color:#a6e22e">evaluate</span>(() =&gt; {
<span style="color:#75715e">//...

}) })()

Cette méthode prend une fonction de rappel, où nous pouvons ajouter le code nécessaire pour récupérer les éléments de la page dont nous avons besoin. Nous retournons un nouvel objet, et ce sera le résultat de notreevaluate()appel de méthode.

Nous pouvons utiliser lepage.$()méthode pour accéder auAPI des sélecteursméthodequerySelector()sur le document, etpage.$()comme alias dequerySelectorAll().

Une fois nos calculs terminés, nous appelons leclose()méthode surbrowser:

browser.close()

Méthodes de page

Nous avons vu au-dessus dupageobjet que nous obtenons en appelantbrowser.newPage(), et nous avons appelé legoto()etevaluate()méthodes là-dessus.

Toutes les méthodes renvoient une promesse, elles sont donc normalement précédées duawaitmot-clé.

Voyons voirquelquesdes méthodes les plus courantes que nous appellerons.Vous pouvez voir la liste complète sur la documentation Puppeteer.

page.$()

Donne accès auAPI des sélecteursméthodequerySelector()sur la page

page.$()

Donne accès auAPI des sélecteursméthodequerySelectorAll()sur la page

page.$eval()

Accepte 2 paramètres ou plus. Le premier est un sélecteur, le second une fonction. S'il y a plus de paramètres, ceux-ci sont passés comme arguments supplémentaires à la fonction.

Il courtquerySelectorAll()sur la page, en utilisant le premier paramètre comme sélecteur, puis il utilise ce paramètre comme premier argument de la fonction.

const innerTextOfButton = await page.$eval('button#submit', el => el.innerText)

click()

Effectuer un événement de clic de souris sur l'élément passé en paramètre

await page.click('button#submit')

On peut passer un argument supplémentaire avec un objet d'options:

  • buttonpeut être réglé surleft(défaut),rightoumiddle
  • clickCountest un nombre qui vaut par défaut 1 et définit combien de fois l'élément doit être cliqué
  • delayest le nombre de millisecondes entre les clics. La valeur par défaut est0

content()

Obtenir la source HTML d'une page

const source = await page.content()

emulate()

Émule un appareil. Il définit l'agent utilisateur sur un périphérique spécifique et définit la fenêtre en conséquence.

La liste des appareils pris en charge est disponibledans ce fichier.

Voici comment vous émulez un iPhone X:

iPhone X

const puppeteer = require('puppeteer');
const device = require('puppeteer/DeviceDescriptors')['iPhone X'];

puppeteer.launch().then(async browser => { const page = await browser.newPage() await page.emulate(device)

//do stuff await browser.close() })

evaluate()

Évalue une fonction dans le contexte de la page. Dans cette fonction, nous avons accès audocumentobjet, nous pouvons donc appeler n'importe quelle API DOM:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluate(() => { return document.querySelectorAll(’.footer-tags a’).length })

console.log(result) })()

Tout ce que nous appelons ici est exécuté dans le contexte de la page, donc si nous exécutonsconsole.log(), nous ne verrons pas le résultat dans le contexte Node.js car il est exécuté dans le navigateur headless.

Nous pouvons calculer des valeurs ici et renvoyer un objet JavaScript, mais si nous voulons retourner un élément DOM et y accéder dans le contexte Node.js, nous devons utiliser une méthode différente,evaluateHandle(). Si nous retournons un élément DOM à partir de evaluer (), nous obtiendrons juste un objet vide.

evaluateHandle()

Similaire à evaluer (), mais si nous retournons un élément DOM, nous récupérerons l'objet approprié plutôt qu'un objet vide:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluateHandle(() => { return document.querySelectorAll(’.footer-tags a’) })

console.log(result) })()

exposeFunction()

Cette méthode vous permet d'ajouter une nouvelle fonction dans le contexte du navigateur, qui est exécutée dans le contexte Node.js.

Cela signifie que nous pouvons ajouter une fonction qui exécute le code Node.js dans le navigateur.

Cet exemple ajoute une fonction test () dans le contexte du navigateur qui lit un fichier «app.js» à partir du système de fichiers, avec le chemin relatif au script:

const puppeteer = require('puppeteer');
const fs = require('fs');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

await page.exposeFunction(‘test’, () => { const loadData = (path) => { try { return fs.readFileSync(path, ‘utf8’) } catch (err) { console.error(err) return false } } return loadData(‘app.js’) })

const result = await page.evaluate(() => { return test() })

console.log(result) })()

focus()

Se concentre sur le sélecteur passé en paramètre

await page.focus('input#name')

goBack()

Remonte dans l'historique de navigation de la page

await page.goBack()

goForward()

Avance dans l'historique de navigation des pages

await page.goForward()

goto()

Ouvre une nouvelle page.

await page.goto('https://flaviocopes.com')

Vous pouvez passer un objet comme deuxième paramètre, avec des options. LewaitUntiloption, si passé lenetworkidle2value attendra que la navigation soit terminée:

await page.goto('https://flaviocopes.com', {waitUntil: 'networkidle2'})

hover()

Faites un survol sur le sélecteur passé en paramètre

await page.hover('input#name')

pdf()

Générez un PDF à partir d'une page. Tu peux

await page.pdf({ path: 'file.pdf })

Vous pouvez passer de nombreuses options à cette méthode, pour définir les détails du PDF généré.Voir la documentation officielle.

reload()

Recharger une page

await page.reload()

screenshot()

Prend une capture d'écran PNG de la page, en l'enregistrant sous le nom de fichier sélectionné à l'aide depath.

await page.screenshot({path: 'screenshot.png'})

Voir toutes les options

select()

Sélectionnez les éléments DOM identifiés par le sélecteur passé en paramètre

await page.select('input#name')

setContent()

Vous pouvez définir le contenu d'une page plutôt que d'ouvrir une page Web existante.

Utile pour générer par programmation des PDF ou des captures d'écran avec du HTML existant:

const html = '<h1>Hello!</h1>'
await page.setContent(html)
await page.pdf({path: 'hello.pdf'})
await page.screenshot({path: 'screenshot.png'})

setViewPort()

Par défaut, la fenêtre est de 800x600px. Si vous souhaitez avoir une fenêtre différente, peut-être pour prendre une capture d'écran, appelezsetViewportpasser un objet avecwidthetheightPropriétés.

await page.setViewport({ width: 1280, height: 800 })

title()

Obtenez le titre de la page

await page.title()

type()

Types dans un sélecteur qui identifie un élément de formulaire

await page.type('input#name', 'Flavio')

LedelayL'option permet de simuler la frappe comme un utilisateur du monde réel, en ajoutant un délai entre chaque caractère:

await page.type('input#name', 'Flavio', {delay: 100})

url()

Obtenez l'URL de la page

await page.url()

viewport()

Obtenir la fenêtre d'affichage de la page

await page.viewport()

waitFor()

Attendez que quelque chose de spécifique se produise. Possède les fonctions de raccourci suivantes:

  • waitForFunction
  • waitForNavigation
  • waitForRequest
  • waitForResponse
  • waitForSelector
  • waitForXPath

Exemple:

await page.waitFor(waitForNameToBeFilled)
const waitForNameToBeFilled = () => page.$('input#name').value != ''

Espaces de noms de page

Un objet de page vous donne accès à plusieurs objets différents:

Chacun de ceux-ci ouvre de nombreuses nouvelles fonctionnalités.

keyboardetmousesont probablement ceux que vous utiliserez le plus lorsque vous essayez d'automatiser les choses.

Par exemple, voici comment vous déclenchez la saisie dans un élément (qui aurait dû être sélectionné précédemment):

await page.keyboard.type('hello!')

Les autres méthodes de clavier sont

  • keyboard.down()pour envoyer un événement keydown
  • keyboard.press()pour envoyer un keydown suivi d'un keyup (simulant un type de clé normal). Utilisé principalement pour les touches de modification (shift, ctrl, cmd)
  • keyboard.sendCharacter()envoie un événement de pression de touche
  • keyboard.type()envoie un événement keydown, keypress et keyup
  • keyboard.up()pour envoyer un événement keyup

Tous ceux-ci reçoivent un code de touche de clavier tel que défini dans le fichier de disposition du clavier américain:https://github.com/GoogleChrome/puppeteer/blob/master/lib/USKeyboardLayout.js. Les caractères normaux et les nombres sont saisis tels quels, tandis que les touches spéciales ont un code spécial pour les définir.

mousepropose 4 méthodes:

  • mouse.click()pour simuler un clic:mousedownetmouseupévénements
  • mouse.down()pour simuler unmousedownun événement
  • mouse.move()pour passer à des coordonnées différentes
  • mouse.up()pour simuler unmouseupun événement