Захват содержания

Захват видимого содержания — это снимок с исходным кодом видимой части окна браузера.

Mutation Observers + WebSocket

WebSockets способен передать данные в различных форматах.

Другой пример Google Отклики, но это не с открытым исходным кодом. Эти типы проектов очень сырые и ужасно медленные.

Один из подходов захвата содержания продемонстрировал Рафаэль Вайнштейн. Его методика использует наблюдение Mutation Observers и WebSocket.

По сути, используется WebSocket когда пользователь прокручивает страницу. Поэтому работает быстро. Вся страница не отправляется для каждого кадра. Это отличный способ совместить функцию платформы Mutation Observers с WebSocket.

к меню ↑

Blob from an HTMLDocument + Binary WebSocket

Следующий способ похож на подход Mutation Observers, но вместо отправки различий, он создает Blob clone all HTMLDocument и отправляет его через двоичный WebSocket.

Действия:

  1. Копирует все ссылки на странице.
  2. Клонирование элементов страницы: document.documentElement.cloneNode (TRUE);
  3. Сделать клон только для чтения без прокрутки свойствами CSS:
    pointer-events: none; 
    user-select: none; 
    overflow: hidden;
  4. Захватить текущее положение части страницы и добавить в data-*.
  5. Создать new Blob() из повторения .outerHTML.

Код для захвата выглядит так:

function screenshotPage() {
  // 1. Клонируем картинки, стили, скрипты
  urlsToAbsolute(document.images);
  urlsToAbsolute(document.querySelectorAll("link[rel='stylesheet']"));
  urlsToAbsolute(document.scripts);

  // 2. Дубликат всего дерева документа
  var screenshot = document.documentElement.cloneNode(true);

  // 3. Скриншот без прокрутки и селекторов
  screenshot.style.pointerEvents = 'none';
  screenshot.style.overflow = 'hidden';
  screenshot.style.userSelect = 'none'; // необходимо вендорные префиксы

  // 4. ... читать далее ...

  // 5. Создать новый файл HTML
  var blob = new Blob([screenshot.outerHTML], {type: 'text/html'});

  // Открыть файл в новой вкладке браузера
  window.open(window.URL.createObjectURL(blob));
  }

urlsToAbsolute () содержит простые выражения для переписывания relative/schemeless URL-адресов в абсолютные. Это необходимо чтобы изображения, CSS, шрифты и скрипты не ломались в контексте.

Чтобы пользователь не прокручивал страницу, нужно спрятать полосы прокрутки scrollX и scrollY для позиции data-* с атрибутами клона HTMLDocument.

Перед финалом создан Blob:

// 4. Сохранить прокрутку страницы addOnPageLoad().
  screenshot.dataset.scrollX = window.scrollX;
  screenshot.dataset.scrollY = window.scrollY;

  // 4.5. Сохранить все для сника
  var script = document.createElement('script');
  script.textContent = '(' + addOnPageLoad_.toString() + ')();'; // обозвать
  screenshot.querySelector('body').appendChild(script);

  // прокрутка для исходной страницы
  function addOnPageLoad() {
  window.addEventListener('DOMContentLoaded', function(e) {
  var scrollX = document.documentElement.dataset.scrollX || 0;
  var scrollY = document.documentElement.dataset.scrollY || 0;
  window.scrollTo(scrollX, scrollY);
  });

Прокрутка создаёт впечатление, что мы сделали часть оригинала страницы, на самом деле всё с клонировано #clever.

к меню ↑

Демонстрация

После нажатия на кнопку, эта часть страницы откроется в новой вкладке с исходным кодом.

может понадобиться разблокировать всплывающее окно, если браузер блокирует его.

к меню ↑

Chrome Extension API + Binary WebSocket

В Google I/O 2012, продемонстрирован другой подход снимка содержания. Это требует API Chrome Extension: не чистый HTML5.

Cуть:

  1. Захват текущей вкладки, как .PNG dataURL. В Chrome Extensions есть API для этого chrome.tabs.captureVisibleTab ().
  2. Преобразование dataURL в Blob. См. помощник convertDataURIToBlob ().
  3. Отправить каждый Blob с помощью двоичного WebSocket, установив socket.responseType='blob'.

Код для снимка в формат PNG текущего положения содержания окна браузера и отправить этот кадр через WebSocket:

  var IMG_MIMETYPE = 'images/jpeg'; // можно image/webp
  var IMG_QUALITY = 80; // [0-100]
  var SEND_INTERVAL = 250; // ms

  var ws = new WebSocket('ws://...', 'dumby-protocol');
  ws.binaryType = 'blob';

  function captureAndSendTab() {
  var opts = {format: IMG_MIMETYPE, quality: IMG_QUALITY};
  chrome.tabs.captureVisibleTab(null, opts, function(dataUrl) {
  // captureVisibleTab returns a dataURL. Decode it -> convert to blob -> send.
  ws.send(convertDataURIToBlob(dataUrl, IMG_MIMETYPE));
  });
  }

  var intervalId = setInterval(function() {
  if (ws.bufferedAmount == 0) {
  captureAndSendTab();
  }
  }, SEND_INTERVAL);