Эта статья не будет содержать много лирики, марали или вводных зачем и кому это может быть надо.

В двух словах:


1. Пакет можно использовать для тестирования сайтов.
2. Пакет можно использовать для парсинга данных.
3. Пакет можно использовать для автоматизации ввода данных на сайты.

Альтернативы:


Casper.js, phantom.js, watir и много кто еще, в гугле полно всех и вся. Почему я за nightmare.js:

  1. Простота использования.
  2. Полная поддержка html5, никаких конфликтов с сайтами.
  3. Расширяемый через экшены.

Структура библиотеки


Nightmare класс использует фреймворк electron, для каждой страницы создавая объект (BrowserWindow) который запускает браузер оболочку Chromium.

Принцип работы


  1. Nightmare инициализирует новое приложение electron с стартовой страницей, которую необходимо подвергнуть дальнейшей обработке.
  2. Перед загрузкой исследуемой страницы загружаются скрипты, которые позволяют поддерживать двустороннее взаимодействие программиста и страницы через серию эмиттеров.
  3. Nightmare предоставляет программисту набор апи (цепочки действий), позволяющие произвести любые манипуляции с сайтом и получить требуемые данные.

Плюсы


  1. Код на стороне клиента и сайта написан на одном языке, никаких шаблонизаторов не требуется.
  2. Возможность расширять модулями через создание экшенов. Экшен может создаваться на уровне класса nightmare или на уровне класса nightmare и уровне electron (что в свою очередь дает возможность использовать devapi Chromium). В npm уже достаточно готовых модулей расширений, которые можно подключать к себе в проект (например realMouse полностью эмулирующую наведение мыши или работа с ифреймами, что блокируется безопасностью браузера).
  3. Все команды являются цепочками, каждая из которых возвращает промис, это позволяет писать код как в стиле промисов, так и внутри асинк функций или генераторов.
  4. Относительно небольшая нагрузка на процессор и память, нужно помнить, что сравнивать такой инструмент с простыми гет и пост запросами не этично, по скорости и памяти браузерные парсеры проигрывают без вариантов).
  5. Работа nightmare возможна в двух режимах, режим отображения браузера и режим фонового процесса.
  6. Поддерживает прокси. Установка юзерагента, выставление расширения браузера.
  7. Можно включать или отключать отображение изображений, поддержку webGL и еще кучу всего.
  8. Можно создавать прелоад скрипты, что позволяет добавлять на с��раницу до загрузки свои функции, библиотеки. Как частный пример можно переписать функцию addEventListener сделав ее декоратором для реальной + инжектировать аналитические функции для проверки того. Что в действительности делает сайт, когда вы на нем находитесь или бороться с навязчивостью фингер принт, который столь сильно полюбили все кому не лень, забывая о вашей «анонимности».

От эмоций к делу


Классический пример использования модуля из документации:

var Nightmare = require('nightmare');		
var nightmare = Nightmare({ show: true });

nightmare
  .goto('https://duckduckgo.com')
  .type('#search_form_input_homepage', 'github nightmare')
  .click('#search_button_homepage')
  .wait('#zero_click_wrapper .c-info__title a')
  .evaluate(function () {
    return document.querySelector('#zero_click_wrapper .c-info__title a').href;
  })
  .end()
  .then(function (result) {
    console.log(result);
  })
  .catch(function (error) {
    console.error('Search failed:', error);
  });

В двух словах о происходящем


Подключение библиотеки, создание объекта с режимом видимого браузера. Заход на страницу, поиск элемента по ЦСС селектору, ввод текста, нажатие кнопки, ожидание появления нового цсс сетектора, выполнение функции на стороне бразуера и возвращение ее, после завершения цепочки заданий в then будет передан результат работы или сработает исключение. На мой взгляд все просто и удобно, но как только скрипт обхода страницы становится большим, такое описание команд становится неудобным, потому предлагаю хороший вариант использования в асинк функции:

const Nightmare = require('nightmare');		

(async ()=>{
let nightmare; 
try {
	nightmare = Nightmare({ show: true });
	await nightmare
  		.goto('https://duckduckgo.com')
 		 .type('#search_form_input_homepage', 'github nightmare')
		  .click('#search_button_homepage')
		  .wait('#zero_click_wrapper .c-info__title a');

	let siteData = await nightmare.evaluate(function () {
    		return document.querySelector('#zero_click_wrapper .c-info__title a').href;
  		});
	// последующая работа с данными
} catch (error) {
	console.error(error);
	throw error;
} finally {
	await nightmare.end();
}
})();

В чем преимущества такого варианта написания кода? Можно получать сколько угодно раз данные с сайта через evaluate, анализировать их и применять различные поведенческие сценарии, описывая это в вашем скрипте.

Можно последовательно переходить по страницам через await nightmare.goto(….), при том Nightmare будет дожидаться загрузки дом.

О задокументированных возможностях


Описывать все функции в примерах считаю бессмысленным, так как все это хорошо указано в документации. Скажу лишь то, что модуль умеет считывать любые данные, делать скриншоты, с��хранять html страницы, pdf страницы, передавать на сайт данные. Через доп модули доступна загрузка файлов на сервер через form input type=”file”. Умеет реагировать на alert, prompt, confirm, может транслировать в виде событий данные из консоли.

Какие особенности стоит учитывать при работе с nightmare


Нужно понимать, что каждое действие будет либо совершено либо произойдет выброс исключительной ситуации, а потому в местах, где нет уверенности, что код пройдет 100% нужно обертывать запросы в try catch и обрабатывать из соответственно. Как пример wait(selector) данная инструкция даст команду приостановить выполнение скрипта до появления html элемента с соответствующим цсс селектором, но в модуле есть дефолтный таймаут, его можно изменять опционально, при наступлении которого будет выброшено исключение, соответственно можно будет обработать почему на странице нет чего-либо и как-то на это среагировать.

Резюме


На мой взгляд nightmare.js очень серьезная библиотека, с хорошим функционалом. Простая в изучении, гибкая, позволяющая выполнять практически любые задачи в тестировании сайтов и их анализе. К строгим критикаам отношусь с пониманием, кому будет интересна тема, по комментариям соберу идеи для следующий статей.

Ссылки


Nigthmare.js
Electron

Спасибо за внимание!