PhantomJS: Webkit в консоли

    image

    PhantomJS это все плюшки WebKit из консоли с управлением на JS и поддержкой различных стандартов и технологий: DOM, CSS, JSON, Canvas и SVG.

    Внутри несколько примеров использования

    Запуск


    Запустить скрипты с помощью PhantomJS очень просто:
    phantomjs script.js [arguments]


    Использование


    Это самое простое приложение для PhantomJS
    console.log('Hello, world!');
    phantom.exit();


    Возьмем пример посложнее. Данный скрипт покажет время загрузки страницы:
    
    if (phantom.state.length === 0) {
        if (phantom.args.length === 0) {
            console.log('Usage: loadspeed.js <some URL>');
            phantom.exit();
        } else {
            var address = phantom.args[0];
            phantom.state = Date.now().toString();
            console.log('Loading ' + address);
            phantom.open(address);
        }
    } else {
        var elapsed = Date.now() - new Date().setTime(phantom.state);
        if (phantom.loadStatus === 'success') {
            console.log('Page title is ' + document.title);
            console.log('Loading time ' + elapsed + ' msec');
        } else {
            console.log('FAIL to load the address');
        }
        phantom.exit();
    }
    

    После запуска его
    phantomjs loadspeed.js http://www.google.com

    мы получим
    Loading http://www.google.com
    Page title is Google
    Loading time 719 msec


    Юнит-Тесты


    Это, на мой взгляд самое полезное применение.
    В качестве примера показана интеграция с QUnit
    if (phantom.state.length === 0) {
        if (phantom.args.length === 0 || phantom.args.length > 2) {
            console.log('Usage: run-qunit.js URL');
            phantom.exit();
        } else {
            phantom.state = 'run-qunit';
            phantom.open(phantom.args[0]);
        }
    } else {
        setInterval(function() {
            var el = document.getElementById('qunit-testresult');
            if (phantom.state !== 'finish') {
                if (el && el.innerText.match('completed')) {
                    phantom.state = 'finish';
                    console.log(el.innerText);
                    try {
                        failed = el.getElementsByClassName('failed')[0].innerHTML;
                    } catch (e) {
                    }
                    phantom.exit((parseInt(failed, 10) > 0) ? 1 : 0);
                }
            }
        }, 100);
    }

    В качестве результатов мы получим
    Tests completed in 1486 milliseconds.
    1267 tests of 1267 passed, 0 failed.


    Рендеринг


    Тоже полезная вещь. Кто-то может написать еще один сервис создания скриншотов страниц.
    if (phantom.state.length === 0) {
        if (phantom.args.length !== 2) {
            console.log('Usage: rasterize.js URL filename');
            phantom.exit();
        } else {
            var address = phantom.args[0];
            phantom.state = 'rasterize';
            phantom.viewportSize = { width: 600, height: 600 };
            phantom.open(address);
        }
    } else {
        var output = phantom.args[1];
        phantom.sleep(200);
        phantom.render(output);
        phantom.exit();
    }
    

    Натравив его на http://raphaeljs.com/polar-clock.html
    phantomjs rasterize.js http://raphaeljs.com/polar-clock.html clock.png

    Получим
    image

    Или к примеру нужно получить pdf с версии для печати в википедии:
    phantomjs rasterize.js "http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes" jakarta.pdf

    что даст нам
    image
    (выглядит не очень из-за сильного зум-аута в FoxitPDF Reader)

    Скачать бинарники для Windows и исходный код можно с google code
    Ну и разумеется сайт проекта: http://www.phantomjs.org
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 35
    • –16
      А есть какие-то причины использовать PhantomJS вместо Node.js помимо «прикольно, ещё один серверный js-движок»?
      • +16
        Это ни в коем случае не «серверный js движок». Это WebKit в консоли.
        Это две большие разницы.
        • –14
          А Node.js — V8 в консоли.
          Не вижу разницы.
          • +6
            V8 это только движок JS
            А WebKit это платформа которая включает в себя движок JS и движок для рендеринга.
        • +7
          Это полноценный браузер (JavaScript+CSS+DOM+BOM+SVG+Canvas) но без графического интерфейса.
          У него общего с Node.js (V8 JavaScript+libeio+libev) только JavaScript.

          Из него выйдет отличный скриншотер (См. новый поиск гугла) и парсер с поддержкой JavaScript
          • 0
            В примерах рендеринг HTML в png и pdf показан
            • –1
              Очень сомневаюсь что в фантоме используется v8. Скорее всего стандартный вебкитовский JS движок.
              • 0
                Их бы усилия, да объединить :)
              • +6
                А есть какие-то причины комментировать, если вы даже не вчитались в суть топика?
              • +1
                А ему иксы нужны?
              • +2
                ради такого я даже огромный qt соберу под маком.
                • +4
                  /usr/local/Cellar/qt/4.7.2: 2562 files, 196M, built in 84.9 minutes
                • +1
                  Активно используем для запуска юнит-тестов с qUnit.
                  Если бы ему x server не нужен был — цены бы не было :(
                  • 0
                    Вот-вот, это огромная проблема, которую хотелось бы обсудить. Что необходимо для полноценной растеризации веб-сайта через эту библиотеку? Что именно нужно из X? Возможно ли это поднять на сервере без видеокарты и так далее?
                    • 0
                      Все, как я понял можно использовать xvfb
                      • 0
                        Я то поднимаю.)))
                    • 0
                      Пока на сервере использую pywebkitgtk, рендеринг webkit из python!
                      Однако это вроде интересней выглядит, может в будущем перейду на PhantomJS.
                      • 0
                        ИМХО, никакой разницы. Просто для скриптования используется JS а не Python и обвязка на основе Qt а не GTK
                        • +1
                          Хотя не, у фантома этого еще доступ к DOM есть нормальный видимо.
                      • +3
                        Небольшой гайд для тех, кто захочет использовать эту библиотеку для создания скриншотов сайта:

                        1. Идем на code.google.com/p/phantomjs/wiki/Installation и устанавливаем, как там написано, либо собираем, как написано на странице помощи по сборке: code.google.com/p/phantomjs/wiki/BuildInstructions

                        2. Устанавливаем Xvfb (frame buffer), он нужен будет для того, чтобы создать виртуальный x server.

                        3. Запускаем Xvfb, например со следующими параметрами:
                        Xvfb :1 -screen 0 1024x768x32 &

                        4. Теперь запускаем скрипт с первым виртуальным дисплеем:
                        :# DISPLAY=:1 phantomjs rasterize.js google.ru google.png
                        • +1
                          Мда, у этой библиотеки есть несколько не очевидных минусов. Как гласит вики, функция phantom.open() запускает загрузку страницы и перевыполняет скрипт, только тогда, когда загружена вся страница, включая все скрипты, картинки, внешние картинки и далее по списку. Наличие скриптов рекапчи, большого количества onload скриптов, делает загрузку страницы очень долгой, например вы можете даже увидеть подобное:
                          Loading time 58859 msec

                          Очень огорчает, что нет ни onDOMReady событий, ни возможности отключить загрузку и выполнение скриптов на странице, так что, скорее всего, для сервисов онлайн-скриншотов эта библиотека подойдет едва ли.
                          • 0
                            Можно, конечно, выкрутиться, использовав доступный в фантоме XHR объект, синхронным запросом взять данные, обработать его и только потом загрузить для обработки в браузере, после чего отобразить.

                            var address = phantom.args[0];
                            var output = phantom.args[1];

                            if (phantom.state.length === 0) {
                              var xmlhttp = new XMLHttpRequest();
                              phantom.viewportSize = { width: 800, height: 600 };

                              xmlhttp.open('GET', address, false);
                              xmlhttp.send(null);

                              if(xmlhttp.status == 200) {
                                var response  = xmlhttp.responseText;

                                /**
                                 * Тут мы выполняем операции по очистке response от скриптов и, например
                                 * внешних iframe и изображений с отличного от текущего домена. Но тут
                                 * придется использовать только регулярные выражения, а не DOM.
                                 */

                                phantom.state  = 'rasterize';
                                phantom.content = response;
                              }
                            } else {
                              phantom.render(output);
                              phantom.exit();
                            }
                            • 0
                              Только это никак не спасает от "… включая все скрипты, картинки, внешние картинки и далее по списку. Наличие скриптов рекапчи, большого количества onload скриптов..."
                              • 0
                                Можно их вырезать.
                              • 0
                                К сожалению описанный метов вызывает NETWORK_ERR: XMLHttpRequest Exception 101: A network error occured in synchronous requests.
                          • +1
                            Вопрос к тем кто уже пощупал… А можно ли получить отчет о длительности загрузки ресурсников — скриптов, картинок, флешек и т.п.? Можно ли получить перечень JS ошибок сгенеренных на странице? Можно ли получить информацию из профайлера страницы (например время выполнения каждой функции),
                            • +1
                              Вряд ли. Все дело в том, что PhantomJS работает по следующему принципу:
                              1. Выполняется (в контексте пустого окна «браузера» ваш скрипт).
                              2. Если вы изменяете свойство content, либо используете метод open(), страница (пере)загружается, управление полностью передается загружаемой странице (скрипты, загрузка изображений, составление DOM-дерева, etc).
                              3. По событию load страницы управление опять передается вашему скрипту, точнее он снова выполняется с самого начала (однако область видимости сохраняется).

                              Поэтому вашу задачу выполнить средствами PhantomJS невозможно, точнее можно, но только сам профайлер и чекер ошибок вам придется сделать самостоятельно, т.е. как в моем примере выше, только переделывая всю страницу, вешая try-catch на скрипты, или свои обработчики onerror, подмиксовывать таймеры перед вызовами и так далее, в общем писать свой полноценный дебагер, который работал бы на подобии встраиваемой части Firebug, например. В общем, задача если и выполнима, но все же трудна.

                              Другой вопрос, что этот функционал, а так же расширить методы работы со страницей в PhantomJS, вы можете, редактируя его исходники, ведь они открыты. На данный момент нужно либо самому писать недостающий функционал, либо ждать обновлений.
                              • 0
                                спасибо за подробный ответ. Я надеялся что функционал профейлера будет в фантоме в том же виде в котором он есть в вебките.
                            • НЛО прилетело и опубликовало эту надпись здесь

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.