PhantomJSでbitFlyer Lightningをスクレイピング

※いなごFlyerをスクレイピングする記事も書きました。
いなごFlyerをPhantomJSでスクレイピング

今週やったこと

  • PhantomJSを試してみた。bitFlyer Lightningをスクレイピング。
  • GitHubで公開中のリポジトリ、「ShadowRecode」を修正
  • 読みかけだった「テスト駆動開発」を読み終えた。
  • 生活習慣改善のためのアプリを導入した。

この中でも特に印象に残っている、PhantomJSについて触れたいなと思います。

PhantomJS

きっかけ

私がPhantomJSを知る切っ掛けになったのはこちらのツイート↓

このツイートをきっかけにPhantomJSに興味を持ったので実際に試してみた。

PhantomJSとは?

その前にそもそもPhantomJSとは何なのか?
調べると次のような説明がでてきた。
「Webkitベースのヘッドレスブラウザ」
ようは画面のないブラウザらしい。
私もまだ理解が足りていないが、ブラウザなのでJavaScriptを動的に生成しているページの情報なんかも取得できるという解釈をした。
JavaScriptを使って操作できるので、フォームを埋めてログインさせたり、ログイン後のページの情報も取ってこれたりする。

今までPHPやPythonでスクレイピングをしたことはあるが、Ajaxでページを読み込んだあとに値を当てはめてたりすると、取得できないことが多々あった。
JavaScriptを解析して通信先のAPIを叩くことで取得するなど涙ぐましい努力が必要だったり、それでもダメなら諦めてきた。
PhantomJSならページを読み込んだ後、Ajaxで取得した情報が適用されるのを待ってからスクレイピングも可能だ。

また、ユーザーマイページのようにログインした状態でアクセスしないとログイン画面にリダイレクトされてしまうページは通常スクレイピングすることができないのだが、PhantomJSならJavaScriptを使ってフォームを入力してログインさせてから、目的のページの情報を取得することも可能である。

スクレイピング以外にもUIの自動テストなんかに使えるらしく、大変便利なツールのようだ。

基礎学習

いきなり目的のものは作れないので、まずはネットのサンプルを参考に機能を試してみた。
参考にさせていただいたのはこちらの記事↓
PhantomJSを使って色々試してみる
PhantomJS でログインが必要なページでも自由自在にスクレイピング

私は普段Macを使っているので、記事にも紹介してある次のコマンドで簡単にインストールができた。

$ brew install phantomjs

あとは手元のPCでひたすら記事のサンプルコードを書いては実行するだけだ。

bitFlyer Lightningをスクレイピング

ある程度PhantomJSの間隔を掴んだところbitFlyer Lightningのスクレイピングに挑戦した。
なぜツイートにあるいなごFlyerではなくbitFlyerのスクレイピングなのか?
それは当時私がいなごFlyerの存在を知らず、bitFlyerの隠語だと早とちりしたためであるorz

自分が間違ったものを作っていると知らず、意気揚々と作成したコードがコチラ↓

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

page.onInitialized = function() {
  page.evaluate(function() {
    document.addEventListener('DOMContentLoaded', function() {
      window.callPhantom('DOMContentLoaded')
    }, false)
  })
}

var funcs = function(funcs) {
  this.funcs = funcs
  this.init()
}

funcs.prototype = {
  init: function() {
    var self = this
    page.onCallback = function(data) {
      if (data === 'DOMContentLoaded') self.next()
    }
  },
  next: function() {
    var func = this.funcs.shift()
    if(func !== undefined) {
      func()
    } else {
      page.onCallback = function(){}
    }
  }
}

function waitFor(testFx, onReady, timeOutMillis) {
  var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 15000,
      start = new Date().getTime(),
      condition = false,
      interval = setInterval(function() {
        if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
          var data;
          condition = (typeof(testFx) === "string" ? eval(testFx) : data = testFx())
          // console.log(data)
        } else {
          if(!condition) {
            console.log("'waitFor()' timeout")
            phantom.exit(1)
          } else {
            typeof(onReady) === "string" ? eval(onReady) : onReady()
            clearInterval(interval)
          }
        }
      }, 1000)
};

new funcs([
  function() {
    console.log('接続')
    page.open('https://lightning.bitflyer.jp/')
  },
  function() {
    console.log('ログイン')
    page.evaluate(function() {
      document.getElementById('LoginId').value = 'メールアドレス'
      document.getElementById('Password').value = 'パスワード'
      document.querySelector('form').submit()
    })
  },
  function() {
    console.log('ログイン完了')
    waitFor(function() {
      return page.evaluate(function() {
        return document.querySelector('.bidsum__label').innerText != "                    &nbsp;                    ";
      })
    }, function() {
      var data = page.evaluate(function () {
        return {
          ask: document.querySelector('.asksum__sum').innerText,
          bid: document.querySelector('.bidsum__label').innerText
        }
      })
      page.render('bitflyer.png')
      console.log('bid -> ' + data.bid + '   ask -> ' + data.ask)
      console.log("exit...")

      phantom.exit()
    })
  }
]).next()

メールアドレスとパスワードは適切な値に変更する必要がある。
処理の流れとしては、

  1. bitFlyer Lightningに接続
  2. メールアドレスとパスワードを埋めてログイン
  3. 遷移先のページで売りと買いの注文総数が表示されるのを待って値を取得

となっている。
3を作成するにあたり、下記の記事を参考にさせていただいた。 PhantomJSで画面表示を待つ

あとは上記のコードにbitflyer.jsのような適当な名前を付けて保存し、ターミナルで実行すると買いと売りの注文量が表示される。

$ phantomjs bitflyer.js

2段階認証が設定されている場合のログインは良い方法が思いつかなかったため、今回は捨てアカウントを作成してログインしている。

まとめ

PhantomJSはスクレイピングの幅を広げてくれる良いツール。
いろいろ悪さできそう。

arrow_upward