歡迎你們前往騰訊雲技術社區,獲取更多騰訊海量技術實踐乾貨哦~javascript
做者:李大偉html
Phantomjs官網介紹是:不須要瀏覽器的完整web協議棧(Full web stack No browser required),也就是常說的無頭瀏覽器——或者好聽點叫作:無界面的web解析器。java
因爲「無頭」——免去了渲染可視化的網頁界面,她的速度要比通常的瀏覽器快很多,又由於她是完整的web協議棧,因此不只僅提供了JavaScript API,還完整的支持各種web標準:DOM操做、CSS選擇器、JSON、Canvas和SVG,以及文件系統API和操做系統API。此外她還提供不少web事件監控處理接口(event handle),這一點也是Phantomjs區別於selenium等web自動化測試工具的關鍵所在,具體的將在後續安全檢測中詳細說明。react
筆者將Phantomjs的特徵彙總以下表:jquery
The WebPage APIweb
The System APIchrome
The FileSystem API瀏覽器
The WebServer API安全
鑑於以上特色,咱們就會發現Phantomjs特別適合用來寫!爬!蟲!bash
支持JavaScript即可以動態加載資源,或完成一些模擬人類的動做;支持DOM操做即可以結構化頁面;CSS的支持即可以快捷方便的完成頁面文檔的渲染,供咱們保存圖片或處處PDF;支持JSON、Canvas和SVG更是對與數據或多媒體頁面處理的加分項;同時文件系統API的提供,也讓咱們很方便的將處理結果格式化存儲起來。
下載Phantomjs後,直接運行Phantomjs就進入了交互模式,這時咱們能夠把她當作一個JavaScript解釋器使用,運算、js方法、使用window.navigator對象查看「瀏覽器」信息等等,你們若是安裝了Phantomjs能夠隨意輸入一些命令感覺一下。感覺結束後輸入phantom.exit()`退出。
圖:REPL 模式下的 Phantomjs
若是是初學js的同窗,這個模式可能會比chrome的console欄更大一些,方便用來練習js命令。此外,這個這個模式並不經常使用,咱們更多的是將Phantomjs看作一個二進制工具來使用。
這也是Phantomjs最經常使用的一個模式:phantomjs /scripts/somejavascript.js來運行一個JavaScript腳本。腳本中可使用Phantomjs提供的各種API(KM的markdown語法不支持頁內錨點,詳見文章前部分的「Phantomjs提供的API彙總」);
建立一個webpage的實例,而後使用open方法打開騰訊網首頁,若是返回值是成功,則日誌打印出網頁標題,以後退出。
/****************************************************************
* create an instance of the webpage module
* get the page and echo the page's title * file: somejavascript.js * auther : Taerg * date : 12/05/2017 *****************************************************************/ var page = require('webpage').create(); // open the webpage // defined callback: check the status and echo teh status page.open("http://www.qq.com", function(status) { if ( status === "success" ) { console.log("Page load success.The page title is:"); console.log(page.title); } else { console.log("Page load failed."); } phantom.exit(0); }); 複製代碼
固然,咱們也能夠用page.content來獲取頁面的全部內容,使用page.cookies來獲取cookie。
以下,咱們獲取訪問王者榮耀網站時的cookie,並使用鍵值對的方式打印在log裏:
/****************************************************************
* create an instance of the webpage module
* echo the cookies
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require('webpage').create();
console.log(1);
page.open("http://www.qq.com/", function(status) {
if (status === 'success') {
var cookies = page.cookies;
for(var i in cookies) {
console.log(cookies[i].name + '=' + cookies[i].value);
}
}
phantom.exit(0);
});
複製代碼
對應的輸出爲:
圖:phantomjs_getcookie
Phantomjs做爲無頭「瀏覽器「,固然對JavaScript的支持也是極好的。以下,咱們定義了一個簡單的函數,來獲取頁面標題後返回。只須要簡單的調用page.evaluate()來執行這段JavaScript代碼便可。
/****************************************************************
* create an instance of the webpage module
* include system module
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var system = require('system');
var url = system.args[1];
console.log(url);
var page = require('webpage').create();
page.open(url, function(status) {
if ( status === "success" ) {
var title = page.evaluate(function () {
return document.title;
});
console.log(title);
}
})
phantom.exit(0);
複製代碼
若是以爲本身用JavaScript代碼來重複造輪子太麻煩,咱們也能夠在Phantomjs中使用第三方的JavaScript庫。Phantomjs爲咱們提供了2中使用第三方庫的方法:
兩者經常混用,主要的區別在於injectJs是阻塞加載,而includeJs是動態加載。injectJs能夠理解爲代碼執行到這裏時,程序阻塞,加載這個js文件到內存後,程序繼續運行,在操做頁面時不會對這個文件發起請求。而includeJs則是在加載頁面用到此js文件時動態加載文件。
實例代碼以下:
/****************************************************************
* create an instance of the webpage module
* load third part js lib
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require('webpage').create();
// open the webpage
page.open("http://www.qq.com", function(status) {
page.injectJs('jquery321.js');
//different with page.includeJs
if (status === 'success') {
var aoffset = page.evaluate(function() {
return (typeof jQuery === 'function') ? jQuery.fn.jquery : undefined;
});
console.log(aoffset);
}else{
console.log('open error');
}
phantom.exit(0);
});
複製代碼
輸出以下:
咱們先inject了版本號爲3.2.1的本地jQuery文件,以後即可以使用jQuery的方法來查看jQuery版本。固然,這只是驗證jQuery加載成功,在咱們徹底可使用其餘jQuery提供快捷方法來實現咱們的需求。
在咱們處理頁面時,經常會有保存頁面截圖的需求,好比:保存頁面BUG的樣子、關鍵信息的留證等等。這時咱們就可使用Phantomjs的page提供的render方法,她支持將完整的頁面(自動滾屏截圖)、指定區間的頁面保存下來(.png, .pdf, .jpg等格式均支持)。
以下,咱們想獲取天氣網站」個人天氣「詳情,而不去關注網頁其餘各類新聞和廣告,咱們只需指定區間,而後保存截圖便可:
/****************************************************************
* phjs_clip.js
* get the weather pic
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = new WebPage();
page.open('http://www.weather.com.cn', function (status) {
if (status !== 'success') {
output.error = 'Unable to access network';
} else {
page.clipRect = {
top: 200,
left: 750,
width: 300,
height: 500
}
page.render('weather.png');
console.log('Capture saved');
}
phantom.exit();
});
複製代碼
保存的圖片以下所示:
圖:phantom_get_weather
當咱們正常使用瀏覽器訪問https://media.om.qq.com/media/5054676/list時,一切正常,以下圖:
圖:safari_get_omqq
根據這套反爬蟲做者的解釋,客戶端通過JavaScript計算出來一個票據,包含在cookie將在服務端再次驗證,驗證經過則返回數據,驗證不經過則不返回數據。以下圖所示:
圖:anti_spide
下面咱們經過腳原本自動拉去這個頁面數據試試
首先咱們先用最簡答的curl來get這個頁面看看能都拿到這個頁面的數據:
圖: curl_get_omqq
如上圖所示,被反爬蟲系統攔截了。
咱們再用Python試試,使用最通用的「HTTP for humans」的requests.get請求:
圖: request_get_omqq
能夠看到依舊會被反爬蟲機制攔截。
經過人工瀏覽器訪問、抓包分析,咱們能夠看到:
1 . 人工訪問這個網頁一共發起了6條請求 2 . 第1條請求時直接請求目標url,因爲沒有合法票據,返回403。同時在403頁面中包含了2個JavaScript文件
圖: load_js
3 .接下來的2個請求分別爲對403頁面中的JavaScript腳本進行加載
4 .加載運行完畢後,得到了合法票據並添加進cookie中再次發起請求,產生了第4條請求。以下圖:
圖:omqq_signiture
5.第4條請求帶有合法票據,所以沒有被403forbidden掉,而是增長一個客戶id標示後302跳轉到了數據頁面。以下圖:Set-cookie中添加了id簽名。
圖: redirect
6 .此時,cookie中已經包含有了合法的簽名以及客戶id,請求到了JSON數據。獲得了正常的頁面:
圖: safafi_get)omqq
至此,咱們就能夠根據前面的分析使用Phantomjs來逐步模擬人工請求,從而繞過反爬蟲系統。先看代碼:
/****************************************************************
* phjs_antispider.js
* anti-anti-spider script for https://media.om.qq.com/media/5054676/list
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require("webpage").create();
var system = require("system")
url = system.args[1];
headers = {};
page.customHeaders = headers;
page.settings = {
javascriptEnabled: true,
userAgent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36',
};
page.viewportSize = {
width: 1024,
height: 768
};
page.open(url,
function(status) {
page.injectJs('jquery321.js');
if (status !== 'success') {
console.log('Unable to access network');
} else {
page.evaluate(function() {
var allElements = $('*');
for ( var i = 0; i<allElements.length; i++ ) {
if (allElements[i].href) {
javascript_code = allElements[i].href.match("javascript:(.+)");
if (javascript_code){
console.log(javascript_code[0]);
eval(javascript_code[0]);
}
}
}
});
}
window.setTimeout(
function() {
console.log("crawl_content:"+page.content+"content_end")
phantom.exit()
},
1000
);
phantom.exit();
});
複製代碼
在上述代碼中:
運行結果以下:可見,咱們的請求已經繞過了反爬蟲機制。
圖: phantomjs_get_omqq
臥槽,我就是個開發,你跟我說抓包分析啥的我不會啊!!寶寶只想爬點數據而已啊…
那就用三行代碼來實現吧:
/****************************************************************
* crawl the anti-aipder website: om.qq.com
* auther : Taerg
* date : 17/05/2017
*****************************************************************/
var casper = require("casper").create();
casper.start('https://media.om.qq.com/media/5054676/list', function() {
require('utils').dump(JSON.parse(this.getPageContent()));
});
casper.run(function() {
this.exit();
});
複製代碼
結果以下:
圖:casper_get_omqq
這三行代碼不只成功繞過了反爬蟲的限制,並且自帶的JSON方法也將也數據結構化顯示(存儲),對於複雜爬蟲的開發能夠極大的簡化開發複雜度。
這三行代碼中用到的就是—CasperJS。
CasperJS官方自稱是一個開源的導航腳本和測試工具,但實際用起來爽的不行不行的。具體包括:
此外,CasperJS最爲強大的地方在於我在這裏給你們簡單介紹以後,我就不用再說什麼了,CasperJS擁有極其豐富的文檔及實例代碼。這一點對比核心文檔仍是TODO,須要咱們來撰寫各種文檔的Phantomjs來講友好太多了。
###相關閱讀
爬蟲實戰:爬蟲之 web 自動化終極殺手 ( 上) Scrapy 對接 Splash 精通 Python 網絡爬蟲:網絡爬蟲學習路線 此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處
原文連接: https://www.qcloud.com/community/article/636391