PhantomJS

webkitowa przeglądarka w konsoli

Maciej Brencz / Wikia

Trochę historii

PhantomJS is a headless WebKit scriptable with a JavaScript API.
It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.

PhantomJS

  • skryptowalna, oparta o WebKit, przeglądarka WWW,
  • skrypty pisane w... JavaScript,
  • dostępny tryb interaktywny (REPL),
  • wbudowany serwer HTTP (eksperymentalny),
  • konfiguracja viewportu, ciasteczek, nagłówków HTTP, ...,
  • uruchamanie kodu JS w kontekście otwartej strony WWW.

Co nowego w PhantomJS 1.9.2

  • wsparcie dla własnych modułów CommonJS (exports i require),
  • wbudowane moduły: webpage, system, fs, webserver, child_process,
  • filtrowanie zapytań HTTP,
  • ustawianie ciasteczek,
  • komunikacja z poziomu JS strony z PhantomJSem (eksperymentalna),
  • postęp wczytywania strony (page.loadingProgress),
  • uruchamianie procesów (spawn i execFile).

PhantomJS w akcji

var page = require('webpage').create(),
	url = "http://akai.org.pl";

page.open(url, function (status) {
	console.log(url + " loaded");

	// screenshot do pliku
	page.render("akai.png");

	// zakończ skrypt
	phantom.exit();
});

Wywiad środowiskowy

var page = require('webpage').create(),
	url = "http://akai.org.pl";

page.open(url, function (status) {
	var title = page.evaluate(function() {
		// jesteśmy w kontekście otwartej strony
		return document.title;
	});

	console.log("Page title: " + title);

	console.log("HTML elements: " + page.evaluate(function(tagName) {
		return document.getElementsByTagName(tagName).length;
	}, '*' /* parametr tagName przekazany z poziomu PhantomJSa */));

	phantom.exit();
});
$ phantomjs example-pagetitle.js
Page title: AKAI
HTML elements: 198

Wykrywanie błędów w kodzie JS

var page = require('webpage').create(),
	url = "http://akai.org.pl";

// wywołania console.log
page.onConsoleMessage = function(msg) {
	console.log('LOG: ' + msg);
};

// błędy JS
page.onError = function(msg, trace) {
	console.log('ERROR: ' + msg);
	trace.forEach(function(item) {
		console.log('  ', item.file, ':', item.line);
	});
};

page.open(url, function (status) {
	phantom.exit();
});
$ phantomjs example-error.js
ERROR: ReferenceError: Can't find variable: Cufon
   http://akai.org.pl/ : 19

Zakładka "Network"

var page = require('webpage').create(),
	url = "http://akai.org.pl",
	requests = 0;

page.onResourceRequested = function (request) {
	console.log('Requested ' + JSON.stringify(request, undefined, 4));
	requests++; // zliczajmy wszystkie zapytania HTTP
};

page.onResourceReceived = function (response) {
	// response.stage = start | end
	// response.status = kod HTTP (200, 301, 302, 404, ...)
	console.log('Received ' + JSON.stringify(response, undefined, 4));
};

page.open(url, function (status) {
	console.log("Number of request: " + requests);
	phantom.exit();
});
$ phantomjs example-netsniff.js
Number of request: 67

A teraz...

...nakręcimy film "Another World"

var page = require('webpage').create(),
	url = "http://www.megidish.net/awjs/";

page.viewportSize = {width: 800, height: 400}; // rozmiar "klatek"

page.open(url, function (status) {
	var f = 0;

	// wstrzyknij jQuery do otwartej strony i usuń wszystkie tagi <p>
	page.includeJs("http://code.jquery.com/jquery-2.0.3.min.js", function() {
		page.evaluate(function() {
			$('p').remove();
		});
	});

	setInterval(function() {
		page.render('movie/movie-' + (f < 9 ? ('0' + f) : f) + '.png');
		console.log('Frame #' + f);

		f++;
		if (f > 80) { // można i dłużej ;)
			phantom.exit();
		}
	}, 250);
});
$ phantomjs example-movie.js

Kilka uwag

  • brak wsparcia dla Flasha,
  • tryb REPL wymaga jeszcze dopracowania (Date.now() === 0),
  • brak niektórych funkcji z ES5 (np. Function.prototype.bind),
  • dokumentacja nie jest aktualizowana na bieżąco,
  • skrypty należy kończyć wywołaniem phantom.exit(),
  • nie wszystkie funkcje WebKita są dostępne (geolokalizacja, <video>, <audio>, performance.timing, WebGL, IndexedDB),
  • przedstawia się jako przeglądarka z "interfejsem dotykowym" (ontouchstart),
  • niedostępne są niektóre nagłówki HTTP: Content-Length, związane z ciastkami.

Zastosowania

  • badanie i monitorowanie wydajności stron WWW - phantomas,
  • uruchamianie testów jednostkowych (Jasmine, QUnit),
  • "lekki" klient dla testów przeglądarkowych (GhostDriver),
  • wykonywanie zrzutów ekranu / filmów z akcji na stronie,
  • web scrapping (znajdowanie najbliższej pizzy poprzez Yelp.com),
  • ...

slides.wikia.net/akai