Python爬蟲制作之PhantomJS的入門用法
直接從瀏覽器中提取渲染好的HTML文檔。如果Ajax請求很多,有時請求參數(shù)還進(jìn)行了加密,我們手動分析每一個Ajax請求,將成為一項(xiàng)繁重的工作,而且沒有一定的JavaScript分析功底,很難做到。這個時候第二種方法的好處就體現(xiàn)出來了,直接提取瀏覽器渲染好的結(jié)果,不進(jìn)行Ajax請求分析,PhantomJS就是這樣的一個瀏覽器。
PhantomJS是一個基于WebKit的服務(wù)器端JavaScript API。它全面支持Web而無需瀏覽器支持,不僅運(yùn)行快,原生支持各種Web標(biāo)準(zhǔn):
DOM處理、CSS選擇器、JSON、Canvas,和SVG。PhantomJS可以用于頁面自動化、網(wǎng)絡(luò)監(jiān)測、網(wǎng)頁截屏,以及無界面測試等。
PhantomJS可以看做一個沒有界面的瀏覽器,它既有Firefox瀏覽器、
google瀏覽器的功能,又因?yàn)闆]有界面而更加快速,占更小的內(nèi)存,在爬蟲開發(fā)中非常受歡迎。
9.3.1 安裝PhantomJS
PhantomJS安裝方法有兩種,一種是下載源碼之后自行編譯,另一種是直接下載編譯好的二進(jìn)制文件,官方推薦直接使用編譯好的二進(jìn)制文件。安裝下載地址為:http://phantomjs.org/download.html,包括Windows、Mac OS、Linux版本,自行選擇對應(yīng)版本下載解壓即可,建議為PhantomJS設(shè)置環(huán)境變量。在下載的安裝包中,其中有一個example文件夾,里面有很多官方的例子可供學(xué)習(xí)和參考。
安裝完成后在命令行中輸入:phantomjs-v。如果正常顯示版本號,則證明安裝配置成功。圖9-5為Windows下的顯示結(jié)果。
圖9-5 phantomJS版本
9.3.2 快速入門
配置完成PhantomJS,下面使用它輸出“hello world”。新建一個JavaScript文件hello.js,代碼內(nèi)容為:
console.log('Hello, world!');
phantom.exit();
這時候在命令行中輸入:
phantomjs hello.js
輸出內(nèi)容為:Hello,world!。代碼中的第一句是在控制臺輸出“Hello,world!”,第二句是終止phantom的運(yùn)行,不然程序會一直運(yùn)行,不會停止。
通過上面的小例子我們已經(jīng)了解了PhantomJS的基本操作,PhantomJS還有一些有趣而且強(qiáng)大功能。
1.頁面加載
通過PhantomJS,一個網(wǎng)頁可以被加載、分析和通過創(chuàng)建網(wǎng)頁對象呈現(xiàn)。下面演示一個簡單的頁面加載的例子,并將當(dāng)前頁面進(jìn)行截圖保存。
pageload.js代碼如下:
var page = require('webpage').create();
page.open('http://www.cnblogs.com/qiyeboy/', function(status) { console.log("Status: " + status);
if(status === "success") { page.render('qiye.png');
} phantom.exit();
});
在命令行中運(yùn)行:
phantomjs pageload.js
輸出內(nèi)容為:Status:success,并在當(dāng)前目錄下生成對網(wǎng)頁的截圖qiye.png,如圖9-6所示。
圖9-6 qiye.png
代碼解釋:首先使用webpage模塊創(chuàng)建一個page對象,然后通過
page對象打開http://www.cnblogs.com/qiyeboy/網(wǎng)址,如果請求響應(yīng)狀態(tài)為success,則通過render方法將當(dāng)前頁面保存為qiye.png圖片。
除了打開網(wǎng)頁截圖之外,還可以對網(wǎng)頁的打開進(jìn)行測速。下面的例子用來計算一個網(wǎng)頁的加載速度,同時還用到了給JavaScript腳本傳遞參數(shù)的功能。loadspeed.js代碼如下:
var page = require('webpage').create(), system = require('system'), t, address;
if (system.args.length === 1) { console.log('Usage: loadspeed.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 ' + system.args[1]);
console.log('Loading time ' + t + ' msec');
} phantom.exit();
});
在命令行中輸入:
phantomjs loadspeed.js http://www.cnblogs.com/qiyeboy/
輸出結(jié)果為:
Loading http://www.cnblogs.com/qiyeboy/ Loading time 793 msec
代碼解釋:首先使用webpage模塊創(chuàng)建一個page對象,使用system模塊獲取系統(tǒng)對象system,并聲明了兩個變量t和address,用來保存時間和傳入?yún)?shù)。如果傳入?yún)?shù)的長度等于1,說明要加載的地址沒有傳入,進(jìn)行提示并退出phantom。為什么要等于1呢?因?yàn)?/span>
phantomjs loadspeed.js第一個參數(shù)是loadspeed.js。接著獲取當(dāng)前的時間,然后打開網(wǎng)頁,獲取加載完成后的時間,進(jìn)行相減即可。
2.代碼評估
為了評估網(wǎng)頁中的JavaScript代碼,可以利用evaluate。這個執(zhí)行是“沙盒式”的,它不會去執(zhí)行網(wǎng)頁外的JavaScript代碼。evaluate方法可以返回一個對象,然而返回值僅限于對象,不能包含函數(shù)(或閉包)。比如我們可以使用evaluate方法獲取http://www.cnblogs.com/
qiyeboy/頁面的標(biāo)題,evaluate.js代碼如下:
var url = 'http://www.cnblogs.com/qiyeboy/';
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();
});
在命令行中輸入:
phantomjs evaluate.js
輸出結(jié)果為:
Page title is七夜的故事 - 博客園
任何來自于網(wǎng)頁并且包括來自evaluate()內(nèi)部代碼的控制臺信息,默認(rèn)不會顯示。要覆蓋此行為,使用onConsoleMessage回調(diào)方法。將evaluate.js代碼改動如下:
var url = 'http://www.cnblogs.com/qiyeboy/';
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();
});
在命令行中輸入:
phantomjs evaluate.js
輸出結(jié)果為:
Page title is七夜的故事 - 博客園
9.3.3 屏幕捕獲
上節(jié)簡單講解了如何將網(wǎng)頁保存為一張圖片,下面詳細(xì)解釋一下這個屏幕捕獲的功能。由于PhantomJS使用的是WebKit內(nèi)核,一個真正的布局和渲染引擎,它可以捕捉一個網(wǎng)頁的屏幕截圖。另外
PhantomJS可以渲染網(wǎng)頁上的元素,所以它不僅可以用于HTML和CSS的內(nèi)容轉(zhuǎn)換,還可以用于SVG和畫布。PhantomJS不僅可以將網(wǎng)頁保存為png格式,還可以保存為jpg、gif和pdf格式。下面將
pageload.js代碼進(jìn)行改動,轉(zhuǎn)成pdf格式,代碼如下:
var page = require('webpage').create();
page.open('http://www.cnblogs.com/qiyeboy/', function(status) { console.log("Status: " + status);
if(status === "success") { page.render('qiye.pdf');
} phantom.exit();
});
最后生成的pdf文件,效果如圖9-7所示。
圖9-7 qiye.pdf
PhantomJS不僅可以將頁面轉(zhuǎn)化為不同的文件格式,還可以對視圖進(jìn)行縮放和裁剪,主要用到page對象中兩個非常重要的屬性:
viewportSize和clipRect。viewportSize是視區(qū)的大小,其作用可以看做是將打開的瀏覽器窗口進(jìn)行縮放。clipRect是在這個視區(qū)中裁剪矩形的大小,需要四個參數(shù),前兩個是基準(zhǔn)點(diǎn),后兩個參數(shù)是寬高。下面將pageload.js進(jìn)行改動,代碼如下:
var page = require('webpage').create();
page.viewportSize = { width: 1024, height: 768 };
page.clipRect = { top: 0, left: 0, width: 512, height: 256 };
page.open('http://www.cnblogs.com/qiyeboy/', function(status) { console.log("Status: " + status);
if(status === "success") { page.render('qiye.png');
} phantom.exit();
});
效果如圖9-8所示,只是截取出了頂端一角。
圖9-8 網(wǎng)頁裁剪
9.3.4 網(wǎng)絡(luò)監(jiān)控
因?yàn)镻hantomJS允許檢驗(yàn)網(wǎng)絡(luò)流量,因此它適合分析網(wǎng)絡(luò)行為和性能,實(shí)現(xiàn)對網(wǎng)絡(luò)的監(jiān)聽。當(dāng)向遠(yuǎn)程服務(wù)器發(fā)送請求時,可以使用
onResourceRequested和onResourceReceived兩個方法嗅探所有的資源請求和響應(yīng)。示例netmonitor.js代碼如下:
var url = 'http://www.cnblogs.com/qiyeboy/';
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);
在命令行中輸入:
phantomjs netmonitor.js
請求和響應(yīng)的信息會以JSON的格式進(jìn)行顯示,效果如圖9-9所示。
圖9-9 網(wǎng)絡(luò)監(jiān)控
9.3.5 頁面自動化
PhantomJS可以加載和處理一個網(wǎng)頁,非常適用于自動化處理,
PhantomJS中標(biāo)準(zhǔn)JavaScript的DOM操作和CSS選擇器都是生效的。
下面使用一個小例子講解一下DOM操作,獲取MTime時光網(wǎng)的影評信息,HTML標(biāo)記位置如圖9-10所示。
圖9-10 評分和票房標(biāo)記
示例代碼如下:
var page = require('webpage').create();
console.log('The default user agent is ' + page.settings.userAgent);
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:49.0)
Gecko/20100101 Firefox/49.0';
page.open('http://movie.mtime.com/108737/', function(status) { if (status !== 'success') { console.log('Unable to access network');
} else { var ua = page.evaluate(function() { return document.getElementById('ratingRegion').textContent;
});
console.log(ua);
} phantom.exit();
});
輸出結(jié)果如下:
The default user agent is Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/ 538.1(KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1 7.7總分:104,335人評分 4,299人想看音樂 畫面 導(dǎo)演 故事 …票房:5.
92億元
代碼解釋:首先創(chuàng)建page對象,接著將默認(rèn)的User-Agent進(jìn)行了修改,打開指定網(wǎng)頁,當(dāng)加載完成之后,執(zhí)行DOM操作,獲取id為
ratingRegion元素下的內(nèi)容,并打印出來。
大家可以看一下默認(rèn)UserAgent的內(nèi)容,會發(fā)現(xiàn)里面包含了
PhantomJS關(guān)鍵字,一些網(wǎng)站就是通過這個關(guān)鍵字來識別是否正在使用PhantomJS爬取數(shù)據(jù)。
在1.6版本之后PhantomJS允許添加外部的JS庫,比如下面的例子添加了jQuery,然后執(zhí)行了jQuery代碼。
var page = require('webpage').create();
page.open('http://www.sample.com', function() { page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min
.js", function() { page.evaluate(function() { $("button").click();
});
phantom.exit()
});
});
9.3.6 常用模塊和方法
上面的例子中我們用到了phantom、webpage和system模塊,在這三個模塊基礎(chǔ)上再講一個fs模塊。
1.phantom
對于phantom,主要講解其中的五個方法,如表9-2所示。
表9-2 phantom方法
2.webpage
對于webpage,主要說一下includeJs、open兩個普通方法,
onInitialized、onLoadFinished兩個回調(diào)方法。
includeJs方法原型為includeJs(url,callback){void},功能是包含從指定的URL獲取遠(yuǎn)程javaScript腳本,并執(zhí)行回調(diào)方法。示例代碼如下:
var webPage = require('webpage');
var page = webPage.create();
page.includeJs( // Include the https version, you can change this to http if you like.
'https:// ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js', function() { (page.evaluate(function() { // jQuery is loaded, now manipulate the DOM var $loginForm = $('form# login');
$loginForm.find('input[name="username"]').value('phantomjs');
$loginForm.find('input[name="password"]').value('c45p3r');
}))
} );
open方法比較復(fù)雜,有四種函數(shù)重載方式,分別為open(url,
callback){void}、open(url,method,callback){void}、
open(url,method,data,callback){void}、open(url,settings,
callback){void}。open(url,callback)方法之前已經(jīng)用過,第二種和第三種方式類似,所以下面主要說一下后兩種形式。
open(url,method,data,callback)中url為鏈接,method為
GET或者POST請求,data為附加的數(shù)據(jù),callback為回調(diào)函數(shù)。示例如下,用于發(fā)送一個POST請求。
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...
});
open(url,settings,callback)中url為鏈接,setting為對請求頭
和內(nèi)容的設(shè)置,callback為回調(diào)函數(shù)。示例如下:
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...
});
onInitialized是回調(diào)方法,在webpage對象被創(chuàng)建之后,url被加載之前被調(diào)用,主要是用來操作一些全局變量。示例代碼如下:
var webPage = require('webpage');
var page = webPage.create();
page.onInitialized = function() { page.evaluate(function() { document.addEventListener('DOMContentLoaded', function() { console.log('DOM content has loaded.');
}, false);
});
};
onLoadFinished是回調(diào)方法,在頁面加載完成之后調(diào)用,方法還有一個參數(shù)status。如果加載成功status為success,否則為fail。
webpage中open方法就是用這個方法作為回調(diào)函數(shù)。示例代碼如下:
var webPage = require('webpage');
var page = webPage.create();
page.onLoadFinished = function(status) { console.log('Status: ' + status);
// Do other things here...
};
3.system
system模塊只有屬性,沒有方法。下面通過表9-3列舉一下
system的屬性及其含義。
表9-3 system屬性
4.fs
fs模塊全稱為File System,主要是對文件系統(tǒng)進(jìn)行操作。該模塊方法很多,這里主要講解創(chuàng)建文件、判斷文件是否存在、讀寫文件的方法,如表9-4所示。
表9-4 fs方法
以上介紹了一些常用模塊和方法,如果大家想詳細(xì)了解相關(guān)內(nèi)容,可以去phantom官網(wǎng)(http://phantomjs.org/api/)查看完整的API文檔。
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答?。?點(diǎn)擊進(jìn)入論壇