読者です 読者をやめる 読者になる 読者になる

clock-up-blog

go-mi-tech

PhantomJS で Amazon の注文履歴を漁る

JavaScript PhantomJS

なんとなくコマンドラインからやってみたかったンだ

自分の注文履歴を手軽に grep したかっただけなンだ。。。

PhantomJS とは

WebKit が積まれている JavaScript エンジン。
要するにブラウジングをコンソール内 (ヘッドレス) でエミュレートできる。

今回は使ってないけど、WebKit が積まれているので、画面キャプチャとかもできる。
クローラー作りが捗りますな。


とりあえずできあがったもの


             /)
           ///)
          /,.=゙''"/
   /     i f ,.r='"-‐'つ____   こまけぇこたぁいいんだよ!!
  /      /   _,.-‐'~/⌒  ⌒\
    /   ,i   ,二ニ⊃( ●). (●)\
   /    ノ    il゙フ::::::⌒(__人__)⌒::::: \
      ,イ「ト、  ,!,!|     |r┬-|     |
     / iトヾヽ_/ィ"\      `ー'´     /

https://github.com/kobake/amazon-shop-tool

※node.jsが必要。

$ git clone git@github.com:kobake/amazon-shop-tool.git
$ cd amazon-shop-tool
$ npm install
$ chmod +x amazon-order-history
$ ./amazon-order-history
Email: (Input your email for amazon.co.jp)
Password: (Input your password for amazon.co.jp)

取得できるもの

こういうのがずらずらと取得できる。

222-2222222-2222222,20101218日,¥2100,注文が確定しました,YOURNAME,暗号解読〈上〉
111-1111111-1111111,20101030日,¥4195,注文が確定しました,YOURNAME,人月の神話

複数商品を一度に注文したときの履歴が1行にまとまってしまうのがアレ。
今のところは困ってないけど後々分割したい。

プログラム解説(シェルスクリプト部分)

サインイン情報受け取り部

PhantomJS でも標準入力受け取りはできるっぽいけど、サンプルが少ないのでちょっとアレ。
シェルスクリプトで読ませるほうが参考にできるサンプル多いのでそっち採用。
積まれている量の多いナレッジを使うのがおそらくジャスティス。

# Email
echo -n "Email: "
read mail

# Password
read -sp "Password: " pass
tty -s && echo

このへんを参考にしました。
ShellScript - シェルスクリプトでパスワード入力プロンプト - Qiita

PhantomJS 起動

パスの指定とか我流すぎる気がする。フツーの方法が知りたい。

dir=$(cd $(dirname $0);pwd)
phantomjs="$dir/node_modules/phantomjs/bin/phantomjs"
"$phantomjs" "$dir/js/index.js" "$mail" "$pass"

プログラム解説(js部分)

サインイン情報受け取り

args[0] にはスクリプト名が入る。それ以降がパラメータ。

var mail = args[1];
var pass = args[2];

エンジン準備

webpage を create して、いろいろ下ごしらえをします。

var page = require('webpage').create();
// ↓これをやっておくと、
//   ページ内スクリプトからのログが PhantomJS 上の標準出力に表示される。
page.onConsoleMessage = function (msg) {
    console.log(msg);
};

サインイン

最初はサインインしていない状態なので、どのページ開いてもサインインフォームが出る。

で、そのフォーム内では

  • #ap_email のところにメールアドレス
  • #ap_password のところにパスワード

を入れて、
#signInSubmit-input のボタンをクリックすればサインイン処理となる。


page.evaluate でページ内スクリプト実行をエミュレートできる。

var url = 'https://www.amazon.co.jp/gp/css/order-history';
page.open(url,
    function () {
        …
        page.evaluate(function(mail, pass){
            jQuery('#ap_email').val(mail);
            jQuery('#ap_password').val(pass);
            jQuery('#signInSubmit-input').click();
        }, mail, pass);
    }
);

そのまんまのコード。

ページ内の注文履歴をログ出力

まずは実際のブラウザ内でページ内の履歴を出力するスクリプトを実験しながら仕上げると良い。

f:id:kobake:20140907062921p:plain


で、page.evaluate の中身に、上記で仕上げたスクリプトをそのまま貼り付ければ良い。

page.evaluate(function(){
  // この部分のスクリプトは
  // 実際にブラウザで確認したものを貼り付けると良い
  jQuery('.action-box').each(function(){
    var text = '';
    var order = jQuery(this);
    text = order.find('.order-level .info-data a').text().trim(); // 注文番号
    text += "," + order.find('.order-level h2').text().trim(); // 日付
    text += "," + order.find('.order-level .price').text().trim().replace(/[ ,]/g, ''); // 価格
    text += "," + order.find('.order-level .top-text').text().trim(); // 状態
    text += "," + order.find('.order-level .info-data.recipient').text().trim(); // 受取人
    order.find('.ship-listing .shipment > li').each(function(){
        var item = jQuery(this);
        text += "," + item.find('.item-title').text().trim(); // タイトル
    });
    console.log(text);
  });
});

ページめくり

「次へ」という見た目のリンクを探してクリック。

…といきたいところだが、a タグを jQuery で click しても反応無いので、
ここは直接 location.href を書き換える形で。

page.evaluate(function(){
    // 次ページ
    var next = jQuery('div.pagination-box a:contains("次へ")');
    if(next.size() == 1){
        location.href = next.attr('href');
    }
});

その他:逐次処理について

おそらく jQuery.Deferred あたりを使うのがスマートなのかもしれない。

が、個人的にはいろいろいじってみた感触としては、

あたりが学習コスト対効果が良かった。


というかもうちょっと直接的に言うと、汎用的な用途を狙うフレームワークの学習コストがそこそこある割に、それほど効果を感じなかったので、なんか自前でゴリゴリやるほうがマシという感じでした。

しかしチーム開発が必要なときには何かしらフレームワークを選定する必要があるであるのであろう。。。ふーむ。

おしまい

いろんな都合で JavaScript 触らざるを得ないことが最近多いけど、こいつとはいまだに仲良くなりきれていませぬ。

});