Пользователь
0,0
рейтинг
4 апреля 2011 в 12:03

Разработка → 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
Максим Сябро @Azy
карма
30,4
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (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
        спасибо за подробный ответ. Я надеялся что функционал профейлера будет в фантоме в том же виде в котором он есть в вебките.
  • НЛО прилетело и опубликовало эту надпись здесь

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