UZABASE Tech Blog

株式会社ユーザベースの技術チームブログです。 主に週次の持ち回りLTやセミナー・イベント情報について書きます。

PhantomJSを使ってみる

Techチームの遠藤です。

コンテンツのグローバル展開に向けて、いくつかの地点での画面表示の速度測定のためにphantomjsを使用し計測しました。
全部ではないですが初めの部分だけ記述します。

PhantomJSはまぁ仮想ブラウザを立ち上げてHPを操作していくものですね。
自動テストなどに使えるものです。

PhantomJS

http://phantomjs.org/

DownloadでそれぞれのOSにあったものをDLしてください

私はwindowsでやってるのでwindowsのみ記述します。 といっても大したことしてません。

windowsの場合はDLしてきたzipファイルを解凍し、任意の場所に配置してから環境変数にそのフォルダを指定すると使えるようになります。

さっそく使ってみます。

jsファイルを書いて、コマンドプロンプトで phantomjs XXX.js

phantomjsコマンドと実行するファイルを指定するだけでできます。

まず手始めにgoogleへアクセスしてみます。

var page = require('webpage').create();
page.open('http://www.google.co.jp/', function () {
        page.render('sample.png');
        phantom.exit();
});

新しく作ったJSファイルに上記を記述して実行。

アクセスできました。 sample.pngというピクチャが保存されています。

↓こんな感じ

f:id:uzabase:20141217181612p:plain

実際に使うにはどんどんページ遷移していきたいので、、、 下記ページを参考に遷移する先をtask化していきます。

https://github.com/ogr09/phantomjs_doc_ja/blob/master/Quick-Start.md

http://tips.hecomi.com/entry/20121229/1356785834

var page = require('webpage').create();

function next(){
  if (tasklist.length == 0) {
    phantom.exit();
  }
  var task = tasklist.shift();

  page.address = task.path;
  page.resources = [];

  page.open(page.address, function(status) {
    if (status !== 'success') {
      console.log('FAIL to load the address');
      phantom.exit(1);
    } else {
      var imagename = 'sample2_' + ('0' + task.id).slice(-2);
      page.render(imagename + '.png');

      next();
    }
  });
}

var tasklist = [
{
  id:1,
  path:'http://www.yahoo.co.jp/'
},{
  id:2,
  path:'http://www.google.co.jp/'
}];

next();

こんな感じに...

実行してみるとちゃんとアクセスされているようです。
sample2_01.png、sample2_02.pngと画像が保存されているので順にアクセスされてる模様です。

さて、意味もなくやってるわけじゃなくて仕事で使うので自社サイトのアクセスをするわけですが。。。
自社サイトでは認証があるのでそれを実装します。

var page = require('webpage').create();

function next(){
  if (tasklist.length == 0) {
    phantom.exit();
  }
  var task = tasklist.shift();

  page.address = task.path;
  page.resources = [];

  page.open(page.address, function(status) {
    if (status !== 'success') {
      console.log('FAIL to load the address');
      phantom.exit(1);
    } else {
      var imagename = 'sample3_' + ('0' + task.id).slice(-2);
      page.render(imagename + '.png');
      if(task.operation == null){
        next();
      } else {
        task.operation(page);
      }
    }
  });
}

var tasklist = [
{
  id:1,
  path:'http://www.ub-speeda.com/',
  operation:
    function(page){
      page.evaluate(function() {
        //ここは各サイトで実装が異なります
        document.forms[0].username.value = 'dummy_username';
        document.forms[0].password.value = 'dummy_password';
        document.forms[0].submit();
      });

      //弊社サイトではログイン数管理をしており、それを超過した場合、古いログインを追い出すなどがあるため確認メッセージを出し、再度ログインボタンを押してもらう仕様のため、その対応です
      setTimeout(function() {
        if (page.url.indexOf('top/welcome') > 0) {
          page.evaluate(function() {
            document.forms[0].submit();
          });
          setTimeout(function() {
            next();
          }, 3000);
        } else {
          next();
        }
     }, 3000);
    }
},{
  id:2,
  path:'http://www.ub-speeda.com/company/companyinformation/cid/JPN3O1U73D3VNGWO'
}];

next();

operationという変数を作ってそこにログイン処理を放り込んでみました。 operationが実装されていれば実行する感じですね。 これを応用すればHP内の操作を追加していけるかと思います。 こちらは実際動作するのですがID/Pass等が必要なため試していただける方は少ないかと思います。(ゴメンナサイ

次にファイルのアクセスに関しての情報をファイルに記述します。 ここではページのロード時間しか記述しませんが、ちょこっと検索すればより詳細な情報を取得できるサンプルコードがあるところがあるので詳細はそちらを参考にしてください。

まず、ファイルに書きだす方法ですが公式を参考に。。。

http://phantomjs.org/api/fs/method/write.html

var fs = require('fs'); fs.write(ファイル名, 内容, 'w');

で書き出せます。

組み込んでみましょう。

var page = require('webpage').create();
var fs   = require('fs');

page.onLoadStarted = function() {
  page.startTime = new Date();
};

function next(){
  if (tasklist.length == 0) {
    phantom.exit();
  }
  var task = tasklist.shift();

  page.address = task.path;
  page.resources = [];

  page.open(page.address, function(status) {
    if (status !== 'success') {
      console.log('FAIL to load the address');
      phantom.exit(1);
    } else {
      page.endTime = new Date();

      var logname = 'sample4_' + ('0' + task.id).slice(-2);
      store(logname, page.endTime, page.startTime);

      if(task.operation == null){
        next();
      } else {
        task.operation(page);
      }
    }
  });
}

function store(logname, endTime, startTime){
  page.render(logname + '.png');
  fs.write(logname + '.log', endTime - startTime , 'w');
}

var tasklist = [
{
  id:1,
  path:'http://www.ub-speeda.com/',
  operation:
    function(page){
      page.evaluate(function() {
        document.forms[0].username.value = 'dummy_username';
        document.forms[0].password.value = 'dummy_password';
        document.forms[0].submit();
      });

      setTimeout(function() {
        if (page.url.indexOf('top/welcome') > 0) {
          page.evaluate(function() {
            document.forms[0].submit();
          });
          setTimeout(function() {
            next();
          }, 3000);
        } else {
          next();
        }
     }, 3000);
    }
},{
  id:2,
  path:'http://www.ub-speeda.com/company/companyinformation/cid/JPN3O1U73D3VNGWO'
}];

next();

さて、これで
sample4_01.log
sample4_02.log
というファイルが出来ました。

中身は「endTime - startTime 」という内容が示すとおり殺伐とした数字だけです。

sample4_01.logの中身

219

sample4_02.logの中身

2448

これでページを開く時間がわかるようになりました。
実際にはこれをより詳細にHAR形式で出力するなどして、使えるものに仕上げていってます。
他にも、ダウンロードやajaxでの表示待ちなどを組み込みながら作ったりします。

こんな感じで日々仕事してます。。。