1. 程式人生 > >phantomjs2.1 初體驗

phantomjs2.1 初體驗

http dom canvas ima 行為 pen 廣告 自動 str

上次看了一下scrapy1.1的新手指南

決定寫個小爬蟲實驗一下

目標網站是http://www.dm5.com/manhua-huofengliaoyuan
準備爬取漫畫火鳳燎原的已有章節,將圖片保存到本地

開始一切順利,從漫畫目錄頁面開始,拿到了每一話(卷)的地址

然而訪問後發現頁面中的圖片地址都是加過密的,找不到真實地址。
(網頁源代碼中沒有,f12看network大概看了一下,也沒有發現地址,所以應該是加密了)

後來試著打開了幾個漫畫網站,只有騰訊動漫能在頁面中找到圖片的連接。

決定試一試phantomjs

PhantomJS是一個無界面的,可腳本編程的WebKit瀏覽器引擎。它原生支持多種web 標準:DOM 操作,CSS選擇器,JSON,Canvas 以及SVGPhantomJS是一個無界面的,可腳本編程的WebKit瀏覽器引擎。它原生支持多種web 標準:DOM 操作,CSS選擇器,JSON,Canvas 以及SVG。
<!-- more -->

以下使用火鳳燎原第5卷第2頁的地址http://www.dm5.com/m5342-p2/為例子
按著官網指南走一邊。

安裝phantomjs2.1.1

從這裏下載對應好的包
或者自己下載源碼進行編譯(據說自己編譯巨慢)

我下載的是phantomjs-2.1.1-linux-x86_64.tar.bz2
解壓縮,在目錄裏執行

./bin/phantomjs -v
-->2.1.1

話說這樣執行沒問題,也給了+x權限,但是ln -s 到/usr/bin目錄下卻無法執行。。
將phantomjs連接到python環境的bin目錄下。

新手指南

官方新手指南
我是按著官方走,但是實驗自己需要爬取的頁面

Hello,World!

新建一個文檔hello.js
內容:

# 在控制臺打印日誌
console.log(‘Hello, world!‘);
// 退出phantomjs
phantom.exit();

在hello.js目錄下執行

phantomjs hello.js
--> Hello,world!

註意任何時候都不要忘記phantom.exit();
他用來讓phantomjs退出

載入頁面並將整個頁面保存成圖片

//創建一個webpage對象
var page = require(‘webpage‘).create();
// 打開頁面
page.open(‘http://www.dm5.com/m5342-p2/‘, function(status) {
  // 輸出狀態
  console.log("Status: " + status);
  if(status === "success") {
    // 如果狀態為success,將整個page保存為hfly.jpg(也可以是png,pdf, gif)
    page.render(‘hfly.jpg‘);
  }
  phantom.exit();
});

執行代碼後

技術分享
http://oc1suuvql.bkt.clouddn.com/image/3f0da110-75fa-44be-b504-9f0b01a0dc89.jpg

感覺速度很慢,不過這是保存了整個頁面,如果只保存圖片會不會快一點?
官網真貼心,緊跟著就給了一個測速腳本

測試速度loadspeed.js

這個速度是phantomjs加載頁面並且渲染頁面的總耗時。

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();
});

執行,參數為要測試的地址
地址前面要加上http://或者https://

phantomjs loadspeed.js http://www.baidu.com
-->Loading time 5403 msec
phantomjs loadspeed.js http://www.dm5.com/m5342-p2/
-->Loading time 76584 msec

。。。
敢問你是不是在逗我?秒速五厘米很美、、秒速76厘米就是逗逼了。。
為什麽這麽慢?他怎麽就這麽慢?是我環境的問題嘛?
(因為我是用的虛擬機centos7,本地win7 pycharm remote evns,虛擬機的內存小cpu只分配了一個核心,可能渲染的就慢一些?)

早有耳聞phantomjs速度慢,沒想到google誠不欺我。。
不行。。我要在本地win7上也試一下。
本地

phantomjs.exe loadspeed.js http://www.baidu.com
-->Loading time 701msec
phantomjs.exe loadspeed.js http://www.dm5.com/m5342-p2/
-->Loading time 5534 msec

我猜對了。。。
那我真是好尷尬,本地win7 安裝python3 的各種包真是無力
搞個虛擬機專門用來配置python環境。。沒想到phantomjs需要一定的性能。。

我再試試我的vps。。512M,1核,本地虛擬機是1核,768M。

phantomjs.exe loadspeed.js http://www.google.com
-->Loading time 415msec
phantomjs.exe loadspeed.js http://www.nba.com
-->Loading time 2800 msec
phantomjs.exe loadspeed.js http://www.dm5.com/m5342-p2/
-->Loading time 7993 msec

看來不是性能問題,是下載速度。。
我用的虛擬機是本地橋接,沒想到網速會差這麽多

!!又尼瑪反轉,劇情神打臉,啪啪啪啪

技術分享
http://oc1suuvql.bkt.clouddn.com/image/ccf06c6b-c876-4f45-a194-ba04e5eea016.jpg

虛擬機的網速也是呱呱叫的
目前,唯一能解釋的就是vmware不行,效率低(本身就是虛擬機)
但是vps也是虛擬機來著。。到底人家專業做的麽?

小結:使用phantomjs,要麽在本地機器上運行,要麽直接放vps上運行。
用vmware,慢出個翔、、

代碼評估(code evaluation)

不知道怎麽翻譯,明明就是分析代碼然後取出需要的內容

使用evaluate()方法去審核頁面代碼,這個方法是沙盒式的,不會去執行頁面外的js代碼。
(也就是說在外面定義的變量不能在evalute方法中使用)
evalute方法是直接去操作page對象了,把處理後取得的內容返回。

evaluate()方法返回一個對象,也只能返回一個對象,不能包含函數。

// 獲得頁面標題
url = ‘http://www.dm5.com/m5342-p2/‘
// 創建webpage對象
var page = require(‘webpage‘).create();
page.open(url, function(status) {
  if(status === "success"){
    // 從page對象裏,evalute出來title(不知道怎麽翻譯。。)
    var title = page.evaluate(function() {
      return document.title;
    });
    console.log(‘Page title is ‘ + title);
  }else {
    console.log(‘failed‘);
  }
  phantom.exit();
});

執行後輸出頁面標題

通常一個網頁自己也有console輸出,在chrome裏f12選擇console就能看到。
這個輸出在phantomjs裏是不會被顯示出來的
evaluate方法裏的console.log也不會顯示(因為相當於網頁自己的console輸出了。)
如果想要輸出
需要重寫onConsoleMessage方法

url=‘http://www.dm5.com/m5342-p2/‘
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();
});

我尼瑪。
為啥會有一個百度的廣告。
估計是這個網站使用了百度推廣或者統計嗎?
但是chrome裏看控制臺,卻沒有這個百度的輸出
不知道為啥

只要phantomjs腳本運行起來,就可以使用css 選擇器和標準的js DOM 操作。
所以需要了解一下css selector 和 DOM 操作

自動化任務

由於phantomjs可以加載和操作web界面,所以可以用它來做自動化。
詳見page automation tasks

網絡監控

歪了歪了,,我只想拿頁面上的圖片。。
但是官方指南只是介紹大概功能,鑒於這是最後一點內容。也一並記錄下來好了

phantomjs 有網絡通信的檢查功能,很適合用來做網絡行為的分析。
當接受到請求時,可以通過重寫onResourceRequested和onResourceReceived回調函數來實現接收到資源請求和資源接受完畢的監聽。
詳見network monitoring

// 網絡監聽
url=‘http://www.dm5.com/m5342-p2/‘
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);

這樣在webpage載入的時候,會把所有網絡請求的請求內容和響應內容打印到控制臺。

官方例子

裏面有很多樣例代碼,可以直接看,不同的再去翻手冊
Examples

記錄一下拿圖片地址的代碼

果然官方指南只是大略的介紹一下

拿圖片地址的文件get_pic_url.js

// 接受漫畫網頁地址
url = system.args[1];
var page = require(‘webpage‘).create();
page.open(url, function(status) {
  if(status === "success"){
            // 處理頁面
          var pic_url = page.evaluate(function() {
            // DOM操作
            return document.getElementById(‘cp_image‘).getAttribute(‘src‘);
          });
          console.log(pic_url);
  }else{
    console.log(‘failed‘);
  }
  phantom.exit();
});

執行 phantomjs get_pic_url.js http://www.dm5.com/m5342-p2/
輸出圖片地址。

總結

phantomjs是一個無界面的瀏覽器。
所以在代碼最後一定要加入phantom.exit()方法確保其退出。

phantomjs加載頁面以後
用evaluate()方法對渲染後的頁面代碼進行操作,此函數值操作頁面,和我們執行的js不在一個域。

phantomjs可以做自動化測試,網絡監聽等工作。

phantomjs2.1 初體驗