Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
WorkerConf 2021 - Browser automation with Puppe...
Search
Jecelyn Yeen
June 25, 2021
Programming
1.9k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
WorkerConf 2021 - Browser automation with Puppeteer
Jecelyn Yeen
June 25, 2021
More Decks by Jecelyn Yeen
See All by Jecelyn Yeen
My Journey as Technical Presenter
jecfish
0
1k
Becoming a GDE
jecfish
0
3.9k
How to get started in IT Freelancing
jecfish
1
300
New Web API & Stylings
jecfish
3
760
如何打造高性能且SEO友好的单页应用(SPA)
jecfish
2
920
JS SEO
jecfish
4
1.6k
Web Performance Optimization
jecfish
5
1.8k
Have Fun with Angular
jecfish
0
130
RxJs Trex
jecfish
0
710
Other Decks in Programming
See All in Programming
技術的負債解消で開発者の未来を開く- AIの力でコード刷新
kmd2kmd
0
120
Datadog LLM Observabilityで実現する 安全なLLM Usage 管理
3150
0
130
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
620
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
280
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
920
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
180
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.5k
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
150
1B+ /day規模のログを管理する技術
broadleaf
0
120
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
140
Oxlintのカスタムルールの現況
syumai
6
1.2k
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
200
Featured
See All Featured
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.6k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
400
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
150
Mobile First: as difficult as doing things right
swwweet
225
10k
Being A Developer After 40
akosma
91
590k
Leo the Paperboy
mayatellez
7
1.9k
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
410
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
950
Transcript
@JecelynYeen Developer advocate, Google @ChromeDevTools
None
My road bike
Mountain bike My road bike
Mountain bike Hiking, hot and humid My road bike
Mountain bike Hiking, hot and humid Hiking, Switzerland My road
bike
None
Browser automation with Puppeteer
PM YANG Professional developer PAUL
PM YANG I want a daily email on our server’s
internet speed. Professional developer PAUL
PM YANG I want a daily email on our server’s
internet speed. Professional developer PAUL Why does he need that?
PM YANG It’s easy. Go to fast.com on the server
and send me the screenshot.
PM YANG It’s easy. Go to fast.com on the server
and send me the screenshot. Professional developer PAUL I never said it’s hard...
None
None
Professional developer PAUL There are 2 ways to do this:
Manually 1. Login to server 2. Open a browser 3. Go to fast.com 4. Take a screenshot 5. Send email
Professional developer PAUL There are 2 ways to do this:
Manually 1. Login to server 2. Open a browser 3. Go to fast.com 4. Take a screenshot 5. Send email Automate it 1. Schedule a daily server task 2. Automate screenshot 3. Automate email sending
Professional developer PAUL Researching...
Professional developer PAUL Researching... Puppeteer
None
Browser automation library for Node.js
Control a browser with modern JavaScript API.
const puppeteer = require('puppeteer'); (async () => { })();
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); })();
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); })();
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://fast.com/'); })();
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://fast.com/'); await page.screenshot({ path: 'img/screenshot-yyyyMMdd.png' }); })();
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://fast.com/'); await page.screenshot({ path: 'img/screenshot-yyyyMMdd.png' }); await browser.close(); })();
Not working
None
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://fast.com/'); await page.waitForSelector('.speed-results-container.succeeded'); await page.screenshot({ path: 'img/screenshot-yyyyMMdd.png' }); await browser.close(); })();
Run it again
Professional developer PAUL
PM YANG Cool, it will be great if to have
date in the screenshot. Possible?
const puppeteer = require('puppeteer'); (async () => { const browser
= await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://fast.com/'); await page.waitForSelector('.speed-results-container.succeeded'); await page.$eval('#your-speed-message', (el, dt) => { el.innerText = `Internet speed as of ${dt} is`; }, 'yyyy-MM-dd')); await page.screenshot({ path: `img/screenshot-yyyyMMdd.png` }); await browser.close(); })();
PM YANG I want...
// Save as pdf, only work in headless mode await
page.pdf({ path: `doc/speed-yyyyMMdd.pdf` }); // Click to show more details await page.click('#show-more-details-link'); await page.waitForSelector('#upload-label.succeeded', { timeout: 0 }); // Emulate mobile view and save screenshot // src/common/DeviceDescriptors.ts const tablet = puppeteer.devices['iPad Mini']; await page.emulate(tablet); await page.screenshot({ path: `img/screenshot-yyyyMMdd.png` }); // Reload page await page.reload();
// Save as pdf, only work in headless mode await
page.pdf({ path: `doc/speed-yyyyMMdd.pdf` }); // Click to show more details await page.click('#show-more-details-link'); await page.waitForSelector('#upload-label.succeeded', { timeout: 0 }); // Emulate mobile view and save screenshot // src/common/DeviceDescriptors.ts const tablet = puppeteer.devices['iPad Mini']; await page.emulate(tablet); await page.screenshot({ path: `img/screenshot-yyyyMMdd.png` }); // Reload page await page.reload();
// Save as pdf, only work in headless mode await
page.pdf({ path: `doc/speed-yyyyMMdd.pdf` }); // Click to show more details await page.click('#show-more-details-link'); await page.waitForSelector('#upload-label.succeeded', { timeout: 0 }); // Emulate mobile view and save screenshot // src/common/DeviceDescriptors.ts const tablet = puppeteer.devices['iPad Mini']; await page.emulate(tablet); await page.screenshot({ path: `img/screenshot-yyyyMMdd.png` }); // Reload page await page.reload();
// Save as pdf, only work in headless mode await
page.pdf({ path: `doc/speed-yyyyMMdd.pdf` }); // Click to show more details await page.click('#show-more-details-link'); await page.waitForSelector('#upload-label.succeeded', { timeout: 0 }); // Emulate mobile view and save screenshot // src/common/DeviceDescriptors.ts const tablet = puppeteer.devices['iPad Mini']; await page.emulate(tablet); await page.screenshot({ path: `img/screenshot-yyyyMMdd.png` }); // Reload page await page.reload();
github.com/puppeteer
❤
const browser = await puppeteer.launch(); const page = await browser.newPage();
await page.goto('https://v8.dev/blog/10-years'); // Create screenshots of your web app in Light Mode and Dark Mode. // Tip: check out `npx dark-mode-screenshot` for more options! await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'light' }]); await page.screenshot({ path: 'light.png', fullPage: true }); await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]); await page.screenshot({ path: 'dark.png', fullPage: true }); await browser.close();
const browser = await puppeteer.launch(); const page = await browser.newPage();
await page.goto('https://mathiasbynens.be/demo/timezone'); page.evaluate(() => { globalThis.date = new Date(1479579154987); }); await page.emulateTimezone('America/Buenos_Aires'); console.log(await page.evaluate(() => date.toString())); // → 'Sat Nov 19 2016 15:12:34 GMT-0300 (Argentina Standard Time)' await page.emulateTimezone('Asia/Kuala_Lumpur'); console.log(await page.evaluate(() => date.toString())); // → 'Sun Nov 20 2016 02:12:34 GMT+0800 (Malaysia Time)' await browser.close();
const browser = await puppeteer.launch(); const page = await browser.newPage();
await page.goto('https://developer.chrome.com/tags/devtools/'); await page.emulateVisionDeficiency('blurredVision'); await page.screenshot({ path: 'blurred-vision.png', fullPage: true }); await page.emulateVisionDeficiency('achromatopsia'); await page.screenshot({ path: 'achromatopsia.png', fullPage: true }); await page.emulateVisionDeficiency('deuteranopia'); await page.screenshot({ path: 'deuteranopia.png', fullPage: true }); await browser.close();
addyosmani.com/blog/ puppeteer-recipes/
const browser = await puppeteer.launch();
const browser = await puppeteer.launch(); // Launch options const browser
= await puppeteer.launch({ product: 'firefox' });
const browser = await puppeteer.launch(); // Launch options const browser
= await puppeteer.launch({ product: 'firefox' }); const browser = await puppeteer.launch({ headless: false, slowMo: 3000 });
const browser = await puppeteer.launch(); // Launch options const browser
= await puppeteer.launch({ product: 'firefox' }); const browser = await puppeteer.launch({ headless: false, slowMo: 3000 }); const browser = await puppeteer.launch({ devtools: true });
goo.gle/devtools-blog
@JecelynYeen Developer advocate, Google @ChromeDevTools