?
本文檔使用 php中文網(wǎng)手冊(cè) 發(fā)布
概述
REPL環(huán)境
webpage模塊
open()
evaluate()
includeJs()
render()
viewportSize,zoomFactor
onResourceRequested
onResourceReceived
system模塊
應(yīng)用
過(guò)濾資源
截圖
抓取圖片
生成網(wǎng)頁(yè)
參考鏈接
有時(shí),我們需要瀏覽器處理網(wǎng)頁(yè),但并不需要瀏覽,比如生成網(wǎng)頁(yè)的截圖、抓取網(wǎng)頁(yè)數(shù)據(jù)等操作。PhantomJS的功能,就是提供一個(gè)瀏覽器環(huán)境的命令行接口,你可以把它看作一個(gè)“虛擬瀏覽器”,除了不能瀏覽,其他與正常瀏覽器一樣。它的內(nèi)核是WebKit引擎,不提供圖形界面,只能在命令行下使用,我們可以用它完成一些特殊的用途。
PhantomJS是二進(jìn)制程序,需要安裝后使用。
$ npm install phantomjs -g
使用下面的命令,查看是否安裝成功。
$ phantomjs --version
phantomjs提供了一個(gè)完整的REPL環(huán)境,允許用戶通過(guò)命令行與PhantomJS互動(dòng)。鍵入phantomjs,就進(jìn)入了該環(huán)境。
$ phantomjs
這時(shí)會(huì)跳出一個(gè)phantom提示符,就可以輸入Javascript命令了。
phantomjs> 1+2 3 phantomjs> function add(a,b) { return a+b; } undefined phantomjs> add(1,2) 3
按ctrl+c可以退出該環(huán)境。
下面,我們把上面的add()函數(shù)寫成一個(gè)文件add.js文件。
// add.js function add(a,b){ return a+b; } console.log(add(1,2)); phantom.exit();
上面的代碼中,console.log()的作用是在終端窗口顯示,phantom.exit()則表示退出phantomjs環(huán)境。一般來(lái)說(shuō),不管什么樣的程序,exit這一行都不能少。
現(xiàn)在,運(yùn)行該程序。
$ phantomjs add.js
終端窗口就會(huì)顯示結(jié)果為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", // ... }
webpage模塊是PhantomJS的核心模塊,用于網(wǎng)頁(yè)操作。
var webPage = require('webpage'); var page = webPage.create();
上面代碼表示加載PhantomJS的webpage模塊,并創(chuàng)建一個(gè)實(shí)例。
下面是webpage實(shí)例的屬性和方法介紹。
open方法用于打開具體的網(wǎng)頁(yè)。
var page = require('webpage').create(); page.open('http://slashdot.org', function (s) { console.log(s); phantom.exit(); });
上面代碼中,open()方法,用于打開具體的網(wǎng)頁(yè)。它接受兩個(gè)參數(shù)。第一個(gè)參數(shù)是網(wǎng)頁(yè)的網(wǎng)址,這里打開的是著名新聞網(wǎng)站Slashdot,第二個(gè)參數(shù)是回調(diào)函數(shù),網(wǎng)頁(yè)打開后該函數(shù)將會(huì)運(yùn)行,它的參數(shù)是一個(gè)表示狀態(tài)的字符串,如果打開成功就是success,否則就是fail。
注意,只要接收到服務(wù)器返回的結(jié)果,PhantomJS就會(huì)報(bào)告網(wǎng)頁(yè)打開成功,而不管服務(wù)器是否返回404或500錯(cuò)誤。
open方法默認(rèn)使用GET方法,與服務(wù)器通信,但是也可以使用其他方法。
var webPage = require('webpage'); var page = webPage.create(); var postBody = 'user=username&password=password'; page.open('http://www.google.com/', 'POST', postBody, function(status) { console.log('Status: ' + status); // Do other things here... });
上面代碼中,使用POST方法向服務(wù)器發(fā)送數(shù)據(jù)。open方法的第二個(gè)參數(shù)用來(lái)指定HTTP方法,第三個(gè)參數(shù)用來(lái)指定該方法所要使用的數(shù)據(jù)。
open方法還允許提供配置對(duì)象,對(duì)HTTP請(qǐng)求進(jìn)行更詳細(xì)的配置。
var webPage = require('webpage'); var page = webPage.create(); var settings = { operation: "POST", encoding: "utf8", headers: { "Content-Type": "application/json" }, data: JSON.stringify({ some: "data", another: ["custom", "data"] }) }; page.open('http://your.custom.api', settings, function(status) { console.log('Status: ' + status); // Do other things here... });
evaluate方法用于打開網(wǎng)頁(yè)以后,在頁(yè)面中執(zhí)行JavaScript代碼。
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(); });
網(wǎng)頁(yè)內(nèi)部的console語(yǔ)句,以及evaluate方法內(nèi)部的console語(yǔ)句,默認(rèn)不會(huì)顯示在命令行。這時(shí)可以采用onConsoleMessage回調(diào)函數(shù),上面的例子可以改寫如下。
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方法內(nèi)部有console語(yǔ)句,默認(rèn)不會(huì)輸出在命令行。這時(shí),可以用onConsoleMessage方法監(jiān)聽這個(gè)事件,進(jìn)行處理。
includeJs方法用于頁(yè)面加載外部腳本,加載結(jié)束后就調(diào)用指定的回調(diào)函數(shù)。
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() }); });
上面的例子在頁(yè)面中注入jQuery腳本,然后點(diǎn)擊所有的按鈕。需要注意的是,由于是異步加載,所以phantom.exit()
語(yǔ)句要放在page.includeJs()
方法的回調(diào)函數(shù)之中,否則頁(yè)面會(huì)過(guò)早退出。
render方法用于將網(wǎng)頁(yè)保存成圖片,參數(shù)就是指定的文件名。該方法根據(jù)后綴名,將網(wǎng)頁(yè)保存成不同的格式,目前支持PNG、GIF、JPEG和PDF。
var webPage = require('webpage'); var page = webPage.create(); page.viewportSize = { width: 1920, height: 1080 }; page.open("http://www.google.com", function start(status) { page.render('google_home.jpeg', {format: 'jpeg', quality: '100'}); phantom.exit(); });
該方法還可以接受一個(gè)配置對(duì)象,format字段用于指定圖片格式,quality字段用于指定圖片質(zhì)量,最小為0,最大為100。
viewportSize屬性指定瀏覽器視口的大小,即網(wǎng)頁(yè)加載的初始瀏覽器窗口大小。
var webPage = require('webpage'); var page = webPage.create(); page.viewportSize = { width: 480, height: 800 };
viewportSize的Height字段必須指定,不可省略。
zoomFactor屬性用來(lái)指定渲染時(shí)(render方法和renderBase64方法)頁(yè)面的放大系數(shù),默認(rèn)是1(即100%)。
var webPage = require('webpage'); var page = webPage.create(); page.zoomFactor = 0.25; page.render('capture.png');
onResourceRequested屬性用來(lái)指定一個(gè)回調(diào)函數(shù),當(dāng)頁(yè)面請(qǐng)求一個(gè)資源時(shí),會(huì)觸發(fā)這個(gè)回調(diào)函數(shù)。它的第一個(gè)參數(shù)是HTTP請(qǐng)求的元數(shù)據(jù)對(duì)象,第二個(gè)參數(shù)是發(fā)出的網(wǎng)絡(luò)請(qǐng)求對(duì)象。
HTTP請(qǐng)求包括以下字段。
id:所請(qǐng)求資源的編號(hào)
method:使用的HTTP方法
url:所請(qǐng)求的資源 URL
time:一個(gè)包含請(qǐng)求時(shí)間的Date對(duì)象
headers:HTTP頭信息數(shù)組
網(wǎng)絡(luò)請(qǐng)求對(duì)象包含以下方法。
abort():終止當(dāng)前的網(wǎng)絡(luò)請(qǐng)求,這會(huì)導(dǎo)致調(diào)用onResourceError回調(diào)函數(shù)。
changeUrl(newUrl):改變當(dāng)前網(wǎng)絡(luò)請(qǐng)求的URL。
setHeader(key, value):設(shè)置HTTP頭信息。
var webPage = require('webpage'); var page = webPage.create(); page.onResourceRequested = function(requestData, networkRequest) { console.log('Request (#' + requestData.id + '): ' + JSON.stringify(requestData)); };
onResourceReceived屬性用于指定一個(gè)回調(diào)函數(shù),當(dāng)網(wǎng)頁(yè)收到所請(qǐng)求的資源時(shí),就會(huì)執(zhí)行該回調(diào)函數(shù)。它的參數(shù)就是服務(wù)器發(fā)來(lái)的HTTP回應(yīng)的元數(shù)據(jù)對(duì)象,包括以下字段。
id:所請(qǐng)求的資源編號(hào)
url:所請(qǐng)求的資源的URL r- time:包含HTTP回應(yīng)時(shí)間的Date對(duì)象
headers:HTTP頭信息數(shù)組
bodySize:解壓縮后的收到的內(nèi)容大小
contentType:接到的內(nèi)容種類
redirectURL:重定向URL(如果有的話)
stage:對(duì)于多數(shù)據(jù)塊的HTTP回應(yīng),頭一個(gè)數(shù)據(jù)塊為start,最后一個(gè)數(shù)據(jù)塊為end。
status:HTTP狀態(tài)碼,成功時(shí)為200。
statusText:HTTP狀態(tài)信息,比如OK。
如果HTTP回應(yīng)非常大,分成多個(gè)數(shù)據(jù)塊發(fā)送,onResourceReceived會(huì)在收到每個(gè)數(shù)據(jù)塊時(shí)觸發(fā)回調(diào)函數(shù)。
var webPage = require('webpage'); var page = webPage.create(); page.onResourceReceived = function(response) { console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response)); };
system模塊可以加載操作系統(tǒng)變量,system.args就是參數(shù)數(shù)組。
var page = require('webpage').create(), system = require('system'), t, address; // 如果命令行沒(méi)有給出網(wǎng)址 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可以實(shí)現(xiàn)多種應(yīng)用。
處理頁(yè)面的時(shí)候,有時(shí)不希望加載某些特定資源。這時(shí),可以對(duì)URL進(jìn)行匹配,一旦符合規(guī)則,就中斷對(duì)資源的連接。
page.onResourceRequested = function(requestData, request) { if ((/http:\/\/.+?\.css$/gi).test(requestData['url'])) { console.log('Skipping', requestData['url']); request.abort(); } };
上面代碼一旦發(fā)現(xiàn)加載的資源是CSS文件,就會(huì)使用request.abort
方法中斷連接。
最簡(jiǎn)單的生成網(wǎng)頁(yè)截圖的方法如下。
var page = require('webpage').create(); page.open('http://google.com', function () { page.render('google.png'); phantom.exit(); });
page對(duì)象代表一個(gè)網(wǎng)頁(yè)實(shí)例;open方法表示打開某個(gè)網(wǎng)址,它的第一個(gè)參數(shù)是目標(biāo)網(wǎng)址,第二個(gè)參數(shù)是網(wǎng)頁(yè)載入成功后,運(yùn)行的回調(diào)函數(shù);render方法則是渲染頁(yè)面,然后以圖片格式輸出,該方法的參數(shù)就是輸出的圖片文件名。
除了簡(jiǎn)單截圖以外,還可以設(shè)置各種截圖參數(shù)。
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格式的字符串輸出。
下面的例子則是使用了更多參數(shù)。
// 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); } });
上面代碼中的幾個(gè)屬性和方法解釋如下:
settings.userAgent:指定HTTP請(qǐng)求的userAgent頭信息,上面例子是手機(jī)瀏覽器的userAgent。
settings.viewportSize:指定瀏覽器窗口的大小,這里是400x600。
evaluate():用來(lái)在網(wǎng)頁(yè)上運(yùn)行Javascript代碼。在這里,我們抓取第一條新聞,然后修改背景顏色,并返回該條新聞的標(biāo)題。
clipRect:用來(lái)指定網(wǎng)頁(yè)截圖的大小,這里的截圖左上角從網(wǎng)頁(yè)的(0. 0)坐標(biāo)開始,寬600像素,高700像素。如果不指定這個(gè)值,就表示對(duì)整張網(wǎng)頁(yè)截圖。
render():根據(jù)clipRect的范圍,在當(dāng)前目錄下生成以第一條新聞的名字命名的截圖。
使用官方網(wǎng)站提供的rasterize.js,可以抓取網(wǎng)絡(luò)上的圖片,將起保存在本地。
phantomjs rasterize.js http://ariya.github.com/svg/tiger.svg tiger.png
使用rasterize.js,還可以將網(wǎng)頁(yè)保存為pdf文件。
phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
phantomjs可以生成網(wǎng)頁(yè),使用content方法指定網(wǎng)頁(yè)的HTML代碼。
var page = require('webpage').create(); page.viewportSize = { width: 400, height : 400 }; page.content = '<html><body><canvas id="surface"></canvas></body></html>'; phantom.exit();
官方網(wǎng)站有一個(gè)例子,通過(guò)創(chuàng)造svg圖片,然后截圖保存成png文件。
BenjaminBenBen, Using PhantomJS WebServer
Ariya Hidayat, Capturing Web Page Without Stylesheets: 過(guò)濾CSS文件