My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
ReleaseNotes  
Release Notes
Updated Mar 30, 2012 by ariya.hi...@gmail.com

PhantomJS 1.6 is still being developed. It is scheduled to be released on June 20, 2012.

PhantomJS 1.5 "Ghost Flower"

PhantomJS 1.5 was released on March 20, 2012. This version is backward compatible with version 1.4. Existing scripts should work without any modification, unless there is a need to run Flash or other plugins (see below).

PyPhantomJS, the implementation of PhantomJS in Python with PyQt, ceased the development ( issue 344 ) and thus the code has been removed from the repository.

Pure headless (no X11) on Linux

While it's always possible to customize the build of PhantomJS Linux without X11 (in particular since the last 1.4 release), it's a tedious adventure. Beginning from this release, X11-less setup is the standard when building PhantomJS Linux from source.

The benefits of pure headless are two-fold: no need to use Xvfb, it also compiles out-of-the-box on a barebone Linux server without GUI. This should make it easy to place PhantomJS in various continuous integration systems and cloud/elastic platforms.

Note that the pure headless mode does not compromise the functionalities and rendering quality. For screen capture, text rasterization is still done through FreeType and Fontconfig. Various formats (PNG, GIF, JPEG) for inlined images are still supported. Even producing PDF from the web page works just fine.

No more support for Flash and other plugins

Plugin support has been completely disabled (see issue 413) for the following reasons:

  • Going pure headless without X11 means it is not possible to have native window handle for the plugin.
  • Flash apps should be tested by whatever tools Adobe provides to the developers.
  • Issues are reported but nobody volunteers to analyze or fix them.

Future reported issues and bugs which relate to Flash and other plugins will be marked as WontFix.

Improved troubleshooting

To facilitates easier troubleshooting, there exists support for interactive mode (REPL), remote debugging, and error handling.

If PhantomJS is launched without any argument, it starts in the so-called interactive mode, also known for REPL (read-eval-print-loop). This mode allows a faster cycle of experiment and script prototyping. PhantomJS REPL supports the expected features: command editing, persistent history, and autocomplete (with Tab key).

Terminal line editing feature of this interactive mode is based on Linenoise project (an improved fork of the original).

Remote debugging permits inspection of the script and web page via another WebKit-based browser (Safari and Chrome). This is achieved by launching PhantomJS with the new option, as in this example

phantomjs --remote-debugger-port=9000 test.js

After than, open Safari/Chrome and go to the http://ipaddress:9000. The browser will show the familiar Web Inspector interface which in this case works on the script being tested.

Note: As of now, remote debugging is only for Linux (see issue 430).

To easily catch an error occured in a web page, whether it is a syntax error or other thrown exception, an onError handler for the WebPage object has been added. An example on such a handler is:

page.onError = function (msg, trace) {
    console.log(msg);
    trace.forEach(function(item) {
        console.log('  ', item.file, ':', item.line);
    })
}

Now if the page opens a site with some JavaScript exceptions, a detailed information (including the stack trace) will be printed out.

Note: Further refinement to the stack trace is still being planned (see issue 166).

System module

A set of functions to access system-level functionalities is available, modelled after CommonJS System proposal.

To start using, it needs to be instantiated via the system module such as:

var system = require('system');

Read-only properties:

  • platform is the name of the platform, always fixed as phantomjs.

Query functions:

  • env returns the list (as key value pair) of the environment variables.
  • args returns the list of command-line arguments. The first one is always the script name, it is followed by the subsequent arguments.

An example printenv.js demonstrates the same functionality as in the Unix printenv utility:

var system = require('system'),
    env = system.env,
    key;

for (key in env) {
    if (env.hasOwnProperty(key)) {
        console.log(key + '=' + env[key]);
    }
}
phantom.exit();

An example arguments.js prints all the command-line arguments:

var system = require('system');
if (system.args.length === 1) {
    console.log('Try to pass some args when invoking this script!');
} else {
    system.args.forEach(function (arg, i) {
            console.log(i + ': ' + arg);
    });
}
phantom.exit();

If the script is invoked:

phantomjs arguments.js answer 42

gives the following result:

0: arguments.js
1: answer
2: 42

Control web security

Performing cross-domain XHR is often necessary for some scripting purposes. This is now possible by disabling web security ( issue 28 ), either with --web-security=no command-line option or webSecurityEnabled page setting.

Note: Disabling web security may make the system more vulnerable to attacks and other malicious content. Use it with great caution.

An example findads.js uses disabled web security to access the frame content from Google Ads server: https://gist.github.com/2037945.

New features

Bug fixes

PhantomJS 1.4 "Glory of the Snow"

PhantomJS 1.4 was released on December 22, 2011. It is a minor update, mostly bug fixes and one new major feature: WebServer module.

This version is backward compatible with version 1.3. Existing scripts should work without any modification.

Minimum requirement to build PhantomJS 1.3 is Qt 4.6 or later. Latest stable release of Qt, i.e. version 4.8.0, is strongly recommended.

WebServer module

Note: This WebServer module is intended for ease of communication between PhantomJS scripts and the outside world. It is not recommended to use it as a general production server.

By using the embedded web server module Mongoose, PhantomJS script can start a web server which listens to a particular port.

A very simple example is as follows. It always gives the same response for any request.

var server, service;

server = require('webserver').create();

service = server.listen(8080, function (request, response) {
    response.statusCode = 200;
    response.write('<html><body>Hello!</body></html>');
});

The request object passed to the callback function may contain the following properties:

  • method defines the request method (GET, POST, ...)
  • url contains the complete request URL, including the query string (if any)
  • httpVersion has the actual HTTP version
  • headers stores all HTTP headers as key-value pair

The response object should be used to create the response:

  • statusCode sets the returned status code
  • write sends a chunk for the response body (it can be called multiple times).

This WebServer module is still rather simple in this version. Depending on the needs, the functionalities and the corresponding API will be expanded in the next versions.

Static version build script

For continuous integration server and various other uses cases, often it is desired to have a static version of PhantomJS which has almost zero dependencies. While building PhantomJS for the static build is not difficult, it is often a daunting task to figure out the bits and pieces necessary to achieve that build.

For convenience, now there are two build scripts, available in the deploy subdirectories, each for Linux and Mac. The script automatically downloads the source code of Qt, build everything locally, and then prepare the binary for deployment. There is no need to have Qt installed on the system before running the script.

The produced binary has very minimal dependencies and can be transferred to another machine easily. With the help of UPX (optional), the size of the binary is only about 10 MB.

Note: Even with the static build, as of now you still need to setup Xvfb for the Linux version. Also for Mac, don't forget the Info.plist file (see  issue 281 ).

New features

Bug fixes

Examples

PhantomJS 1.3 "Water Lily"

PhantomJS 1.3 was released on September 23, 2011. It is a minor update, mostly bug fixes and few additional new features.

This version is backward compatible with version 1.2. Existing scripts should work without any modification.

Minimum requirement to build PhantomJS 1.3 is Qt 4.6 or later. Latest stable release of Qt, i.e. version 4.7.4, is strongly recommended.

Initial module support

Module API modelled after CommonJS Modules is available, currently only supporting webpage and fs built-in modules.

For compatibility reason, WebPage object at the global scope is still available. It will be deprecated in some future release. The new recommended way to create a web page is as follows:

var page = require('webpage').create();

page.open(url, function (status) {
  // do something
});

WebPage object

WebPage object wraps a native object that represents the web page. Because of technical limitation, a WebPage object can not be properly garbage collected and freed from the memory. To prevent increasing heap usage when create a lot of WebPage objects, use the new release() function, as in this example:

var page = require('webpage').create();

page.open(url, function (status) {
  // do something
  // ....
  // finish
  page.release();
});

A new callback onInitialized can be used to modify the global objects before a page is loaded. In the following example, further calls to Math.random() effectively will always return the specified constant.

page.onInitialized = function() {
    Math.random = function() {
        return 42;
    };
};

Related to page rasterization using render() function, it is now possible to control the physical scroll offset of the web page using the new property of WebPage called scrollPosition, as illustrated below:

page.scrollPosition = { top: 100, left: 0 };
page.render('output.png');

There is now a convenient way to create a new page by passing an option the constructor:

var page = new WebPage({
  onConsoleMessage: function (msg) {
    console.log(msg);
  },

  settings: {
    loadPlugins: false,
    userAgent: 'Dragonless Phantom'
  },

  viewportSize: {
    width: 800,
    height: 600
  }
});

Page settings

The behavior of the web page can be further modified by the following new settings:

  • javascriptEnabled defines whether to execute the script in the page or not (default to true)
  • XSSAuditingEnabled defines whether load requests should be monitored for cross-site scripting attempts (default to false)
  • localToRemoteUrlAccessEnabled defines whether local resource (e.g. from file) can access remote URLs or not (default to false)
  • userName sets the user name used for HTTP authentication
  • password sets the password used for HTTP authentication

Example usage:

var page = new WebPage();

page.settings.javascriptEnabled = true;
page.settings.XSSAuditingEnabled = true;
page.settings.localToRemoteUrlAccessEnabled = true;

page.open(url, function (status) {
  // do something
});

Mouse events

Mouse events can be sent to the page using the new sendEvent function, like in the following examples:

page.sendEvent('mousedown', 45, 50);

The first argument is the event type. Other available types are mouseup, mousemove, and click. The next two arguments represents the mouse position.

As of now, left button is the only pressed button for the event. For mousemove however, there is no button pressed (i.e. it is not dragging).

The events are not like synthetic DOM events. Each event is sent to the web page as if it comes as part of user interaction.

File system access

A set of API functions is available to access files and directories. They are modelled after CommonJS Filesystem proposal.

To start using, it needs to be instantiated via the fs module such as:

var fs = require('fs');

Read-only properties:

  • separator is the path separator (forward slash or backslash, depending on the operating system).
  • workingDirectory is the current working directory.

Query functions:

  • list(path) returns the list of all the names of all the files in a specified path.
  • absolute(path) returns the absolute path starting from the root file system, resolved from the current working directory.
  • exists(path) returns true if a file or a directory exists.
  • isDirectory(path) returns true if the specified path is a directory.
  • isFile(path) returns true if the specified path is a file.
  • isAbsolute(path) returns true if the specified path is an absolute path.
  • isExecutable(path) returns true if the specified file can be executed.
  • isReadable(path) returns true if a file or a directory is readable.
  • isWritable(path) returns true if a file or a directory is writeable.
  • isLink(path) returns true if the specified path is a symbolic link.

Directory-related functions:

  • changeWorkingDirectory(path) changes the current working directory to the specified path.
  • makeDirectory(path) creates a new directory.
  • makeTree(path) creates a directory including any missing parent directories.
  • removeDirectory(path) removes a directory if it is empty
  • removeTree(path) removes the specified path, regardless of whether it is a file or a directory.
  • copyTree(source, destination) copies the entire files from a source path to the destination path.

File-related functions:

  • open(path, mode) returns a stream object representing the stream interface to the specified file (mode can be r for read, w for write, or a for append).
  • read(path) returns the entire content of a file.
  • write(path, content, mode) writes content to a file (mode can be w for write or a for append).
  • size(path) returns the size (in bytes) of the file specified by the path.
  • remove(path) removes the file specified by the path.
  • copy(source, destination) copies a file to another.
  • move(source, destination) movies a file to another, effectively renaming it.
  • touch(path) touches a file (i.e. changes its access timestamp).

A stream object returned from the open() function has the following functions:

  • read returns the content of the stream.
  • write(data) writes the string to the stream.
  • readLine reads only a line from the stream and return it.
  • writeLine(data) writes the data as a line to the stream.
  • flush() flushes all pending input output.
  • close() completes the stream operation.

As an example of file access API, the following function recursively traverses a directory and prints all the found entries:

function scanDirectory(path) {
    var fs = require('fs');
    if (fs.exists(path) && fs.isFile(path)) {
        console.log(path);
    } else if (fs.isDirectory(path)) {
        fs.list(path).forEach(function (e) {
            if ( e !== '.' && e !== '..' ) {
                scanDirectory(path + '/' + e);
            }
        });
    }
};

Command-line options

Newly available options are:

  • --max-disk-cache-size=size limits the size of disk cache (in KB)
  • --output-encoding=encoding sets the encoding used for terminal output (default is utf8).
  • --script-encoding=encoding sets the encoding used for the starting script (default is utf8).
  • --local-to-remote-url-access=[yes|no] allows local content to access remote URL (default is no).
  • --ignore-ssl-errors=[yes|no] ignores SSL errors, such as expired or self-signed certificate errors (default is no).
  • --cookies-file=/path/to/cookies.txt specifies the file name to store the persistent cookies.

Rather than passing all options in the command-line, it is also possible to store the options in a file using JavaScript Object Notation (JSON) and then tell PhantomJS to read it:

phantomjs --config=/path/to/config.json script.js arg1 arg2 arg3

where the contents of config.json looks like:

{
    'ignoreSslErrors': true,
    'localToRemoteUrlAccessEnabled': true
}    

Platform-specific

Mac OS X: There is no more application bundle, the executable is bin/phantomjs and not bin/phantomjs.app/Contents/MacOS/phantomjs anymore.

Bug fixes

  • Fixed open() and POST method, without specifying the finished handler
  • Fixed script execution warning dialog ( issue 165 )
  • Added WebPage.release() to free the web page from memory ( issue 154 )
  • Added special handling of about:blank ( issue 235 )
  • Made a separate network access manager for each page ( issue 190 )

New features

Examples

  • Added a new example on using Modernizr to detect features ( issue 144 )
  • Fixed pizza.js example to use Mobile Yelp ( issue 200 )
  • Fixed netsniff.coffee example due to wrong indentation ( issue 225 )
  • Added an example to show live network traffic ( issue 227 )
  • Added an example demonstrating different output encodings ( issue 186 )

PhantomJS 1.2 "Birds of Paradise"

PhantomJS 1.2 was released on June 21, 2011. It is a major update, it introduces a whole set of new API. It is not compatible with the previous version. For porting existing scripts into the new API, follow the description below.

WebPage object

In order to improve the security aspect (see  issue 41 ), PhantomJS scripts will not run in the context of web page execution. This means, there is no way for malicious scripts to detect the presence of 'phantom' object and exploits its API.

The sandboxing is achieved via a new WebPage object. It is an encapsulation of a web page. A specific URL can be loaded using its open() function. A typical usage is:

var page = new WebPage();

page.open(url, function (status) {
  // do something
});

The callback in the open() is executed when the page loading is completed, with status equals to "success" if there is no error and "failed" is error has occurred.

The above construct is a convenient version of the following:

var page = new WebPage();

page.onLoadFinished = function (status) {
  // do something
};

page.open(url);

Beside onLoadFinished, there is also onLoadStarted which is invoked when page loading starts for the first time:

var page = new WebPage();

page.onLoadStarted = function () {
    console.log('Start loading...');
};

page.onLoadFinished = function (status) {
    console.log('Loading finished.');
};

page.open(url);

Page settings

The behavior of the web page can be set via its settings object, with the following properties:

  • loadImages defines whether to load inline images or not (default to true)
  • loadPlugins defines whether to load plugins (Flash, Silverlight, ...) or not (default to false)
  • userAgent defines the user agent string passed to the server

As an example, here is how to change the user agent:

var page = new WebPage();

page.settings.userAgent = 'Dragonless Phantom';

page.open(url, function (status) {
  // do something
});

Rasterization

A web page can be rasterized to an image or a PDF file using render() function.

This rasterize.js is all it takes to capture a web site.

var page = new WebPage(),
    address, output, size;

if (phantom.args.length < 2 || phantom.args.length > 3) {
    console.log('Usage: rasterize.js URL filename');
    phantom.exit();
} else {
    address = phantom.args[0];
    output = phantom.args[1];
    page.viewportSize = { width: 600, height: 600 };
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

Network traffic

All the resource requests and responses can be sniffed using the onResourceRequested and onResourceReceived. An example to dump everything is:

var page = new WebPage();
page.onResourceRequested = function (request) {
    console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function (response) {
    console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
page.open(url);

The included examples/netsniff.js shows how to capture and process all the resource requests and responses and export the result in HAR format.

The following shows the waterfall diagram obtained from BBC website:

JavaScript evaluation

To evaluate JavaScript code in the context of the web page, use evaluate() function. The execution is sandboxed, there is no way for the code to access any JavaScript objects and variables outside its own page context. An object can be returned from evaluate(), however it is limited to simple objects and can't contain functions or closures.

Here is an example to show the title of a web page:

var page = new WebPage();
page.open(url, function (status) {
    var title = page.evaluate(function () {
        return document.title;
    });
    console.log('Page title is ' + title);
});

Any console message from a web page, including from the code inside evaluate(), will not be displayed by default. To override this behavior, use the onConsoleMessage callback. The previous example can be rewritten to:

var page = new WebPage();
page.onConsoleMessage = function (msg) {
    console.log('Page title is ' + msg);
};
page.open(url, function (status) {
    page.evaluate(function () {
        console.log(document.title);
    });
});

To inject external code, use injectJs function passing the file name containing the code to be loaded. If the file can not be found in the current directory, it will be searched in the path specified in the libraryPath property. Both phantom and WebPage object have injectJs function.

To load external JavaScript library, includeJs is very useful. It behaves like the well-known dynamic script loading technique. An example:

page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
    // jQuery is loaded, now manipulate the DOM
});

Bug fixes

New features

  • Added callback for console message ( issue 12 )
  • Improved security model via WebPage object ( issue 41 )
  • Added support for POST, HEAD, PUT, and DELETE ( issue 88 )
  • Scripts filename is now passed as phantom.scriptName
  • Added callback to capture resource requests and responses ( issue 2 )
  • Added the ability to load external JavaScript ( issue 32 )

Examples

  • Ported examples to use WebPage object
  • Added a new example to upload an image to imagebin.org
  • Added a new example to show HTTP POST feature
  • Added a new example to sniff network traffic and save it in HAR format

PhantomJS 1.1 "Cherry Blossoms"

PhantomJS 1.1 was released on April 27, 2011. This release is a minor update and all existing scripts should still work.

Some highlights of this release:

  • Support for file upload, network proxy, disk cache, and GIF rasterization output
  • Scripts can be written in CoffeeScript
  • Another implementation of PhantomJS using Python (via PyQt)

The complete changes are as follows.

Bug fixes

New features

  • Added check for system proxy setting
  • Added support for rasterizing as GIF image
  • Added support for CoffeeScript
  • Python implementation using PyQt
  • Added clipping rectangle to the render function
  • Added command line option to use disk cache

Examples

  • Added a new example: driver for QUnit tests
  • Added a new example: using Canvas to produce the color wheel
  • Added an example on sychronous waiting
  • Added text extracting example
  • Ported all examples to CoffeeScript
Powered by Google Project Hosting