很多時(shí)候我們?cè)陂_(kāi)發(fā)網(wǎng)頁(yè)時(shí),需要用到瀏覽器動(dòng)態(tài)生成頁(yè)面的功能,但是讓瀏覽器無(wú)限制的加載就會(huì)增加服務(wù)器負(fù)擔(dān),因此在這種情況下我們就需要一個(gè)無(wú)頭瀏覽器,PhantomJS 是其中一個(gè)很好的選擇。同時(shí),我們的服務(wù)器語(yǔ)言——PHP也可以很好的與 PhantomJS 相結(jié)合,實(shí)現(xiàn)瀏覽器自動(dòng)化任務(wù)。
舉例來(lái)說(shuō),遇到這樣一個(gè)需求:我們需要自動(dòng)獲取某個(gè)網(wǎng)頁(yè)上的圖片并保存到本地,進(jìn)一步來(lái)講,當(dāng)網(wǎng)頁(yè)上的圖片數(shù)量固定時(shí),我們可以通過(guò)獲取圖片的 src 屬性,都保存在一個(gè)數(shù)組里,再用循環(huán)遍歷數(shù)組里存儲(chǔ)的 URL,將每一個(gè)圖片保存到本地。因此可以寫(xiě)一個(gè) PHP 文件:
<?php
$url = 'https://www.baidu.com/';
$imgs = array();
//調(diào)用 PhantomJS 獲取網(wǎng)頁(yè)內(nèi)容
$pageData = exec('phantomjs getWebResources.js ' . $url);
//從 HTML 頁(yè)面內(nèi)提取出所有的圖片
$html = new DOMDocument();
@$html->loadHTML($pageData);
$elements = $html->getElementsByTagName('img');
foreach($elements as $e) {
$imgs[] = $e->getAttribute('src');
}
//遍歷圖片地址,保存到本地
foreach($imgs as $img_url){
$img_content = file_get_contents( $img_url );
file_put_contents( basename($img_url), $img_content );
}
?>
其中 getWebResources.js 文件是一個(gè) PhantomJS 腳本文件,用來(lái)獲取網(wǎng)頁(yè)上所有資源,包括 HTML、CSS、JS、圖片等,并將所有的資源內(nèi)容輸出到標(biāo)準(zhǔn)輸出流。具體代碼如下:
//引入必要的模塊
var system = require('system'),fs = require('fs'),webpage = require('webpage');
//讀取執(zhí)行命令時(shí)傳入的參數(shù),例如:phantomjs getWebResources.js https://www.baidu.com/
var url = system.args[1],res = {'html':null,'css':[],'js':[],'img':[]};
//創(chuàng)建一個(gè)瀏覽器頁(yè)面
var page = webpage.create();
//設(shè)置選擇器獲取CSS文件鏈接
function getCss() {
var stylesheets = document.getElementsByTagName('link');
for (var j = 0; j< stylesheets.length; j++) {
var style = stylesheets[j];
if (style.rel.toLowerCase() != 'stylesheet') {
continue;
}
var href = style.href;
if (href.indexOf('http', 0) === 0) {
res.css.push(href);
} else if (href.indexOf('file:///') === 0) {
res.css.push(href.substr(8));
} else if (href.indexOf('/') === 0) {
res.css.push(href);
} else {
res.css.push(url + '/' + href);
}
}
}
//設(shè)置選擇器獲取JS文件鏈接
function getJs() {
var scripts = document.getElementsByTagName('script');
for (var j = 0; j< scripts.length; j++) {
var script = scripts[j];
if (script.src) {
if (script.src.indexOf('http', 0) === 0) {
res.js.push(script.src);
} else if (script.src.indexOf('file:///') === 0) {
res.js.push(script.src.substr(8));
} else if (script.src.indexOf('/') === 0) {
res.js.push(script.src);
} else {
res.js.push(url + '/' + script.src);
}
}
}
}
//設(shè)置選擇器獲取圖片鏈接
function getImg() {
var imgs = document.getElementsByTagName('img');
for (var j = 0; j < imgs.length; j++) {
var imgsrc = imgs[j].src;
if (imgsrc.indexOf('http', 0) === 0) {
res.img.push(imgsrc);
} else if (imgsrc.indexOf('file:///') === 0) {
res.img.push(imgsrc.substr(8));
} else if (imgsrc.indexOf('/') === 0) {
res.img.push(imgsrc);
} else {
res.img.push(url + '/' + imgsrc);
}
}
}
//當(dāng)頁(yè)面加載完成時(shí),輸出資源內(nèi)容到標(biāo)準(zhǔn)輸出流
page.onLoadFinished = function(status){
var title = page.evaluate(function() {return document.title;});
res.html = page.content;
getCss();getJs();getImg();
console.log(JSON.stringify(res));
phantom.exit();
};
//開(kāi)始加載頁(yè)面
page.open(url);
在上述代碼中,我們利用了 PhantomJS 提供的 webPage 模塊,創(chuàng)建了一個(gè)瀏覽器頁(yè)面,并實(shí)現(xiàn)了頁(yè)面所需的數(shù)據(jù)的提取。之后,我們需要在 PHP 中通過(guò) exec 函數(shù)來(lái)調(diào)用 PhantomJS 腳本,再將獲取到的數(shù)據(jù)進(jìn)行處理即可。
除了這個(gè)例子,PhantomJS 調(diào)用 PHP 的應(yīng)用還有很多,比如:通過(guò)登錄某個(gè)網(wǎng)站自動(dòng)獲取需要的數(shù)據(jù)、自動(dòng)化測(cè)試等等。相信大家使用過(guò)程中絕不會(huì)感到無(wú)趣。