Автостопом по Puppeteer

Version 42.0

Знакомство

Это Я =>

Software Engineer в

iTechArt Group.

 

Профессиональный формошлёп.

 

JavaScript-разработчик с

958-дневным стажем.

@fasvald

egorvoz@gmail.com

Как меня найти

Наш ту ду список

Обзор ту ду:

  • Что такое безголовый браузер.
  • Какие существуют безголовые браузеры и их API.
  • Какие кейсы использования.
  • Что за чудо такое, этот Puppeteer.
  • Примеры работы с Puppeteer.
  • И Т О Г И.

ВНИМАНИЕ!!!

Дальше пойдет сухая теория

Но сначала, немного истории ...

Что ты такое,

безголовый браузер ?

Это браузер без графического интерфейса.

Также:

  • он ест меньше ресурсов
  • его легко поставить на сервер
    (не требует графической оболочки)
  • его можно запустить через CLI
  • им можно управлять программно
  • как бонус: быстрая скорость работы 
 

Approved by

Области применения

  • Сделать скриншот
  • Создать PDF документ
  • Различные метрики (привет Lighthouse)
  • Различные тесты (automated)
  • Data Scrapping
  • Тестирование расширений для Chrome
  • ... и многое, многое другое

Approved by

Рассмотрим примеры основных headless браузеров

Да-да, их очень много ...

PhantomJS

PhantomJS — это заскриптованный безголовый WebKit с JavaScript API.

У него есть быстрая и нативная поддержка различных веб стандартов: DOM handling, CSS selector, JSON, Canvas, и SVG.

Поддерживаемые языки:

JavaScript, Python, Ruby, Java, C#, Haskell, Objective-C, Perl, PHP, R (через Selenium).

Статус: RIP.

Nightmare

Nightmare — это высокоуровневая библиотека для работы с автоматизацией в браузере, созданная как более простая версия PhatomJS. Работает на Electron.
 

Поддерживаемые языки:

 JavaScript.

 

Статус: Жив. Здоров. Развивается.

SlimerJS

SlimerJS похож на PhantomJs, только использует движок Gecko (Mozilla Firefox) вместо WebKit .

(И это еще он не по-настоящему безголовый).

 

Поддерживаемые языки: 

 JavaScript

Статус: Сейчас Жив и Здоров. По слухам скоро RIP.

Итак.

Ты используешь

Internet Explorer.

trifleJS

Поддерживаемые языки:

 JavaScript

Статус: RIP.

Безголовый Internet Explorer, который использует .NET WebBrowser Class & JavaScript API с движком V8 на борту.

Headless Chrome

Активируется через флаг

--headless либо с помощью Node.JS или C++ библиотек.

Поддерживаемые языки: 

 JavaScript, C++.

Статус: Жив. Здоров. Развивается.

chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/

# Size of a standard letterhead.
chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://www.chromestatus.com/

# Nexus 5x
chrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/

Headless Firefox

Статус: Жив. Здоров. Развивается.

Принцип работы такой же, как и у Headless Chrome.

Активируется пока только через флаг --headless либо через Selenium.

Поддерживаемые языки: 

 JavaScript, Java, Python (через Selenium).

/path/to/firefox -headless -screenshot https://developer.mozilla.com

/path/to/firefox -screenshot test.jpg  https://developer.mozilla.com --window-size=800,1000

Headless Safari

Headless режим отсутствует.

 

Есть вариант использования через веб драйвер chromedp.

Статус: NaN.

Поддерживаемые языки: 

 NaN.

Headless Edge

Поддерживаемые языки: 

 NaN.

Headless режим отсутствует.

 

Есть вариант использования через веб драйвер chromedp.

 

Пока релизнулся

Microsoft Edge DevTools Protocol.

Статус: NaN.

HEADLESS

А теперь поговорим про безголовый Chrome

Puppeteer

Puppeteer (Кукловод) — это библиотека для Node.JS которая предоставляет высокоуровневый API для контроля над безголовым хромом или хромиумом через DevTools Protocol.

 

Его также можно сконфигурировать для использование в full режиме (не безголовый режим).

npm i puppeteer

#1 Как установить  ?

или yarn add puppeteer

npm i puppeteer-core

#2 Как установить ?

или yarn add puppeteer-core

Как работает Puppeteer ?

Chrome DevTools Protocol

Chromium

Кукловод

Скрипты

для  Chrome

Как работает Puppeteer ?

Firefox DevTools Protocol (в разработке)

Gecko

Кукловод

Скрипты

для  Firefox (alpha)

Ссылка на  Firefox версию

Очень крутой и семантический API.

Рассмотрим примеры

Перед началом всегда прочтите FAQ

Сделать скриншот

 

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

const URL = 'https://github.com/';

(async () => {
  // NOTE: Puppeteer sets an initial page size to 800px x 600px, which defines the screenshot size.
  // The page size can be customized with Page.setViewport()

  const dir = './screens';

  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }

  const browser = await puppeteer.launch({
    headless: true,
    ignoreHTTPSErrors: true,
  });

  const page = await browser.newPage();

  page.setViewport({
    width: 1920,
    height: 1080,
  })

  await page.goto(URL, {
    waitUntil: ['networkidle0', 'domcontentloaded'],
    // timeout: 30000,
  });

  await page.screenshot({
    path: 'screens/example.png',
  })

  await page.screenshot({
    path: 'screens/fullpage.png',
    fullPage: true,
  })

  await browser.close();
})();

Создать PDFку

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

const URL = 'https://github.com/';

// NOTE: u can't add script tag init :) yet
const buildTemplate = (type) => {
  // If you do not need customize =>
  // https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#pagepdfoptions

  // Since version 1.2+ you can use footerTemplate & headerTemplate API

  return `
    <div style="font-size: 10px; color: red;">
      <span>${ type === 'header' ? 'HEADER' : 'FOOTER'}</span>
      <span class="date"></span> |
      <span class="title"></span> |
      <span class="url"></span> |
      <span class="pageNumber"></span> /
      <span class="totalPages"></span>
    </div>
  `;
}

(async () => {
  const dir = './pdf';

  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }

  const browser = await puppeteer.launch({
    headless: true,
    ignoreHTTPSErrors: true,
  });

  const page = await browser.newPage();

  await page.goto(URL, {
    waitUntil: ['networkidle0', 'domcontentloaded'],
    // timeout: 30000,
  });

  await page.pdf({
    path: 'pdf/document.pdf',
    displayHeaderFooter: true,
    headerTemplate: buildTemplate('header'), // new one
    footerTemplate: buildTemplate('footer'), // new one
    printBackground: true,
    landscape: false,
    // pageRanges: '1-2',
    format: 'A4',
    margin: {
      top: 100,
      right: 40,
      bottom: 100,
      left: 40,
    },
  })

  await browser.close();
})();

API

Performance +

code coverage

// ...

// Enable both JavaScript and CSS coverage
  await Promise.all([
    page.coverage.startJSCoverage(),
    page.coverage.startCSSCoverage()
  ]);

  await page.tracing.start({path: 'trace.json'});

  await page.goto(`${URL}/books/allbooks/`, {
    waitUntil: ['networkidle0', 'domcontentloaded'],
    // timeout: 30000,
  });

  // Disable both JavaScript and CSS coverage
  const [jsCoverage, cssCoverage] = await Promise.all([
    page.coverage.stopJSCoverage(),
    page.coverage.stopCSSCoverage(),
  ]);

  let totalJSBytes = 0;
  let usedJSBytes = 0;

  for (const entry of jsCoverage) {
    totalJSBytes += entry.text.length;

    for (const range of entry.ranges) {
      usedJSBytes += range.end - range.start - 1;
    }
  }

  console.log(`JS used (bytes): ${Math.round(usedJSBytes / totalJSBytes * 100)}%`);

  let totalCSSBytes = 0;
  let usedCSSBytes = 0;

  for (const entry of cssCoverage) {
    totalCSSBytes += entry.text.length;

    for (const range of entry.ranges) {
      usedCSSBytes += range.end - range.start - 1;
    }
  }

  console.log(`CSS used (bytes): ${Math.round(usedCSSBytes / totalCSSBytes * 100)}%`);

  // how it was year ago
  // https://michaljanaszek.com/blog/test-website-performance-with-puppeteer

  // for more use CDPSession => client.send(Performance API)
  const metrics = await page.metrics();
  console.log(`Page metrics: \n`, metrics);

  await page.tracing.stop();

// ...

Performance +

code coverage 2.0

const parse = require('./parse');

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

const url = `https://www.mann-ivanov-ferber.ru`;

async function launchChromeAndRunLighthouse(url, opts, config = null) {
  return chromeLauncher.launch({ chromeFlags: opts.chromeFlags }).then((chrome) => {
    opts.port = chrome.port;
    return lighthouse(url, opts, config).then((results) => {
      // use results.lhr for the JS-consumeable output
      // https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts
      // use results.report for the HTML/JSON/CSV output as a string
      // use results.artifacts for the trace/screenshots/other specific case you need (rarer)
      return chrome.kill().then(() => results);
    });
  });
}

const opts = {
  chromeFlags: ['--show-paint-rects'],
};

const runLH = async function() {
  try {
    const results = await launchChromeAndRunLighthouse(url, opts);

    const urlArtifactsRes = await parse.getMainArtifacts(results)
    const urlBasicScores = await parse.getBasicsScores(results)

    // console.log('*** Runtime info ***')
    // console.log(urlArtifactsRes.toString())

    console.log('*** Basic scores ***')
    console.log(urlBasicScores.toString())
  } catch (err) {
    console.log(err);
  }
};

runLH()

Парсинг данных

Серверный рендеринг

+

ЮАЙ Тесты

+

А что если написать сообщение в Slack ?

+

... или в Telegram

(запрещенный Роскомнадзором)

+

Эй, гугл! А есть еще примеры?

Подведем И Т О Г И

И т о г о:

  • Вы посмотрели презентацию и послушали меня.
  • Потратили 25 минут или больше  свой жизни на вот это вот.

НО

Теперь вы шарите

Полезные ссылки

Что такое безголовый браузер ?

Что такое chromedp ?

Я все. Спасибо.

Вопросики и ответики?

Автостопом по Puppeteer

By Yahor Vaziyanau

Автостопом по Puppeteer

Что делать, если нам нужно сделать из веб-страницы pdf-документ или скриншот? Или если вдруг возникла необходимость написать UI-тесты и посмотреть статистику использования CSS-селекторов и вызова JS-функций? Правильно, использовать PhantomJS. Ой. Погодите, на дворе — 2019 год. Настало время Puppeteer — Node API для «безголового» Chrome от Google!

  • 3,410