騰訊雲上 PhantomJS 用法示例

騰訊雲加社群發表於2017-04-12

騰訊雲技術社群-掘金主頁持續為大家呈現雲端計算技術文章,歡迎大家關注!


作者:崔慶才

前言

大家有沒有發現之前我們寫的爬蟲都有一個共性,就是隻能爬取單純的html程式碼,如果頁面是JS渲染的該怎麼辦呢?如果我們單純去分析一個個後臺的請求,手動去摸索JS渲染的到的一些結果,那簡直沒天理了。所以,我們需要有一些好用的工具來幫助我們像瀏覽器一樣渲染JS處理的頁面。

其中有一個比較常用的工具,那就是

PhantomJS

Full web stack No browser required
PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast andnative support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
PhantomJS是一個無介面的,可指令碼程式設計的WebKit瀏覽器引擎。它原生支援多種web 標準:DOM 操作,CSS選擇器,JSON,Canvas 以及SVG。

好,接下來我們就一起來了解一下這個神奇好用的庫的用法吧。

ps:伺服器是騰訊雲

騰訊雲上 PhantomJS 用法示例

安裝

PhantomJS安裝方法有兩種,一種是下載原始碼之後自己來編譯,另一種是直接下載編譯好的二進位制檔案。然而自己編譯需要的時間太長,而且需要挺多的磁碟空間。官方推薦直接下載二進位制檔案然後安裝。

大家可以依照自己的開發平臺選擇不同的包進行下載

下載地址

當然如果你不嫌麻煩,可以選擇

下載原始碼

然後自己編譯。

目前(2016/3/21)最新發行版本是 v2.1,

安裝完成之後命令列輸入

phantomjs -v複製程式碼

如果正常顯示版本號,那麼證明安裝成功了。如果提示錯誤,那麼請重新安裝。

本文介紹大部分內容來自於官方文件,博主對其進行了整理,學習更多請參考

官方文件

快速開始

第一個程式

第一個程式當然是Hello World,新建一個 js 檔案。命名為 helloworld.js

console.log('Hello, world!');
phantom.exit();複製程式碼

命令列輸入

phantomjs helloworld.js複製程式碼

程式輸出了 Hello,world!程式第二句話終止了 phantom 的執行。

注意:phantom.exit();這句話非常重要,否則程式將永遠不會終止。

頁面載入

可以利用 phantom 來實現頁面的載入,下面的例子實現了頁面的載入並將頁面儲存為一張圖片。

var page = require('webpage').create();
page.open('http://cuiqingcai.com', function (status) {
    console.log("Status: " + status);
    if (status === "success") {
        page.render('example.png');
    }
    phantom.exit();
});複製程式碼

首先建立了一個webpage物件,然後載入本站點主頁,判斷響應狀態,如果成功,那麼儲存截圖為example.png

以上程式碼命名為 pageload.js,命令列

phantomjs pageload.js複製程式碼

發現執行成功,然後目錄下多了一張圖片,example.png

騰訊雲上 PhantomJS 用法示例

因為這個 render 方法,phantom 經常會用到網頁截圖的功能。

測試頁面載入速度

下面這個例子計算了一個頁面的載入速度,同時還用到了命令列傳參的特性。新建檔案儲存為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://cuiqingcai.com複製程式碼

執行結果

Loading http://cuiqingcai.com
Loading time 11678 msec複製程式碼

這個時間包括JS渲染的時間,當然和網速也有關。

程式碼評估

To evaluate JavaScript code in the context of the web page, use evaluate() function. The execution is “sandboxed”, there is no way for the code to access any JavaScript objects and variables outside its own page context. An object can be returned from evaluate(), however it is limited to simple objects and can’t contain functions or closures.

利用 evaluate 方法我們可以獲取網頁的原始碼。這個執行是“沙盒式”的,它不會去執行網頁外的 JavaScript 程式碼。evalute 方法可以返回一個物件,然而返回值僅限於物件,不能包含函式(或閉包)

var url = 'http://www.baidu.com';
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();
});複製程式碼

以上程式碼獲取了百度的網站標題。

Page title is 百度一下,你就知道複製程式碼

任何來自於網頁並且包括來自evaluate()內部程式碼的控制檯資訊,預設不會顯示。

需要重寫這個行為,使用 onConsoleMessage 回撥函式,示例可以改寫成

var url = 'http://www.baidu.com';
var page = require('webpage').create();
page.onConsoleMessage = function (msg) {
    console.log(msg);
};
page.open(url, function (status) {
    page.evaluate(function () {
        console.log(document.title);
    });
    phantom.exit();
});複製程式碼

這樣的話,如果你用瀏覽器開啟百度首頁,開啟除錯工具的console,可以看到控制檯輸出資訊。

重寫了 onConsoleMessage 方法之後,可以發現控制檯輸出的結果和我們需要輸出的標題都列印出來了。

一張網頁,要經歷怎樣的過程,才能抵達使用者面前?
一位新人,要經歷怎樣的成長,才能站在技術之巔?
探尋這裡的祕密;
體驗這裡的挑戰;
成為這裡的主人;
加入百度,加入網頁搜尋,你,可以影響世界。

請將簡歷傳送至 %c ps_recruiter@baidu.com( 郵件標題請以“姓名-應聘XX職位-來自console”命名) color:red
職位介紹:http://dwz.cn/hr2013
百度一下,你就知道複製程式碼

啊,我沒有在為百度打廣告!

螢幕捕獲

Since PhantomJS is using WebKit, a real layout and rendering engine, it can capture a web page as a screenshot. Because PhantomJS can render anything on the web page, it can be used to convert contents not only in HTML and CSS, but also SVG and Canvas.

因為 PhantomJS 使用了 WebKit核心,是一個真正的佈局和渲染引擎,它可以像螢幕截圖一樣捕獲一個web介面。因為它可以渲染網頁中的人和元素,所以它不僅用到HTML,CSS的內容轉化,還用在SVG,Canvas。可見其功能是相當強大的。

下面的例子就捕獲了github網頁的截圖。上文有類似內容,不再演示。

var page = require('webpage').create();
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});複製程式碼

除了 png 格式的轉換,PhantomJS還支援 jpg,gif,pdf等格式。

測試樣例

其中最重要的方法便是 viewportSize 和 clipRect 屬性。

viewportSize 是視區的大小,你可以理解為你開啟了一個瀏覽器,然後把瀏覽器視窗拖到了多大。

clipRect 是裁切矩形的大小,需要四個引數,前兩個是基準點,後兩個引數是寬高。

通過下面的小例子感受一下。

var page = require('webpage').create();
//viewportSize being the actual size of the headless browser
page.viewportSize = { width: 1024, height: 768 };
//the clipRect is the portion of the page you are taking a screenshot of
page.clipRect = { top: 0, left: 0, width: 1024, height: 768 };
//the rest of the code is the same as the previous example
page.open('http://cuiqingcai.com/', function() {
  page.render('germy.png');
  phantom.exit();
});複製程式碼

執行結果

騰訊雲上 PhantomJS 用法示例

就相當於把瀏覽器視窗拖到了 1024×768 大小,然後從左上角裁切出了 1024×768 的頁面。

網路監聽

Because PhantomJS permits the inspection of network traffic, it is suitable to build various analysis on the network behavior and performance.

因為 PhantomJS 有網路通訊的檢查功能,它也很適合用來做網路行為的分析。

When a page requests a resource from a remote server, both the request and the response can be tracked via onResourceRequested and onResourceReceived callback.

當接受到請求時,可以通過改寫onResourceRequested和onResourceReceived回撥函式來實現接收到資源請求和資源接受完畢的監聽。例如

var url = 'http://www.cuiqingcai.com';
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);複製程式碼

執行結果會列印出所有資源的請求和接收狀態,以JSON格式輸出。

頁面自動化處理

Because PhantomJS can load and manipulate a web page, it is perfect to carry out various page automations.

因為 PhantomJS 可以載入和操作一個web頁面,所以用來自動化處理也是非常適合的。

DOM操作

Since the script is executed as if it is running on a web browser, standard DOM scripting and CSS selectors work just fine.

指令碼都是像在瀏覽器中執行的,所以標準的 JavaScript 的 DOM 操作和 CSS 選擇器也是生效的。

例如下面的例子就修改了 User-Agent,然後還返回了頁面中某元素的內容。

var page = require('webpage').create();
console.log('The default user agent is ' + page.settings.userAgent);
page.settings.userAgent = 'SpecialAgent';
page.open('http://www.httpuseragent.org', function(status) {
  if (status !== 'success') {
    console.log('Unable to access network');
  } else {
    var ua = page.evaluate(function() {
      return document.getElementById('myagent').textContent;
    });
    console.log(ua);
  }
  phantom.exit();
});複製程式碼

執行結果

The default user agent is Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.0 Safari/538.1

Your Http User Agent string is: SpecialAgent

首先列印出了預設的 User-Agent,然後通過修改它,請求驗證 User-Agent 的一個站點,通過選擇器得到了修改後的 User-Agent。

使用附加庫

在1.6版本之後允許新增外部的JS庫,比如下面的例子新增了jQuery,然後執行了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()
  });
});複製程式碼

引用了 jQuery 之後,我們便可以在下面寫一些 jQuery 程式碼了。

Webpage物件

在前面我們介紹了 webpage 物件的幾個方法和屬性,其實它本身還有其它很多的屬性。具體的內容可以參考

Webpage

Webpage用例

裡面介紹了 webpage的所有屬性,方法,回撥。

命令列

Command-line Options

PhantomJS提供的命令列選項有:

  • –help or -h lists all possible command-line options. Halts immediately, will not run a script passed as argument. [幫助列表]

  • –version or -v prints out the version of PhantomJS. Halts immediately, will not run a script passed as argument. [檢視版本]

  • –cookies-file=/path/to/cookies.txt specifies the file name to store the persistent Cookies. [指定存放cookies的路徑]

  • –disk-cache=[true|false] enables disk cache (at desktop services cache storage location, default is false). Also accepted: [yes|no]. [硬碟快取開關,預設為關]

  • –ignore-ssl-errors=[true|false] ignores SSL errors, such as expired or self-signed certificate errors (default is false). Also accepted: [yes|no]. [忽略ssl錯誤,預設不忽略]

  • –load-images=[true|false] load all inlined images (default is true). Also accepted: [yes|no]. [載入圖片,預設為載入]

  • –local-storage-path=/some/path path to save LocalStorage content and WebSQL content. [本地儲存路徑,如本地檔案和SQL檔案等]

  • –local-storage-quota=number maximum size to allow for data. [本地檔案最大大小]

  • –local-to-remote-url-access=[true|false] allows local content to access remote URL (default is false). Also accepted: [yes|no]. [是否允許遠端載入檔案,預設不允許]

  • –max-disk-cache-size=size limits the size of disk cache (in KB). [最大快取空間]

  • –output-encoding=encoding sets the encoding used for terminal output (default is utf8). [預設輸出編碼,預設utf8]

  • –remote-debugger-port starts the script in a debug harness and listens on the specified port [遠端除錯埠]

  • –remote-debugger-autorun runs the script in the debugger immediately: ‘yes’ or ‘no’ (default) [在除錯環境下是否立即執行指令碼,預設否]

  • –proxy=address:port specifies the proxy server to use (e.g. –proxy=192.168.1.42:8080). [代理]

  • –proxy-type=[http|socks5|none] specifies the type of the proxy server (default is http). [代理型別,預設http]

  • –proxy-auth specifies the authentication information for the proxy, e.g. –proxy-auth=username:password). [代理認證]

  • –script-encoding=encoding sets the encoding used for the starting script (default is utf8). [指令碼編碼,預設utf8]

  • –ssl-protocol=[sslv3|sslv2|tlsv1|any’] sets the SSL protocol for secure connections (default is SSLv3). [SSL協議,預設SSLv3]

  • –ssl-certificates-path= Sets the location for custom CA certificates (if none set, uses system default). [SSL證照路徑,預設系統預設路徑]

  • –web-security=[true|false] enables web security and forbids cross-domain XHR (default is true). Also accepted: [yes|no]. [是否開啟安全保護和禁止異站Ajax,預設開啟保護]

  • –webdriver starts in ‘Remote WebDriver mode’ (embedded GhostDriver): ‘[[:]]’ (default ‘127.0.0.1:8910’) [以遠端WebDriver模式啟動]

  • –webdriver-selenium-grid-hub URL to the Selenium Grid HUB: ‘URLTOHUB’ (default ‘none’) (NOTE: works only together with ‘–webdriver’) [Selenium介面]

  • –config=/path/to/config.json can utilize a JavaScript Object Notation (JSON) configuration file instead of passing in multiple command-line optionss [所有的命令列配置從config.json中讀取]

注:JSON檔案配置格式

{
  /* Same as: --ignore-ssl-errors=true */
  "ignoreSslErrors": true,

  /* Same as: --max-disk-cache-size=1000 */
  "maxDiskCacheSize": 1000,

  /* Same as: --output-encoding=utf8 */
  "outputEncoding": "utf8"

  /* etc. */
}

There are some keys that do not translate directly:

 * --disk-cache => diskCacheEnabled
 * --load-images => autoLoadImages
 * --local-storage-path => offlineStoragePath
 * --local-storage-quota => offlineStorageDefaultQuota
 * --local-to-remote-url-access => localToRemoteUrlAccessEnabled
 * --web-security => webSecurityEnabled複製程式碼

以上是命令列的基本配置

例項

在此提供官方文件例項,多對照例項練習,使用起來會更得心應手。

官方例項

結語

以上是博主對 PhantomJS 官方文件的基本總結和翻譯,如有差錯,希望大家可以指正。另外可能有的小夥伴覺得這個工具和 Python 有什麼關係?不要急,後面會有 Python 和 PhantomJS 的綜合使用的。


相關閱讀

騰訊雲上Selenium用法示例
騰訊雲主機Python3環境安裝PySpider爬蟲框架過程
Python操作Redis - 雲爬蟲初探


此文已由作者授權騰訊雲技術社群釋出,轉載請註明文章出處;獲取更多雲端計算技術乾貨,可請前往騰訊雲技術社群

相關文章