有時,我們需要瀏覽器處理網頁,但並不需要瀏覽,比如生成網頁的截圖、抓取網頁數據等操作。PhantomJS的功能,就是提供一個瀏覽器環境的命令行接口,你可以把它看作一個“虛擬瀏覽器”,除了不能瀏覽,其他與正常瀏覽器一樣。它的內核是WebKit引擎,不提供圖形界面,只能在命令行下使用,我們可以用它完成一些特殊的用途。
PhantomJS是二進制程序,需要安裝后使用。使用下面的命令,查看是否安裝成功。
phantomjs --version
REPL環境
phantomjs提供了一個完整的REPL環境。鍵入phantomjs,就進入了該環境。
$ phantomjs
這時會跳出一個phantom提示符,就可以輸入Javascript命令了。
phantomjs> 1+2
3
phantomjs> function add(a,b) { return a+b; }
undefined
phantomjs> add(1,2)
3
按ctrl+c可以退出該環境。
下面,我們把上面的add()函數寫成一個文件add.js文件。
// add.js
function add(a,b){ return a+b; }
console.log(add(1,2));
phantom.exit();
上面的代碼中,console.log()的作用是在終端窗口顯示,phantom.exit()則表示退出phantomjs環境。一般來說,不管什么樣的程序,這一行都不能少。
現在,運行該程序:
$ phantomjs add.js
終端窗口就會顯示結果為3。
下面是更多的例子。
phantomjs> phantom.version
{
"major": 1,
"minor": 5,
"patch": 0
}
phantomjs> console.log("phantom is awesome")
phantom is awesome
phantomjs> window.navigator
{
"cookieEnabled": true,
"language": "en-GB",
"productSub": "20030107",
"product": "Gecko",
// ...
}
基本用法
加載網頁
下面,我們用PhantomJS加載網頁。新建一個文本文件page.js,寫入下面的代碼:
// page.js
var page = require('webpage').create();
page.open('http://slashdot.org', function (s) {
console.log(s);
phantom.exit();
});
第一行require('webpage').create() 表示加載網頁模塊,並創建一個實例。
第二行open()方法,接受兩個參數。第一個參數是網頁的網址,這里我們打開的是著名新聞網站Slashdot,第二個參數是回調函數,當網頁打開后,該函數將會運行,它的參數是狀態提示(status),如果打開成功,該參數的值就是success。運行page.js,屏幕將會顯示success。
執行代碼
打開網頁以后,可以使用page實例的evaluate方法,在頁面中執行代碼。
var page = require('webpage').create();
page.open(url, function(status) {
var title = page.evaluate(function() {
return document.title;
});
console.log('Page title is ' + title);
phantom.exit();
});
網頁內部的console語句,以及evaluate方法內部的console語句,默認不會顯示在命令行。這時可以采用onConsoleMessage回調函數,上面的例子可以改寫如下。
var page = require('webpage').create();
page.onConsoleMessage = function(msg) {
console.log('Page title is ' + msg);
};
page.open(url, function(status) {
page.evaluate(function() {
console.log(document.title);
});
phantom.exit();
});
上面代碼中,evaluate方法內部有console語句,默認不會輸出在命令行。這時,可以用onConsoleMessage方法監聽這個事件,進行處理。
加載資源
如果網頁實例向遠程服務器請求資源,這時HTTP請求(request)和HTTP回應可以用onResourceRequested和onResourceReceived追蹤。
var page = require('webpage').create();
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);
上面代碼會以JSON格式,輸出所有HTTP請求和HTTP回應的頭信息。
page實例的includeJs方法,用於頁面加載外部腳本。
var page = require('webpage').create();
page.open('http://www.sample.com', function() {
page.includeJs("http://path/to/jquery.min.js", function() {
page.evaluate(function() {
$("button").click();
});
phantom.exit()
});
});
上面的例子在頁面中注入jQuery腳本,然后點擊所有的按鈕。需要注意的是,由於是異步加載,所以phantom.exit()
語句要放在page.evaluate()
方法的回調函數之中,否則頁面會過早退出。
接受參數
修改page.js,使得它可以從命令行接受參數。
system模塊可以加載操作系統變量,system.args就是參數數組。
var page = require('webpage').create(),
system = require('system'),
t, address;
// 如果命令行沒有給出網址
if (system.args.length === 1) {
console.log('Usage: page.js <some URL>');
phantom.exit();
}
t = Date.now();
address = system.args[1];
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
} else {
t = Date.now() - t;
console.log('Loading time ' + t + ' ms');
}
phantom.exit();
});
使用方法如下:
phantomjs page.js http://www.google.com
應用
Phantomjs可以實現多種應用。
過濾資源
處理頁面的時候,有時不希望加載某些特定資源。這時,可以對URL進行匹配,一旦符合規則,就中斷對資源的連接。
page.onResourceRequested = function(requestData, request) {
if ((/http:\/\/.+?\.css$/gi).test(requestData['url'])) {
console.log('Skipping', requestData['url']);
request.abort();
}
};
上面代碼一旦發現加載的資源是CSS文件,就會使用request.abort
方法中斷連接。
截圖
最簡單的生成網頁截圖的方法如下。
var page = require('webpage').create();
page.open('http://google.com', function () {
page.render('google.png');
phantom.exit();
});
page對象代表一個網頁實例;open方法表示打開某個網址,它的第一個參數是目標網址,第二個參數是網頁載入成功后,運行的回調函數;render方法則是渲染頁面,然后以圖片格式輸出,該方法的參數就是輸出的圖片文件名。
除了簡單截圖以外,還可以設置各種截圖參數。
var page = require('webpage').create();
page.open('http://google.com', function () {
page.zoomFactor = 0.25;
console.log(page.renderBase64());
phantom.exit();
});
zoomFactor表示將截圖縮小至原圖的25%大小;renderBase64方法則是表示將截圖(PNG格式)編碼成Base64格式的字符串輸出。
下面的例子則是使用了更多參數。
// page.js
var page = require('webpage').create();
page.settings.userAgent = 'WebKit/534.46 Mobile/9A405 Safari/7534.48.3';
page.settings.viewportSize = { width: 400, height: 600 };
page.open('http://slashdot.org', function (status) {
if (status !== 'success') {
console.log('Unable to load!');
phantom.exit();
} else {
var title = page.evaluate(function () {
var posts = document.getElementsByClassName("article");
posts[0].style.backgroundColor = "#FFF";
return document.title;
});
window.setTimeout(function () {
page.clipRect = { top: 0, left: 0, width: 600, height: 700 };
page.render(title + "1.png");
page.clipRect = { left: 0, top: 600, width: 400, height: 600 };
page.render(title + '2.png');
phantom.exit();
}, 1000);
}
});
上面代碼中的幾個屬性和方法解釋如下:
- settings.userAgent:指定HTTP請求的userAgent頭信息,上面例子是手機瀏覽器的userAgent。
- settings.viewportSize:指定瀏覽器窗口的大小,這里是400x600。
- evaluate():用來在網頁上運行Javascript代碼。在這里,我們抓取第一條新聞,然后修改背景顏色,並返回該條新聞的標題。
- clipRect:用來指定網頁截圖的大小,這里的截圖左上角從網頁的(0. 0)坐標開始,寬600像素,高700像素。如果不指定這個值,就表示對整張網頁截圖。
- render():根據clipRect的范圍,在當前目錄下生成以第一條新聞的名字命名的截圖。
抓取圖片
使用官方網站提供的rasterize.js,可以抓取網絡上的圖片,將起保存在本地。
phantomjs rasterize.js http://ariya.github.com/svg/tiger.svg tiger.png
使用rasterize.js,還可以將網頁保存為pdf文件。
phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
生成網頁
phantomjs可以生成網頁,使用content方法指定網頁的HTML代碼。
var page = require('webpage').create();
page.viewportSize = { width: 400, height : 400 };
page.content = '<html><body><canvas id="surface"></canvas></body></html>';
phantom.exit();
官方網站有一個例子,通過創造svg圖片,然后截圖保存成png文件。
http://javascript.ruanyifeng.com/tool/phantomjs.html#
Python例子:
-
用python獲取數據。然后就開始處理了。具體的處理邏輯就不展示了。