В прошлом совете я рассказал о том, что у книжного поиска под капотом. В этом — как мы собираем превьюшки разворотов для результатов поиска и навигации по книге.
Превьюшки разворотов генерирует PhantomJS, управляемый браузер без визуального интерфейса. Чаще всего его используют для автоматизации, визуального и интеграционного тестирования (см. PhantomCSS и Poltergeist).
Превьюшки генерируются при каждой продакшен-сборке книги: и развороты, и движок меняются так часто, что хранить их и перегенерировать время от времени не имеет смысла. Поэтому для превьюшек мы используем «безголовый», а не реальный браузер: в «Типографике и вёрстке» PhantomJS генерирует их за 1,5 минуты, Хром — за 5 минут, а Сафари — за 6.
Чтобы в превьюшках было меньше шума, убираем с них номера разворотов и колонтитулы. Делаем это через инъекцию стилей для превьюшек:
function injectPreviewCSS() {
// ...
page.evaluate(function(css) {
$('<div />', { html: '<style>' + css + '</style>' }).appendTo('body');
}, previewCSS);
}
page.open(book, function() {
injectPreviewCSS();
// ...
}
Так как книги самостоятельно управляют загрузкой картинок, дополнительно учим PhantomJS дожидаться их загрузки:
var RESOURCE_WAIT = 1000;
var MAX_RENDER_WAIT = 30000;
var resourceCount = 0;
var renderTimeout;
// При запросе картинки увеличиваем счетчик ресурсов,
// которые ещё предстоит скачать. Если уже собрались
// снимать скриншоты, отменяем.
page.onResourceRequested = function() {
resourceCount += 1;
clearTimeout(renderTimeout);
};
// При получении картинки, уменьшаем счетчиков ресурсов.
// Если уже всё скачали, даем браузеру ещё секунду
// на раздумье.
//
// Если за эту секунду, браузер не стал ничего скачивать,
// считаем, что всё готово и начинаем снимать скриншоты.
page.onResourceReceived = function(res) {
if (!res.stage || res.stage === 'end') {
resourceCount -= 1;
if (resourceCount === 0) {
renderTimeout = setTimeout(doRender, RESOURCE_WAIT);
}
}
};
// Если за 30 секунд браузер так всё и не загрузил,
// перестаем ждать и снимаем скриншоты.
setTimeout(function() {
doRender();
}, MAX_RENDER_WAIT);
Этот подход применим и для работы с сайтами, асинхронно загружающими содержимое
У PhantomJS есть и проблемы: он не поддерживает видео и отстает в поддержке стандартов. Книжный движок до сих пор использует -webkit- префиксы для флексбоксов только ради него. Поэтому со временем планируем перейти на Headless Chrome.
P. S. А ещё мы ищем фронтендера в издательство.
|