https://habrahabr.ru/post/331752/Эта статья не будет содержать много лирики, марали или вводных зачем и кому это может быть надо.
В двух словах:
1. Пакет можно использовать для тестирования сайтов.
2. Пакет можно использовать для парсинга данных.
3. Пакет можно использовать для автоматизации ввода данных на сайты.
Альтернативы:
Casper.js, phantom.js, watir и много кто еще, в гугле полно всех и вся. Почему я за nightmare.js:
- Простота использования.
- Полная поддержка html5, никаких конфликтов с сайтами.
- Расширяемый через экшены.
Структура библиотеки
Nightmare класс использует фреймворк electron, для каждой страницы создавая объект (BrowserWindow) который запускает браузер оболочку Chromium.
Принцип работы
- Nightmare инициализирует новое приложение electron с стартовой страницей, которую необходимо подвергнуть дальнейшей обработке.
- Перед загрузкой исследуемой страницы загружаются скрипты, которые позволяют поддерживать двустороннее взаимодействие программиста и страницы через серию эмиттеров.
- Nightmare предоставляет программисту набор апи (цепочки действий), позволяющие произвести любые манипуляции с сайтом и получить требуемые данные.
Плюсы
- Код на стороне клиента и сайта написан на одном языке, никаких шаблонизаторов не требуется.
- Возможность расширять модулями через создание экшенов. Экшен может создаваться на уровне класса nightmare или на уровне класса nightmare и уровне electron (что в свою очередь дает возможность использовать devapi Chromium). В npm уже достаточно готовых модулей расширений, которые можно подключать к себе в проект (например realMouse полностью эмулирующую наведение мыши или работа с ифреймами, что блокируется безопасностью браузера).
- Все команды являются цепочками, каждая из которых возвращает промис, это позволяет писать код как в стиле промисов, так и внутри асинк функций или генераторов.
- Относительно небольшая нагрузка на процессор и память, нужно помнить, что сравнивать такой инструмент с простыми гет и пост запросами не этично, по скорости и памяти браузерные парсеры проигрывают без вариантов).
- Работа nightmare возможна в двух режимах, режим отображения браузера и режим фонового процесса.
- Поддерживает прокси. Установка юзерагента, выставление расширения браузера.
- Можно включать или отключать отображение изображений, поддержку webGL и еще кучу всего.
- Можно создавать прелоад скрипты, что позволяет добавлять на страницу до загрузки свои функции, библиотеки. Как частный пример можно переписать функцию 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
Спасибо за внимание!