PhantomJS 1.1, Cherry Blossom, was released on April 27, 2011. This release is a minor update and all existing scripts should still work.
+ +Some highlights of this release:
+ +Bug fixes:
+ +New features:
+ +Examples:
+ +Back to all releases.
+ +PhantomJS 1.2, Birds of Paradise, 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:
+ +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
+ +Examples
+ +Back to all releases.
+ +PhantomJS 1.3, Water Lily, 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 improvement
+ +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:
+ +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:
+ +Query functions:
+ +Directory-related functions:
+ +File-related functions:
+ +A stream object returned from the open() function has the following functions: + +
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:
+ +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
+ +New features
+ +Examples
+ +Back to all releases.
+ +PhantomJS 1.4, Glory of the Snow, 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('Hello!'); +}); ++ +
The request object passed to the callback function may contain the following properties:
+ +The response object should be used to create the response:
+ +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
+ +Back to all releases.
+ +PhantomJS 1.5, Ghost Flower, 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:
+ +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 (an improved fork of the original project).
+ +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:
+ +Query functions: + +
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
+ +Back to all releases.
+ +PhantomJS 1.6, Lavender, was released on June 20, 2012. It is a minor update, mostly bug fixes and some new API.
+ +This version is backward compatible with version 1.5. Existing scripts should work without any modification.
+ +Improved support for rendering
+ +While it is always possible to capture the web page and render it as an image, it involves creating an external file to hold that image. With this version, the captured content can be retrieved as a string, base64-encoded using the new renderBase64(format) function.
+ +The example will dump the base64-encoded rendering of the web page in PNG format (the default if no format is specified) to the terminal:
+ ++var page = require('webpage').create(); +page.open('http://m.bing.com', function (status) { + console.log(page.renderBase64()); + phantom.exit(); +}); ++ +
To facilitate creating thumbnail preview, scaling the screen capture is now possible via the new zoomFactor property. In this example, the BBC site is captured to an image at 25% zoom.
+ ++var page = require('webpage').create(); +page.open('http://news.bbc.co.uk', function (status) { + page.zoomFactor = 0.25; + page.render('bbc.png'); + phantom.exit(); +}); ++ +
Better script evaluation
+ +Arguments can be passed to evaluate() function to run a script in the context of the web page.
+ +In the following example, the text value of a DOM element is extracted. The element is chosen based on the selector which is passed to evaluate.
+ ++var page = require('webpage').create(); +page.open('http://m.bing.com', function (status) { + var title = page.evaluate(function (s) { + return document.querySelector(s).innerText; + }, 'title'); + console.log(title); + phantom.exit(); +}); ++ +
Evaluating a script asynchronously is now possible via the new evaluateAsync function. Unlike the standard evaluate, the function returns immediately and does not wait until the script execution finishes. Consequently there is no return value from this function.
+ +New features
+ +Improvements
+ +Back to all releases.
+ +PhantomJS 1.6 "Lavender" was released on June 20, 2012. It is a minor update with some improvements on the rendering and script evaluation, as well as various bug fixes.
+ +PhantomJS 1.5 "Ghost Flower" was released on March 20, 2012. It added pure headless (no X11) for the Linux version, improved troubleshooting with interactive mode and remote debugger, and a new system module.
+ +PhantomJS 1.4 "Glory of the Snow" was released on December 22, 2011. It is a minor update, mostly bug fixes and one new major feature: WebServer module.
+ +PhantomJS 1.3 "Water Lily" was released on September 23, 2011. It added preliminary module syntax, file system support, mouse events, and other page-related improvements.
+ +PhantomJS 1.2 "Birds of Paradise" was released on June 21, 2011. It implemented an abstraction for web page object, added support for rasterization and network traffic monitoring.
+ +PhantomJS 1.1 "Cherry Blossom" was released on April 27, 2011. It added supports for file upload, network proxy, disk cache, GIF output. In addition, scripts can now be written in CoffeeScript.
+ +