SlideShare una empresa de Scribd logo
1 de 68
Descargar para leer sin conexión
Initiation à Puppeteer et Rendertron
Audrey Schoonwater
@witamine
Sommaire
01 02
Node.js Puppeteer
Plateforme de
développement
Librairie Node.js
03
Rendertron
Développé avec
Puppeteer
Node.js
Node.js en bref
But : Plateforme rendre le JavaScript côté serveur pour les robots
● Depuis 2009
● Développer des applications JavaScript (moteur JS v8 de Chrome)
● Permet d'exécuter du JavaScript très bas niveau et côté serveur.
Après l’install Node.js
Le dossier de “nodejs” contient :
● Exécuteur node.exe
● Module npm (Node Package Manager) :
ajouter / retirer des librairies
● Variables d'environnements pour exécuter les
commandes node et npm dans l’invite de
commande.
Hello World ! 1/2
Créer un dossier pour les projets node.js : C:nodejs
1. Créer helloworld.js
2. Coller le code suivant :
1. Exécuter le programme
1 // écrit dans la console "Hello World !"
2 console.log("Hello World !");
Hello World ! 2/2
Créer le fichier server.js avec le code suivant
1 const { createServer } = require('http'); // Librairie HTTP native
2 //Création du serveur
3 const server = createServer((request, response) => {
4 response.writeHead(200, {'Content-Type': 'text/plain'});
5 response.end('Hello Worldn');
6 });
7 server.listen(3000, () => console.log(`Adresse serveur : http://localhost:3000`));
Prérequis
De quoi a-t-on besoin pour utiliser Puppeteer ?
● Lignes de commande
Connaissance basique
● JavaScript
Plateforme Node.js
● DOM Document Object Model
Connaissance basique
Qu’est-ce que Puppeteer ?
● Librairie développée par Google en 2017
● Elle contrôle une instance du navigateur Chrome ou
Chromium via le protocole DevTools.
● Cette instance peut être headless ou non, c’est-à-dire un
navigateur sans interface utilisateur.
● Il permet à un programme de lire et d’interagir avec lui.
Qu'est-il possible de faire avec Puppeteer ?
Tout de qu'on peut faire avec un navigateur :
● afficher une page
● cliquer sur un bouton
● remplir un formulaire etc.
Installer Puppeteer
• puppeteer-core librairie légère, fonctionne avec n’importe quel navigateur qui base sur le
protocole DevTools sans installer Chromium
• puppeteer librairie installant Chromium
> npm install puppeteer-core
> npm install puppeteer
Tester Puppeteer
• avec Puppeteer Sandbox
1. Visiter un site headless
• Visiter un site en mode headless
• Résultat : pas d’affichage car Puppeteer est headless = sans UI
const puppeteer = require('puppeteer');
puppeteer.launch({headless:true}).then(async nav => {
const page = await nav.newPage();
await page.setViewport({ width: 1280, height: 800 })
await page.goto('https://www.lemonde.fr');
await nav.close();
});
visitersite.js
2. Visiter un site
• Visiter un site en mode headless activé
• Résultat : le navigateur Chrome s’ouvre, lance https://www.lemonde.fr dans un onglet puis
se referme
const puppeteer = require('puppeteer');
puppeteer.launch({headless:false}).then(async nav => {
const page = await nav.newPage();
await page.setViewport({ width: 1280, height: 800 })
await page.goto('https://www.lemonde.fr');
await nav.close();
});
visitersiteheadlessfalse.js
3. Capturer toute la page
• l’option fullPage permet de capturer toute la page :
• Résultat : Capture de la page / bugue parfois
const puppeteer = require('puppeteer');
puppeteer.launch().then(async nav => {
const page = await nav.newPage();
await page.setViewport({ width: 1280, height: 800 })
await page.goto('http://news.google.fr/news');
await page.screenshot({
path: 'googlenews.png', fullPage: true
});
await nav.close();
})
capturer-toute-la-page.js
4. Émuler et capturer sur iPhone
• Installer la librairie puppeteer/DeviceDescriptors pour émuler un
terminal à choisir dans la liste
• Résultat : Capture de la page / bugue parfois
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhonex = devices['iPhone X']; puppeteer.launch().then(async nav => {
const page = await nav.newPage();
//On utilise page.emulate donc inutile de définir le viewport
await page.emulate(iPhonex);
await page.goto('https://www.nytimes.com/');
await page.screenshot({ path: 'nytimes-iphoneX.png' });
await nav.close();
});
emuleriphone.js
5. Capturer le header
• Installer la librairie puppeteer/DeviceDescriptors pour émuler un
terminal à choisir dans la liste
• Résultat :
const puppeteer = require('puppeteer');
const options = { path:'nytimesheader.png',fullPage:false,clip:{ x:0,y:280,width:1280,height:150} };
puppeteer.launch().then(async nav => {
const page = await nav.newPage();
await page.setViewport({ width: 1280, height: 800
})
await page.goto('https://www.nytimes.com');
await page.screenshot(options);
await nav.close();
});
headerscreenshotpdf.js
6. Bloquer les images
• Capturer Google News sans les images
• Résultat : ci-contre
const puppeteer = require('puppeteer'); (async () => {
const nav = await puppeteer.launch();
const page = await nav.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
if (request.resourceType() === 'image')
request.abort();
else
request.continue();
});
await page.goto('https://news.google.fr/news/');
await page.screenshot({path: 'news.png', fullPage: true});
await nav.close();
})();
block-images.js
7. Récupérer le <title> d’une page
• Résultat : ci-contre
const puppeteer = require('puppeteer');
puppeteer.launch().then(async nav => {
const page = await nav.newPage();
await page.goto('https://www.nytimes.com');
const title = await page.title()
console.log(title)
await nav.close();
});
title.js
8. Saisie au clavier
• Saisir une requête dans la zone de recherche Google.fr
keyboard.png contient une impression de
l’émulation mobile du nytimes.com
• Résultat : ci-contre
clavier.js
const puppeteer = require('puppeteer');
(async () => { const browser = await puppeteer.launch();
const page = await browser.newPage()
await page.goto('https://trix-editor.org/’)
await page.focus('trix-editor’)
await page.keyboard.type("J'ajoute un titre ici avec Puppeteer via : ")
await page.screenshot({
path: 'keyboard.png’
})
await browser.close()
console.log("saisie au clavier");
})();
8. Saisie au clavier
• Saisir une requête dans la zone de recherche Google.fr
keyboard.png contient une impression de l’émulation
mobile du nytimes.com
• Résultat : ci-contre
saisieclavier.js
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhonex = devices['iPhone X']; (async () => {
const nav = await puppeteer.launch()
const page = await nav.newPage()
await page.emulate(iPhonex);
await page.goto('https://www.google.fr')
await page.focus('#tsf > div:nth-child(2) > div.A7Yvie.emca > div.zGVn2e > div > div.a4bIc > input')
await page.keyboard.type('newyork times');
await page.screenshot({ path: 'keyboard.png' })
await nav.close()
})()
9. Récupérer les liens d’un site
const puppeteer = require("puppeteer");
// on utilise async/await donc on a besoin d’une fonction async à lancer
const lancer = async () => { // ouvrir le navigateur et préparer une page
const nav = await puppeteer.launch();
const page = await nav.newPage(); // ouvrir la page à scraper
await page.goto(‘https://news.ycombinator.com’);
// exécuter le JS dans le contexte de la page pour obtenir tous les liens
depuis la collections de nœuds Nodelist
const liens = await page.evaluate(() =>
// récupérer les liens dans un tableau depuis NodeList
Array.from(document.querySelectorAll("a")).map(anchor => [anchor.href,
anchor.textContent])
);
// afficher les liens
console.log(liens);
await nav.close();
};
// lancer la fonction asynchrone
lancer();
Liens-du-site.js
10. Compter les liens d’un site
const puppeteer = require('puppeteer')
async function compter () {
const nav = await puppeteer.launch()
const page = await nav.newPage()
await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'})
await page.evaluate(_ => {
window.scrollBy(0, window.innerHeight)
})
console.log('Combien de liens de classe storylink ?', (await page.$$('a.storylink')).length)
await nav.close()
}
compter()
compter.js
11. Scrapper des liens d’un site
const puppeteer = require('puppeteer'); (async () => {
const nav = await puppeteer.launch();
const page = await nav.newPage();
await page.setExtraHTTPHeaders({Referer: 'https://news.ycombinator.com'})
await page.goto('https://news.ycombinator.com');
await page.waitForSelector('td.title > a');
const news = await page.evaluate(() => {
const liens =Array.from(document.querySelectorAll('td.title > a'))
return liens.map(link => link.href).slice(0, 10)
})
console.log(news);
await nav.close();
})();
Les 10 premiers liens de news.ycombinator.com
Scrapper-liens.js
puppeteer/examples/crawlsite.js crawle une SPA, app monopage, et crée :
• une arborescence du résultat dans ./output/<site slug>/crawl.json.
• en option : captures d'écran de chaque page visitée --screenshots
12. Crawler un site en JS
...
const fs = require('fs');
const del = require('del');
const util = require('util');
const puppeteer = require('puppeteer');
const sharp = require('sharp');
const URL= process.env.URL|| 'https://news.polymer-project.org/';
const SCREENSHOTS = process.argv.includes('--screenshots');
...
Crawler_site.js
puppeteer/examples/crawlsite.js crawle une SPA,
app monopage, et crée :
• une arborescence du résultat dans
./output/<site slug>/crawl.json.
• en option : captures d'écran de chaque page
visitée --screenshots
12. Crawler un site en JS
...
const fs = require('fs');
const del = require('del');
const util = require('util');
const puppeteer = require('puppeteer');
const sharp = require('sharp');
const URL = process.env.URL || 'https://news.polymer-project.org/';
const SCREENSHOTS = process.argv.includes('--screenshots');
...
puppeteer/examples/codecoverage.js pour mesurer le code coverage CSS/JS.
Exemple : vérifier si la stratégie de lazy loading est payante
• Installer les packages manquants : npm i chalk cli-table
• Lancer : node code_coverage.js
13. Code coverage
const puppeteer = require('puppeteer');
const chalk = require('chalk');
constTable = require('cli-table');
const URL= process.env.URL|| 'https://www.chromestatus.com/features';
13. Code coverage
Puppeteer peut :
• Visiter un site (headless ou non)
• Prendre une impression d’écran (img / pdf)
• Émuler et capturer la page sur mobile
• Capturer le header
• Bloquer les images
• Récupérer le titre d’une page <title>
• Saisie au clavier
• Scraper / Compter des liens d’un site
• Crawler un site en JS (SPA)
Puppeteer Recorder
Extension Chrome open source qui enregistre les interactions de votre navigateur
et génère un script Puppeteer.
• Ajoute waitForNavigation, setViewPort et d'autres clauses utiles.
• Génère un script Puppeteer prêt à être copié / collé.
• Indique les événements en cours d'enregistrement.
• Propose des options de configuration pour modifier le code généré.
• Utilisez-le pour créer des vérifications de navigateur Checkly sans écrire de code.
• Plugin Chrome Puppeteer Recorder
Surveillez avec Checkly !
• Site officiel de Checkly.
● plus de panier cassé…
● plus d’API cassées
Surveillez avec Checkly !
● plus de panier cassé
● plus d’API cassées…
Surveillez avec Checkly !
• Puppeteer-firefox est un projet expérimental supporté à 89%.
• Il automatise Firefox avec la même API Node.js que pour Chrome.
• Talk: https://youtu.be/MbnATLCuKI4
• https://www.npmjs.com/package/puppeteer-firefox
• Tweet de lancement
• Voir les fonctions supportées
Et pour Firefox ?
• Dans la console :
Visiter un site headless
// Seul l’import change !
const puppeteer = require('puppeteer-firefox');
(async () => {
const nav = await puppeteer.launch();
console.info(nav);
await nav.close();
})();
• à installer sur l’hébergement
• https://github.com/nesk/puphpeteer
Un équivalent en PHP :
Puphpeteer
Les bots
Crawlers
Analyse le contenu
tel que vous le voyez
pour indexer des pages
Crawler
Googlebot est evergreen
Googlebot utilise Chrome headless
Googlebot limite ses ressources
Temps sur la page / CPU
Googlebot suit le robots.txt
Robots.txt
Univers vs. Web
1,234 milliard
1,391 million 130 000 milliard12 742 km
139 820
Crawlers
Les moteurs crawlent
de plus en plus de JavaScript
et vont s’améliorer avec
l’évolution des navigateurs
Crawler
Comment Googlebot crawle le JS ?
En attente
d’exécution
du JS…
Parse
HTML
1. Crawl non JS
indexation
2. Crawl JS
Googlebot et Parsing HTML
Googlebot parse le HTML
• DCL sans JS : en 1 584 ms
Googlebot et Parsing HTML
Googlebot parse le HTML
• DCL avec JS : en 2 811 ms
• Onload avec JS : en 3 342 ms
• Plus de CPU consommé
CSR vs SSR
Escaped fragment (2009 - 2015)
• Hashbang #! dans les URL de l’app AJAX
example.com/#!slug-vue
• Moteur de rendu (navigateur headless)
pour générer des snapshots HTML
• URL spécifiques (paramètre
_escaped_fragment_) pour mapper les
snapshots HTML aux URL hashbang :
example.com/?_escaped_fragment_=s
lug-vue
Méthode pour “crawler les sites en AJAX” proposée par Google
Navigateur Crawler
App JS
Requête
HTTP URL
hashbang
Serveur Web
Requête
HTTP URL
escaped
fragment
Snapshot
HTML
Extrait et
suit les
liens
“Headless browser”
⇨ Google crawle les URL _escaped_fragment_ et indexe leur contenu à la place des URL hashbang.
Dynamic Rendering
• Utilisation d’URL standard dans l’application
full JS : example.com/slug-page
• Moteur de rendu (navigateur headless) pour
générer des snapshots HTML
• Détection du User Agent pour servir
dynamiquement l’appli JS “client-side” aux
navigateurs classiques ou un snapshot HTML
aux moteurs de recherche
• URL uniques
• Performance optimale :
– Pages HTML relativement légères pour les bots
– Web app rapide pour les utilisateurs
• Mise en place du moteur de rendu
• Gestion du cache / rafraîchissement des
snapshots
Snapshots HTML pour les bots / Web app JS pour les utilisateurs
Navigateur Crawler
App JS
Serveur Web
Snapshot
HTML
Extrait et
suit les
liens
“Headless browser”
Requête HTTP
URL standard
⇨ Les bots voient des pages HTML complètes prêtes à l’indexation.
⇨ Les utilisateurs voient l’appli JS classique (HTML + JS côté client).
Server-Side Rendering
• Utilisation d’URL standard dans
l’application full JS : example.com/slug-
page
• Exécution du JS et génération du HTML
sur le serveur Node (Next.js pour React,
Nuxt.js pour Vue.js, Universal pour
Angular)
• Envoi d’une page HTML complète à tous
les visiteurs
• Du JS côté client peut enrichir ces pages
pour ajouter des éléments de
personnalisation et fluidifier l’UX pour
les Utilisateurs
HTML pour tous / surcouche JS optionnelle pour les utilisateurs
Navigateur / Crawler
Serveur Web
HTML
Extrait et
suit les
liens
Module de SSR
App
JS
Requête HTTP
URL “standard”
Server-Side Rendering
Stratégie à adapter selon le site
• Génération de pages
HTML statiques au
moment du build
• adapté aux sites
statiques avec peu
d’interactivité
• Personnalisation, UX
• Les pages HTML sont
générées à la
demande
• puis sont reprises en
charge par JavaScript
dans le navigateur
• Complexe mais
stratégie qui existe
Static SSR SSR avec
réhydratation
SSR en streaming avec
réhydratation
progressive
01 02 03
Side by Side
Pageload
Comparer Temps de chargement - CSR vs SSR
A QUOI CA SERT ?
Visualiser le chargement d’une ou plusieurs URL
dans le navigateur.
Comparaison côte à côte
Les pages se lancent côte à côte
Centrer sur l’écran
Des options permettent de centrer la
fenêtre sur l’écran
Commande
Mobile / Bande passante
Emule le mobile et la bascule de
CPU/Limitation de bande passante
01
02
03
> node side-by-side-pageload.js -h
Client Side Rendering Server Side Rendering
CSR
devwebfeed.appspot.com
SSR
devwebfeed.appspot.com/ssr
Exécution de JavaScript côté client (navigateur) via un framework
JavaScript.
Lorsque la page est demandée, le HTML est livré au navigateur
et rendu en amont, JS et CSS déjà exécutés.
Temps de chargement
69%
Temps de chargement
75%
Comparer Temps de chargement - CSR vs SSR
Nombre de résultats Google Images
Autre idée d’utilisation avec Puppeteer :
• Avec le user agent Googlebot, le nombre de résultats est affiché dans Google Images.
Et pour un site donné via un site:example.com.
• Comparer le poids des images récupérées pour les comparer aux concurrents...
Rendertron
• Rendertron est une solution de rendering avec un Chrome Headless, pour sérialiser
des pages web à la volée.
• Démo : https://render-tron.appspot.com
● 🔨 Construit avec Puppeteer
● ☁️ Facile à déployer vers Google Cloud
● 🔍 Permet de vérifier si le rendu est ok pour le SEO
Qu’est-ce que Rendertron ?
• Comment ? middleware.
Pour quoi ? contenu correct à fournir
Quand ? bot n’interprète pas le JavaScript.
Rendertron : serveur HTTP autonome.
● requête par proxy du middleware.
● affiche les pages via Headless Chrome :
○ détecte le chargement de la PWA
○ sérialise la réponse à la demande d'origine.
● compatible technologies côté client et composants Web.
Comment ça marche ?
Express.Js
Rendertron-
middleware
Installer Rendertron-middleware
• dans votre éditeur habituel :
• Résultat :
> npm install --save express rendertron-middleware
App avec Express & Rendertron-middleware
Configurer la liste de robots
Rendertron utilise l'en-tête HTTP "user-agent" pour déterminer si la requête provient d'un
robot ou du navigateur d'un utilisateur.
Il compare ces requêtes à une liste complète d'user-agents de robots.
Par défaut, cette liste n'inclut pas Googlebot, car il peut exécuter JavaScript. Pour que
Rendertron affiche également les requêtes Googlebot, il faut ajouter Googlebot à liste des
user-agents :
Rendertron comparera l'en-tête "user-agent" à cette expression régulière.
const BOTS = rendertron.botUserAgents.concat('googlebot');
const BOT_UA_PATTERN = new RegExp(BOTS.join('|’),'i’);
Tester avec Rendertron & GCP
• Le tutoriel Rendertron par Martin Splitt Mr JavaScript chez Google :
– https://webmaster-fr.googleblog.com/2019/01/affichage-dynamique-rendertron.html
• Quels sont les sites qui devraient utiliser
l'affichage dynamique ?
• Comment l'affichage dynamique fonctionne-t-il ?
• Exemple d'application Web
• Configurer le serveur
• Déployer une instance Rendertron
• Ajouter Rendertron au serveur
• Configurer la liste de robots
• Ajouter le middleware
• Tester la configuration
• Conclusion
Pupperender
Puppetron
Merci !
Des questions ?
Audrey Schoonwater
@witamine
mattdixon.co.uk

Más contenido relacionado

La actualidad más candente

CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeadsRNS
 
GWT : under the hood
GWT : under the hoodGWT : under the hood
GWT : under the hoodsvuillet
 
A la découverte de docker
A la découverte de dockerA la découverte de docker
A la découverte de dockerjean pasqualini
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinLudovic Piot
 
Docker Tours Meetup #1 - Introduction à Docker
Docker Tours Meetup #1 - Introduction à DockerDocker Tours Meetup #1 - Introduction à Docker
Docker Tours Meetup #1 - Introduction à DockerThibaut Marmin
 
10 astuces pour améliorer les performances de son application AngularJS - ng...
10 astuces pour améliorer les performances de son application AngularJS - ng...10 astuces pour améliorer les performances de son application AngularJS - ng...
10 astuces pour améliorer les performances de son application AngularJS - ng...Jonathan Meiss
 
TP Git avancé DevoxxFR 2018 (exercices)
TP Git avancé DevoxxFR 2018 (exercices)TP Git avancé DevoxxFR 2018 (exercices)
TP Git avancé DevoxxFR 2018 (exercices)Jérôme Tamborini
 
SonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudson
SonarQube Manuel Automatisation d'analyse ANT JENKINS/HudsonSonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudson
SonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudsonxmacina
 
Tableau de bord Yammer sous SharePoint 2013
Tableau de bord Yammer sous SharePoint 2013Tableau de bord Yammer sous SharePoint 2013
Tableau de bord Yammer sous SharePoint 2013Philippe Sfeir
 
Présentation jQuery pour débutant
Présentation jQuery pour débutantPrésentation jQuery pour débutant
Présentation jQuery pour débutantStanislas Chollet
 
Partie1 TypeScript
Partie1 TypeScriptPartie1 TypeScript
Partie1 TypeScriptHabib Ayad
 

La actualidad más candente (12)

CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
 
GWT : under the hood
GWT : under the hoodGWT : under the hood
GWT : under the hood
 
A la découverte de docker
A la découverte de dockerA la découverte de docker
A la découverte de docker
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
 
Docker@linuq
Docker@linuqDocker@linuq
Docker@linuq
 
Docker Tours Meetup #1 - Introduction à Docker
Docker Tours Meetup #1 - Introduction à DockerDocker Tours Meetup #1 - Introduction à Docker
Docker Tours Meetup #1 - Introduction à Docker
 
10 astuces pour améliorer les performances de son application AngularJS - ng...
10 astuces pour améliorer les performances de son application AngularJS - ng...10 astuces pour améliorer les performances de son application AngularJS - ng...
10 astuces pour améliorer les performances de son application AngularJS - ng...
 
TP Git avancé DevoxxFR 2018 (exercices)
TP Git avancé DevoxxFR 2018 (exercices)TP Git avancé DevoxxFR 2018 (exercices)
TP Git avancé DevoxxFR 2018 (exercices)
 
SonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudson
SonarQube Manuel Automatisation d'analyse ANT JENKINS/HudsonSonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudson
SonarQube Manuel Automatisation d'analyse ANT JENKINS/Hudson
 
Tableau de bord Yammer sous SharePoint 2013
Tableau de bord Yammer sous SharePoint 2013Tableau de bord Yammer sous SharePoint 2013
Tableau de bord Yammer sous SharePoint 2013
 
Présentation jQuery pour débutant
Présentation jQuery pour débutantPrésentation jQuery pour débutant
Présentation jQuery pour débutant
 
Partie1 TypeScript
Partie1 TypeScriptPartie1 TypeScript
Partie1 TypeScript
 

Similar a Initiation à Puppeteer et Rendertron en action

Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mareValtech
 
Mettez du temps réel dans votre Drupal avec Node JS
Mettez du temps réel dans votre Drupal avec Node JSMettez du temps réel dans votre Drupal avec Node JS
Mettez du temps réel dans votre Drupal avec Node JSMatthieu Guillermin
 
Création d’application facile en html via node-webkit
Création d’application facile en html via node-webkitCréation d’application facile en html via node-webkit
Création d’application facile en html via node-webkitIsenDev
 
Développer sereinement avec Node.js
Développer sereinement avec Node.jsDévelopper sereinement avec Node.js
Développer sereinement avec Node.jsJulien Giovaresco
 
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015Stéphane ESCANDELL
 
AngularJS et autres techno frontend
AngularJS et autres techno frontendAngularJS et autres techno frontend
AngularJS et autres techno frontendyllieth
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsHugo Hamon
 
A la découverte de vue.js
A la découverte de vue.jsA la découverte de vue.js
A la découverte de vue.jsBruno Bonnin
 
Développer une application android en 2015
Développer une application android  en 2015Développer une application android  en 2015
Développer une application android en 2015Florent Champigny
 
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !vincent aniort
 
Bootcamp d'Initiation à Android - 2013/11/30 - Live coding : Hello world!
Bootcamp d'Initiation à Android  - 2013/11/30 - Live coding :   Hello world!Bootcamp d'Initiation à Android  - 2013/11/30 - Live coding :   Hello world!
Bootcamp d'Initiation à Android - 2013/11/30 - Live coding : Hello world!Horacio Gonzalez
 
Cobalt chez Orange Lannion, 2015
Cobalt chez Orange Lannion, 2015Cobalt chez Orange Lannion, 2015
Cobalt chez Orange Lannion, 2015Cobaltians
 
Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: AngularHabib Ayad
 
Symfony with angular.pptx
Symfony with angular.pptxSymfony with angular.pptx
Symfony with angular.pptxEsokia
 
2014.12.11 - TECH CONF #3 - Présentation Node.js
2014.12.11 - TECH CONF #3 - Présentation Node.js2014.12.11 - TECH CONF #3 - Présentation Node.js
2014.12.11 - TECH CONF #3 - Présentation Node.jsTelecomValley
 
Autour de Node.js - TechConf#3
Autour de Node.js - TechConf#3Autour de Node.js - TechConf#3
Autour de Node.js - TechConf#3Luc Juggery
 

Similar a Initiation à Puppeteer et Rendertron en action (20)

Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
Mettez du temps réel dans votre Drupal avec Node JS
Mettez du temps réel dans votre Drupal avec Node JSMettez du temps réel dans votre Drupal avec Node JS
Mettez du temps réel dans votre Drupal avec Node JS
 
Création d’application facile en html via node-webkit
Création d’application facile en html via node-webkitCréation d’application facile en html via node-webkit
Création d’application facile en html via node-webkit
 
Vert.x 3
Vert.x 3Vert.x 3
Vert.x 3
 
Développer sereinement avec Node.js
Développer sereinement avec Node.jsDévelopper sereinement avec Node.js
Développer sereinement avec Node.js
 
Support NodeJS avec TypeScript Express MongoDB
Support NodeJS avec TypeScript Express MongoDBSupport NodeJS avec TypeScript Express MongoDB
Support NodeJS avec TypeScript Express MongoDB
 
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015
NodeJS et SocketIO en mode scalable dans le Cloud - GAB 2015
 
Johnny-Five : Robotique et IoT en JavaScript
Johnny-Five : Robotique et IoT en JavaScriptJohnny-Five : Robotique et IoT en JavaScript
Johnny-Five : Robotique et IoT en JavaScript
 
AngularJS et autres techno frontend
AngularJS et autres techno frontendAngularJS et autres techno frontend
AngularJS et autres techno frontend
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
A la découverte de vue.js
A la découverte de vue.jsA la découverte de vue.js
A la découverte de vue.js
 
Développer une application android en 2015
Développer une application android  en 2015Développer une application android  en 2015
Développer une application android en 2015
 
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !
Node, Grunt et leurs copains qui font de l’accessibilité tout seuls !
 
Bootcamp d'Initiation à Android - 2013/11/30 - Live coding : Hello world!
Bootcamp d'Initiation à Android  - 2013/11/30 - Live coding :   Hello world!Bootcamp d'Initiation à Android  - 2013/11/30 - Live coding :   Hello world!
Bootcamp d'Initiation à Android - 2013/11/30 - Live coding : Hello world!
 
Cobalt chez Orange Lannion, 2015
Cobalt chez Orange Lannion, 2015Cobalt chez Orange Lannion, 2015
Cobalt chez Orange Lannion, 2015
 
Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: Angular
 
NodeJs in real life
NodeJs in real lifeNodeJs in real life
NodeJs in real life
 
Symfony with angular.pptx
Symfony with angular.pptxSymfony with angular.pptx
Symfony with angular.pptx
 
2014.12.11 - TECH CONF #3 - Présentation Node.js
2014.12.11 - TECH CONF #3 - Présentation Node.js2014.12.11 - TECH CONF #3 - Présentation Node.js
2014.12.11 - TECH CONF #3 - Présentation Node.js
 
Autour de Node.js - TechConf#3
Autour de Node.js - TechConf#3Autour de Node.js - TechConf#3
Autour de Node.js - TechConf#3
 

Initiation à Puppeteer et Rendertron en action

  • 1. Initiation à Puppeteer et Rendertron Audrey Schoonwater @witamine
  • 2. Sommaire 01 02 Node.js Puppeteer Plateforme de développement Librairie Node.js 03 Rendertron Développé avec Puppeteer
  • 4. Node.js en bref But : Plateforme rendre le JavaScript côté serveur pour les robots ● Depuis 2009 ● Développer des applications JavaScript (moteur JS v8 de Chrome) ● Permet d'exécuter du JavaScript très bas niveau et côté serveur.
  • 5. Après l’install Node.js Le dossier de “nodejs” contient : ● Exécuteur node.exe ● Module npm (Node Package Manager) : ajouter / retirer des librairies ● Variables d'environnements pour exécuter les commandes node et npm dans l’invite de commande.
  • 6. Hello World ! 1/2 Créer un dossier pour les projets node.js : C:nodejs 1. Créer helloworld.js 2. Coller le code suivant : 1. Exécuter le programme 1 // écrit dans la console "Hello World !" 2 console.log("Hello World !");
  • 7. Hello World ! 2/2 Créer le fichier server.js avec le code suivant 1 const { createServer } = require('http'); // Librairie HTTP native 2 //Création du serveur 3 const server = createServer((request, response) => { 4 response.writeHead(200, {'Content-Type': 'text/plain'}); 5 response.end('Hello Worldn'); 6 }); 7 server.listen(3000, () => console.log(`Adresse serveur : http://localhost:3000`));
  • 8.
  • 9. Prérequis De quoi a-t-on besoin pour utiliser Puppeteer ? ● Lignes de commande Connaissance basique ● JavaScript Plateforme Node.js ● DOM Document Object Model Connaissance basique
  • 10. Qu’est-ce que Puppeteer ? ● Librairie développée par Google en 2017 ● Elle contrôle une instance du navigateur Chrome ou Chromium via le protocole DevTools. ● Cette instance peut être headless ou non, c’est-à-dire un navigateur sans interface utilisateur. ● Il permet à un programme de lire et d’interagir avec lui.
  • 11. Qu'est-il possible de faire avec Puppeteer ? Tout de qu'on peut faire avec un navigateur : ● afficher une page ● cliquer sur un bouton ● remplir un formulaire etc.
  • 12. Installer Puppeteer • puppeteer-core librairie légère, fonctionne avec n’importe quel navigateur qui base sur le protocole DevTools sans installer Chromium • puppeteer librairie installant Chromium > npm install puppeteer-core > npm install puppeteer
  • 13. Tester Puppeteer • avec Puppeteer Sandbox
  • 14. 1. Visiter un site headless • Visiter un site en mode headless • Résultat : pas d’affichage car Puppeteer est headless = sans UI const puppeteer = require('puppeteer'); puppeteer.launch({headless:true}).then(async nav => { const page = await nav.newPage(); await page.setViewport({ width: 1280, height: 800 }) await page.goto('https://www.lemonde.fr'); await nav.close(); }); visitersite.js
  • 15. 2. Visiter un site • Visiter un site en mode headless activé • Résultat : le navigateur Chrome s’ouvre, lance https://www.lemonde.fr dans un onglet puis se referme const puppeteer = require('puppeteer'); puppeteer.launch({headless:false}).then(async nav => { const page = await nav.newPage(); await page.setViewport({ width: 1280, height: 800 }) await page.goto('https://www.lemonde.fr'); await nav.close(); }); visitersiteheadlessfalse.js
  • 16. 3. Capturer toute la page • l’option fullPage permet de capturer toute la page : • Résultat : Capture de la page / bugue parfois const puppeteer = require('puppeteer'); puppeteer.launch().then(async nav => { const page = await nav.newPage(); await page.setViewport({ width: 1280, height: 800 }) await page.goto('http://news.google.fr/news'); await page.screenshot({ path: 'googlenews.png', fullPage: true }); await nav.close(); }) capturer-toute-la-page.js
  • 17. 4. Émuler et capturer sur iPhone • Installer la librairie puppeteer/DeviceDescriptors pour émuler un terminal à choisir dans la liste • Résultat : Capture de la page / bugue parfois const puppeteer = require('puppeteer'); const devices = require('puppeteer/DeviceDescriptors'); const iPhonex = devices['iPhone X']; puppeteer.launch().then(async nav => { const page = await nav.newPage(); //On utilise page.emulate donc inutile de définir le viewport await page.emulate(iPhonex); await page.goto('https://www.nytimes.com/'); await page.screenshot({ path: 'nytimes-iphoneX.png' }); await nav.close(); }); emuleriphone.js
  • 18. 5. Capturer le header • Installer la librairie puppeteer/DeviceDescriptors pour émuler un terminal à choisir dans la liste • Résultat : const puppeteer = require('puppeteer'); const options = { path:'nytimesheader.png',fullPage:false,clip:{ x:0,y:280,width:1280,height:150} }; puppeteer.launch().then(async nav => { const page = await nav.newPage(); await page.setViewport({ width: 1280, height: 800 }) await page.goto('https://www.nytimes.com'); await page.screenshot(options); await nav.close(); }); headerscreenshotpdf.js
  • 19. 6. Bloquer les images • Capturer Google News sans les images • Résultat : ci-contre const puppeteer = require('puppeteer'); (async () => { const nav = await puppeteer.launch(); const page = await nav.newPage(); await page.setRequestInterception(true); page.on('request', request => { if (request.resourceType() === 'image') request.abort(); else request.continue(); }); await page.goto('https://news.google.fr/news/'); await page.screenshot({path: 'news.png', fullPage: true}); await nav.close(); })(); block-images.js
  • 20. 7. Récupérer le <title> d’une page • Résultat : ci-contre const puppeteer = require('puppeteer'); puppeteer.launch().then(async nav => { const page = await nav.newPage(); await page.goto('https://www.nytimes.com'); const title = await page.title() console.log(title) await nav.close(); }); title.js
  • 21. 8. Saisie au clavier • Saisir une requête dans la zone de recherche Google.fr keyboard.png contient une impression de l’émulation mobile du nytimes.com • Résultat : ci-contre clavier.js const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage() await page.goto('https://trix-editor.org/’) await page.focus('trix-editor’) await page.keyboard.type("J'ajoute un titre ici avec Puppeteer via : ") await page.screenshot({ path: 'keyboard.png’ }) await browser.close() console.log("saisie au clavier"); })();
  • 22. 8. Saisie au clavier • Saisir une requête dans la zone de recherche Google.fr keyboard.png contient une impression de l’émulation mobile du nytimes.com • Résultat : ci-contre saisieclavier.js const puppeteer = require('puppeteer'); const devices = require('puppeteer/DeviceDescriptors'); const iPhonex = devices['iPhone X']; (async () => { const nav = await puppeteer.launch() const page = await nav.newPage() await page.emulate(iPhonex); await page.goto('https://www.google.fr') await page.focus('#tsf > div:nth-child(2) > div.A7Yvie.emca > div.zGVn2e > div > div.a4bIc > input') await page.keyboard.type('newyork times'); await page.screenshot({ path: 'keyboard.png' }) await nav.close() })()
  • 23. 9. Récupérer les liens d’un site const puppeteer = require("puppeteer"); // on utilise async/await donc on a besoin d’une fonction async à lancer const lancer = async () => { // ouvrir le navigateur et préparer une page const nav = await puppeteer.launch(); const page = await nav.newPage(); // ouvrir la page à scraper await page.goto(‘https://news.ycombinator.com’); // exécuter le JS dans le contexte de la page pour obtenir tous les liens depuis la collections de nœuds Nodelist const liens = await page.evaluate(() => // récupérer les liens dans un tableau depuis NodeList Array.from(document.querySelectorAll("a")).map(anchor => [anchor.href, anchor.textContent]) ); // afficher les liens console.log(liens); await nav.close(); }; // lancer la fonction asynchrone lancer(); Liens-du-site.js
  • 24. 10. Compter les liens d’un site const puppeteer = require('puppeteer') async function compter () { const nav = await puppeteer.launch() const page = await nav.newPage() await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'}) await page.evaluate(_ => { window.scrollBy(0, window.innerHeight) }) console.log('Combien de liens de classe storylink ?', (await page.$$('a.storylink')).length) await nav.close() } compter() compter.js
  • 25. 11. Scrapper des liens d’un site const puppeteer = require('puppeteer'); (async () => { const nav = await puppeteer.launch(); const page = await nav.newPage(); await page.setExtraHTTPHeaders({Referer: 'https://news.ycombinator.com'}) await page.goto('https://news.ycombinator.com'); await page.waitForSelector('td.title > a'); const news = await page.evaluate(() => { const liens =Array.from(document.querySelectorAll('td.title > a')) return liens.map(link => link.href).slice(0, 10) }) console.log(news); await nav.close(); })(); Les 10 premiers liens de news.ycombinator.com Scrapper-liens.js
  • 26. puppeteer/examples/crawlsite.js crawle une SPA, app monopage, et crée : • une arborescence du résultat dans ./output/<site slug>/crawl.json. • en option : captures d'écran de chaque page visitée --screenshots 12. Crawler un site en JS ... const fs = require('fs'); const del = require('del'); const util = require('util'); const puppeteer = require('puppeteer'); const sharp = require('sharp'); const URL= process.env.URL|| 'https://news.polymer-project.org/'; const SCREENSHOTS = process.argv.includes('--screenshots'); ... Crawler_site.js
  • 27. puppeteer/examples/crawlsite.js crawle une SPA, app monopage, et crée : • une arborescence du résultat dans ./output/<site slug>/crawl.json. • en option : captures d'écran de chaque page visitée --screenshots 12. Crawler un site en JS ... const fs = require('fs'); const del = require('del'); const util = require('util'); const puppeteer = require('puppeteer'); const sharp = require('sharp'); const URL = process.env.URL || 'https://news.polymer-project.org/'; const SCREENSHOTS = process.argv.includes('--screenshots'); ...
  • 28. puppeteer/examples/codecoverage.js pour mesurer le code coverage CSS/JS. Exemple : vérifier si la stratégie de lazy loading est payante • Installer les packages manquants : npm i chalk cli-table • Lancer : node code_coverage.js 13. Code coverage const puppeteer = require('puppeteer'); const chalk = require('chalk'); constTable = require('cli-table'); const URL= process.env.URL|| 'https://www.chromestatus.com/features';
  • 30. Puppeteer peut : • Visiter un site (headless ou non) • Prendre une impression d’écran (img / pdf) • Émuler et capturer la page sur mobile • Capturer le header • Bloquer les images • Récupérer le titre d’une page <title> • Saisie au clavier • Scraper / Compter des liens d’un site • Crawler un site en JS (SPA)
  • 31. Puppeteer Recorder Extension Chrome open source qui enregistre les interactions de votre navigateur et génère un script Puppeteer. • Ajoute waitForNavigation, setViewPort et d'autres clauses utiles. • Génère un script Puppeteer prêt à être copié / collé. • Indique les événements en cours d'enregistrement. • Propose des options de configuration pour modifier le code généré. • Utilisez-le pour créer des vérifications de navigateur Checkly sans écrire de code. • Plugin Chrome Puppeteer Recorder
  • 32. Surveillez avec Checkly ! • Site officiel de Checkly.
  • 33. ● plus de panier cassé… ● plus d’API cassées Surveillez avec Checkly !
  • 34. ● plus de panier cassé ● plus d’API cassées… Surveillez avec Checkly !
  • 35. • Puppeteer-firefox est un projet expérimental supporté à 89%. • Il automatise Firefox avec la même API Node.js que pour Chrome. • Talk: https://youtu.be/MbnATLCuKI4 • https://www.npmjs.com/package/puppeteer-firefox • Tweet de lancement • Voir les fonctions supportées Et pour Firefox ?
  • 36. • Dans la console : Visiter un site headless // Seul l’import change ! const puppeteer = require('puppeteer-firefox'); (async () => { const nav = await puppeteer.launch(); console.info(nav); await nav.close(); })();
  • 37. • à installer sur l’hébergement • https://github.com/nesk/puphpeteer Un équivalent en PHP : Puphpeteer
  • 39. Crawlers Analyse le contenu tel que vous le voyez pour indexer des pages Crawler
  • 42. Googlebot limite ses ressources Temps sur la page / CPU
  • 43. Googlebot suit le robots.txt Robots.txt
  • 44. Univers vs. Web 1,234 milliard 1,391 million 130 000 milliard12 742 km 139 820
  • 45. Crawlers Les moteurs crawlent de plus en plus de JavaScript et vont s’améliorer avec l’évolution des navigateurs Crawler
  • 46. Comment Googlebot crawle le JS ? En attente d’exécution du JS… Parse HTML 1. Crawl non JS indexation 2. Crawl JS
  • 47. Googlebot et Parsing HTML Googlebot parse le HTML • DCL sans JS : en 1 584 ms
  • 48. Googlebot et Parsing HTML Googlebot parse le HTML • DCL avec JS : en 2 811 ms • Onload avec JS : en 3 342 ms • Plus de CPU consommé
  • 50. Escaped fragment (2009 - 2015) • Hashbang #! dans les URL de l’app AJAX example.com/#!slug-vue • Moteur de rendu (navigateur headless) pour générer des snapshots HTML • URL spécifiques (paramètre _escaped_fragment_) pour mapper les snapshots HTML aux URL hashbang : example.com/?_escaped_fragment_=s lug-vue Méthode pour “crawler les sites en AJAX” proposée par Google Navigateur Crawler App JS Requête HTTP URL hashbang Serveur Web Requête HTTP URL escaped fragment Snapshot HTML Extrait et suit les liens “Headless browser” ⇨ Google crawle les URL _escaped_fragment_ et indexe leur contenu à la place des URL hashbang.
  • 51. Dynamic Rendering • Utilisation d’URL standard dans l’application full JS : example.com/slug-page • Moteur de rendu (navigateur headless) pour générer des snapshots HTML • Détection du User Agent pour servir dynamiquement l’appli JS “client-side” aux navigateurs classiques ou un snapshot HTML aux moteurs de recherche • URL uniques • Performance optimale : – Pages HTML relativement légères pour les bots – Web app rapide pour les utilisateurs • Mise en place du moteur de rendu • Gestion du cache / rafraîchissement des snapshots Snapshots HTML pour les bots / Web app JS pour les utilisateurs Navigateur Crawler App JS Serveur Web Snapshot HTML Extrait et suit les liens “Headless browser” Requête HTTP URL standard ⇨ Les bots voient des pages HTML complètes prêtes à l’indexation. ⇨ Les utilisateurs voient l’appli JS classique (HTML + JS côté client).
  • 52. Server-Side Rendering • Utilisation d’URL standard dans l’application full JS : example.com/slug- page • Exécution du JS et génération du HTML sur le serveur Node (Next.js pour React, Nuxt.js pour Vue.js, Universal pour Angular) • Envoi d’une page HTML complète à tous les visiteurs • Du JS côté client peut enrichir ces pages pour ajouter des éléments de personnalisation et fluidifier l’UX pour les Utilisateurs HTML pour tous / surcouche JS optionnelle pour les utilisateurs Navigateur / Crawler Serveur Web HTML Extrait et suit les liens Module de SSR App JS Requête HTTP URL “standard”
  • 53. Server-Side Rendering Stratégie à adapter selon le site • Génération de pages HTML statiques au moment du build • adapté aux sites statiques avec peu d’interactivité • Personnalisation, UX • Les pages HTML sont générées à la demande • puis sont reprises en charge par JavaScript dans le navigateur • Complexe mais stratégie qui existe Static SSR SSR avec réhydratation SSR en streaming avec réhydratation progressive 01 02 03
  • 55. Comparer Temps de chargement - CSR vs SSR A QUOI CA SERT ? Visualiser le chargement d’une ou plusieurs URL dans le navigateur. Comparaison côte à côte Les pages se lancent côte à côte Centrer sur l’écran Des options permettent de centrer la fenêtre sur l’écran Commande Mobile / Bande passante Emule le mobile et la bascule de CPU/Limitation de bande passante 01 02 03 > node side-by-side-pageload.js -h Client Side Rendering Server Side Rendering
  • 56. CSR devwebfeed.appspot.com SSR devwebfeed.appspot.com/ssr Exécution de JavaScript côté client (navigateur) via un framework JavaScript. Lorsque la page est demandée, le HTML est livré au navigateur et rendu en amont, JS et CSS déjà exécutés. Temps de chargement 69% Temps de chargement 75% Comparer Temps de chargement - CSR vs SSR
  • 57. Nombre de résultats Google Images Autre idée d’utilisation avec Puppeteer : • Avec le user agent Googlebot, le nombre de résultats est affiché dans Google Images. Et pour un site donné via un site:example.com. • Comparer le poids des images récupérées pour les comparer aux concurrents...
  • 59. • Rendertron est une solution de rendering avec un Chrome Headless, pour sérialiser des pages web à la volée. • Démo : https://render-tron.appspot.com ● 🔨 Construit avec Puppeteer ● ☁️ Facile à déployer vers Google Cloud ● 🔍 Permet de vérifier si le rendu est ok pour le SEO Qu’est-ce que Rendertron ?
  • 60. • Comment ? middleware. Pour quoi ? contenu correct à fournir Quand ? bot n’interprète pas le JavaScript. Rendertron : serveur HTTP autonome. ● requête par proxy du middleware. ● affiche les pages via Headless Chrome : ○ détecte le chargement de la PWA ○ sérialise la réponse à la demande d'origine. ● compatible technologies côté client et composants Web. Comment ça marche ?
  • 63. Installer Rendertron-middleware • dans votre éditeur habituel : • Résultat : > npm install --save express rendertron-middleware
  • 64. App avec Express & Rendertron-middleware Configurer la liste de robots Rendertron utilise l'en-tête HTTP "user-agent" pour déterminer si la requête provient d'un robot ou du navigateur d'un utilisateur. Il compare ces requêtes à une liste complète d'user-agents de robots. Par défaut, cette liste n'inclut pas Googlebot, car il peut exécuter JavaScript. Pour que Rendertron affiche également les requêtes Googlebot, il faut ajouter Googlebot à liste des user-agents : Rendertron comparera l'en-tête "user-agent" à cette expression régulière. const BOTS = rendertron.botUserAgents.concat('googlebot'); const BOT_UA_PATTERN = new RegExp(BOTS.join('|’),'i’);
  • 65. Tester avec Rendertron & GCP • Le tutoriel Rendertron par Martin Splitt Mr JavaScript chez Google : – https://webmaster-fr.googleblog.com/2019/01/affichage-dynamique-rendertron.html • Quels sont les sites qui devraient utiliser l'affichage dynamique ? • Comment l'affichage dynamique fonctionne-t-il ? • Exemple d'application Web • Configurer le serveur • Déployer une instance Rendertron • Ajouter Rendertron au serveur • Configurer la liste de robots • Ajouter le middleware • Tester la configuration • Conclusion
  • 68. Merci ! Des questions ? Audrey Schoonwater @witamine mattdixon.co.uk