編寫爬蟲時,如果單純是靜態(tài)網(wǎng)站驼仪,Nodejs的cheerio,requests以及Python的urlib懂牧、urlib2與request(BeautifulSoup)就能解決需求。如果碰上網(wǎng)站通過AJAX獲取數(shù)據(jù)或者JS延遲獲取數(shù)據(jù)時有序。上面的技術(shù)棧就比較難獲取到我們想要的數(shù)據(jù)握巢,PhantomJS這個無界面瀏覽器晕鹊,又有人稱"虛擬瀏覽器"就派上用場了。
Phantomjs的功能,就是提供一個命令行下使用捏题,它是基于Webkit內(nèi)核玻褪,我們可以使用像正常的瀏覽器訪問所需的網(wǎng)站。在某些時候公荧,很多的人搭配著selenium+phantomjs搭建可以訪問動態(tài)獲取數(shù)據(jù)的網(wǎng)站带射,現(xiàn)在先說phantomjs在爬蟲中的用法。
- 1.安裝phantomjs
- phantomjs是個二進制程序循狰,可以到phantomjs官網(wǎng)下載窟社。如果你安裝了nodejs的npm包管理器,也可以直接運行下面命令安裝:
npm install phantomjs -g
- 2.如果是直接下載phantomjs二進制文件绪钥,還需要把程序文件的路徑添加到環(huán)境變量的path里灿里。這樣方便我們直接在全局調(diào)用phantomjs。
- 3.在windows的DOS命令行窗口程腹,直接輸入phantomjs直接開啟程序匣吊,phantomjs為我們提供RPEL環(huán)境,可以直接解釋javascript寸潦。
- 4.在phantomjs提供的REPL環(huán)境下輸入以下命令色鸳,可以實例輸出
# >>>表示是輸出行
phantomjs --version
>>>2.1.1
phantomjs>window.navigator
{
"appCodeName": "Mozilla",
"appName": "Netscape",
"appVersion": "5.0 (Windows NT 6.1; WOW64) AppleWebKit/538.1 (KHTML, like Gec
ko) PhantomJS/2.1.1 Safari/538.1",
"cookieEnabled": true,
"language": "zh-CN",
"mimeTypes": {
"length": 0
},
"onLine": true,
"platform": "Win32",
"plugins": {
"length": 0
},
"product": "Gecko",
"productSub": "20030107",
"userAgent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/538.1 (KHTML, l
ike Gecko) PhantomJS/2.1.1 Safari/538.1",
"vendor": "Apple Computer, Inc.",
"vendorSub": ""
}
- 5.打開sublimetext編寫一個js文件,代碼如下见转;并且運用phantomjs運行代碼文件命雀。在阮一峰老師phantomjs文檔強調(diào),不管怎么樣的程序里面斩箫,phantom.exit()這行不能少吏砂。phantom.exit()表示退出REPL環(huán)境:
#代碼實例代碼
function plus(a,b){
return a*b;
}
console.log(plus(1,2));
phantom.exit()
#以下為命令行窗口運行的情況
>phantomjs spider.js
2
- 6.webpage模塊:open()
- webpage模塊是phantomjs核心的模塊:可以把webpage看做一個類,通過實例化webpage類對象乘客,然后調(diào)用對象的方法進行獲取網(wǎng)頁狐血,最后使用類方法進行操作。
- open(url,callback):open方法默認第一個參數(shù)為url地址易核,callback是回調(diào)函數(shù)氛雪,參數(shù)只有Status。無論后臺服務(wù)器返回的是500或者400狀態(tài)碼耸成,status的狀態(tài)值都是success的值。
- open()方法默認是以get方法獲取數(shù)據(jù)浴鸿;open()方法也可以使用其他的方式井氢;例如以post方式,open(url,'post',postData,callback)岳链;open方法的第二個參數(shù)用來指定HTTP方法花竞,第三個參數(shù)用來指定所要傳遞的參數(shù)。
- 下面給出簡單的完整的獲取百度首頁的代碼:
# 這是默認get的獲取方法
var webPage=require('webpage');
#設(shè)置網(wǎng)頁的編碼格式,如果不設(shè)置约急,會出現(xiàn)亂碼情況
phantom.outputEncoding="gbk";
#創(chuàng)建一個webpage實例對象
var page=webPage.create();
var tbUrl="https://www.baidu.com";
#設(shè)置瀏覽器偽headers
page.settings.userAgent="Mozilla/5.0(Windows NT 6.1;Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36";
# 調(diào)用open方法打開具體網(wǎng)頁零远,默認以get請求獲取
page.open(tbUrl,function (status) {
setTimeout(function(){
var result=pageTab.evaluate(function(){
return document.body
});
console.log(result.toString());
pageTab.render("1.png");
phantom.exit();
},4000);
})
#post方法傳參數(shù)獲取網(wǎng)頁數(shù)據(jù)
var webPage=require('webpage');
var page=webPage.create();
var postData="username&password"
page.open('http://www.kiwis.com/','post',postData,function(status){
console.log(status);
phantom.exit();
});
# open()方法提供配置對象,對HTTP請求進行詳細的配置
var webPage=require('webpage');
var page=webPage.create();
var setting={
operation:"POST",
encoding:"urf8",
headers:{
"Content-Type":"application/json"
},
data:JSON.stringify({
some:'something',
others:['data1']
})
};
page.open("http://www.kiwis.com",setting,function(status){
console.log("Status:"+status);
phantom.exit();
});
- 7.webpage模塊:evaluate()方法
- evaluate(callback):evaluate方法可以在數(shù)據(jù)網(wǎng)頁返回之后厌蔽,可以直接evaluate執(zhí)行javascript語句進行數(shù)據(jù)的提取和解析牵辣,這也是使用phantomjs作為爬蟲提取數(shù)據(jù)的關(guān)鍵所在。
var webpage=require('webpage');
page=webPage.create();
page.open("https://www.baidu.com",function(status){
var title=page.evaluate(function(){
console.log(document.title);
return document.title;
});
phantom.exit();
});
- 8.webpage模塊:onConsoleMessage():在網(wǎng)頁內(nèi)的console語句和evaluate方法內(nèi)部的console語句奴饮,默認不會顯示在標(biāo)準輸出面板纬向,所以phantomjs模塊提供了onConsoleMessage方法進行監(jiān)聽console的觸發(fā)事件,進行輸出戴卜。
var webPage=require('webpage');
var page=webPage.create();
page.onConsoleMessage(function(data){
console.log("the pass data is"+data);
});
page.open(url,function(status){
if(status){
console.log("hello world!");
}
phantom.exit();
});
- 9.webpage模塊:includeJs()方法逾条。
- includeJs(resourceURL,callback)方法提供了加載外部腳本的功能,使用phantomjs的includeJs對前端jser簡直是福音的存在投剥;在提取數(shù)據(jù)時可以直接加載jQuery庫操作师脂;以前在使用后端服務(wù)的Nodejs的Request和cheerio(服務(wù)端的jquery)腳本爬蟲時會覺得提取XML或HTML中的數(shù)據(jù)時還擔(dān)心前端jquery語法和cheerio不兼容;現(xiàn)在麻麻再也不用擔(dān)心啦江锨。
- includeJs方法在加載完成外部資源或者腳本之后就自動調(diào)用回調(diào)函數(shù)吃警。
var webPage=require('webpage');
var page=webPage.create();
page.open("https://www.baidu.com",function(status){
page.includeJs("https://code.jquery.com/jquery-3.2.1.min.js",function(){
page.evaluate(function(){
$('.su').click();
});
});
});
- 10.webpage模塊:render():
- render方法用于將網(wǎng)頁保存成圖片,參數(shù)就是要保存的圖片路徑泳桦。方法可以根據(jù)路徑的后綴名汤徽,將網(wǎng)頁保存成png、Gif灸撰、jpeg和pdf谒府。方法可以接受一個配置對象,format字段用于圖片格式浮毯,quality字段用于圖片質(zhì)量完疫,最差是0,最好是100债蓝;renderBase64方法就是把截圖png格式編碼成Base64格式的字符串輸出壳鹤。
var webPage=require("webpage");
var page=webPage.create();
page.viewportSize={widtth:960,height:580};
page.open("http://www.baidu.com",function(status){
page.render("1.png",{format:"png",quality:"100"});
phantom.exit()
});
- 11.webpage模塊:viewportSize,zoomFactor
- viewportSize屬性是指定打開的瀏覽器窗口大小(如上節(jié)所示),即網(wǎng)頁的初始化瀏覽器窗口大小。viewportSize的height字段是必須參數(shù)饰迹,不可省略芳誓。
- zoomFactor屬性指定渲染頁面的放大系數(shù)(1即100%)
var webPage=require('webpage');
var page=webPage.create();
page.viewportISize={
width:920,
height:480
};
page.zoomFactor=1;
page.render("1.png");
- 12.webpage模塊:onResouceRequested
- onResourceRequested屬性用來指定一個回調(diào)函數(shù),當(dāng)頁面請求一個資源時啊鸭,會觸發(fā)這個回調(diào)函數(shù)锹淌。第一個參數(shù)是HTTP請求的數(shù)據(jù)對象,第二個參數(shù)是發(fā)出的網(wǎng)絡(luò)請求對象赠制。
- http請求數(shù)據(jù):
- id:請求資源編號
- method:使用http方法
- url:所請求的資源url
- headers:http頭信息數(shù)組
- 網(wǎng)絡(luò)請求對象包含以下方法:
- abort():終止當(dāng)前網(wǎng)絡(luò)請求赂摆,網(wǎng)絡(luò)請求終止會觸發(fā)onResourceError回調(diào)函數(shù)
- changeUrl(newUrl):改變當(dāng)前網(wǎng)絡(luò)請求的URL
- setHeader(key,value):設(shè)置http頭信息
var webPage=require('webpage');
var page=webPage.create();
page.onResourceRequested=function(requestData,RequestObj){
console.log('request'+requestData.id+'----'+JSON.stringify(requestData));
}
//過濾資源應(yīng)用
page.onResourceRequested=function(requestData,RequestObj){
if((/http:\/\/.+?\.css$/gi).test(requestData['url'])){
console.log("abort this resource");
request.abort();
}
}
- 13.webpage模塊:onResourceReceived
- onResourceReceived屬性用于指定一個回調(diào)函數(shù),當(dāng)網(wǎng)頁收到所請求的資源時,就會執(zhí)行該回調(diào)函數(shù)烟号。它的參數(shù)就是服務(wù)器發(fā)來的HTTP回應(yīng)的元數(shù)據(jù)對象绊谭。如果http回應(yīng)非常大,分成多個數(shù)據(jù)塊發(fā)送汪拥,onResourceReceived會在多次收到數(shù)據(jù)塊時觸發(fā)回調(diào)函數(shù)达传。
- 元數(shù)據(jù)對象包含以下字段:
- id:所請求的資源編號
- url:所請求資源的url
- time:包含http回應(yīng)時間的Date對象
- headers:http頭信息數(shù)組
- bodySize:解壓縮的收到的內(nèi)容大小
- content-Type:接到的內(nèi)容種類
- redirectURL:重定向URL(如果有的話)
- stage:對多數(shù)據(jù)塊的http響應(yīng)
- status:HTTP狀態(tài)碼,如404,200
- statusText:http狀態(tài)信息喷楣,比如OK
var webPage=require('webpage');
var page=webPage.create();
page.onResourceReceived=function(response){
console.log("response"+response.status+response.statusText);
}
- 14.System模塊:system模塊可以加載操作系統(tǒng)變量趟大,System.args就是參數(shù)數(shù)組。
- 在命令行下運行 phantomjs 1.js http://www.baidu.com;其中1.js就是下面的代碼
var webpage=require('webpage')
var system=require('system');
var t,address;
//如果命令行沒有給出網(wǎng)址
if(system.args.length===1){
console.log("the url address is need!");
phantom.exit();
}
t=Date.now();
address=system.args[1];
page.open(address,function(status){
if(status!=="success"){
console.log("failed to get webpage");
}else{
t=Date.now()-t;
console.log("Loading time"+t+"ms");
}
phantom.exit();
});
- 15.綜合運用例子:
- 下面是請求http://www.360kan.com網(wǎng)址的示例:
var webPage=require('webpage');
//設(shè)置網(wǎng)頁編碼格式
phantom.outputEncoding="gbk";
var pageTab=webPage.create();
var tbUrl="http://www.360kan.com/";
//設(shè)置請求頭信息
pageTab.settings.userAgent="Mozilla/5.0(Windows NT 6.1;Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36";
pageTab.open(tbUrl,function (status) {
//360kan網(wǎng)址的數(shù)據(jù)是動態(tài)加載的铣焊,這里等待2秒在執(zhí)行其他操作逊朽。
setTimeout(function(){
pageTab.includeJs("http://code.jquery.com/jquery-3.2.1.min.js", function() {
pageTab.evaluate(function() {
var lists=$(".name");
for(i=0;i<lists.length;i++){
var list=lists[i];
console.log(lists.text()+"\n");
}
});
phantom.exit()
});
},2000);
})
pageTab.onConsoleMessage = function(msg) {
console.log('Page title is ' + msg);
};
- 16.Phantomjs官方翻譯文檔示例:
- setting.userAgent指定http請求的userAgent頭信息
- setting.viewportSize:z指定瀏覽器窗口的大小
- clipRect:指定截圖的大小,第一參數(shù)top(距離瀏覽器上面多少距離)曲伊;第二參數(shù)是left(距離左邊多少)叽讳;width和height從字面可以知道是寬高大小。
var webpage=require('webpage');
var page=webpage.create();
page.setting.UserAgent="webkit/534.46 Mobile/9A405 safari/7534.48.3";
page.setting.viewportSize={width:400,height:600};
page.open("http://www.baidu.com",function(status){
if(status!=="success"){
console.log("load failed");
phantom.exit();
}else{
var title=page.evaluate(function(){
return document.title;
});
window.setTimeout(function(){
page.clipRect={top:0,left:0,width:600,height:400};
page.render(title+".png");
page.clipRect={left:0,top:600,width:400,height:400};
page.render(title+"1.png");
phantom.exit();
});
}
});
上面是phantomjs的常用使用方法坟募,下一篇關(guān)于selenium2和phantomjs結(jié)合使用爬蟲js延遲或者AJAX獲取數(shù)據(jù)的提取方式實例岛蚤。
資料參考來自:
1.阮一峰老師 phantomJS
2.騰云閣社區(qū)關(guān)于phantomjs使用