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

備考欄に感想を書くタイプのエンジニア

それで出世が遅れ(ry

最近学んだこと: CasperJS を利用して Amazon での買物を自動化する

PhantomJS CasperJS EC2

ここ1週間ほど、ウェブサイトのテスト目的で CasperJS を利用していて、せっかくなので公開できるレベルのコードもなにか書いておこうと思ったのでした。とは言え、特定のウェブサイトに対するテスト スクリプトなんて一般化して公開できないので、なぜか CasperJS で Amazon で買い物する動作をコードにしました。

※後述のコードは 2016 年 6 月時点での Amazon.co.jp のウェブサイトのナビゲーション要素を利用している都合上、ウェブサイトの構成が変わったり刷新されたりすると使えなくなります。

したこと

PhantomJS と CasperJS をインストールする

実行環境は以下の通りですが、wget する場合に Bitbucket を利用する例がネットに散見されるものの、どうも現在何らかの理由で使えないようなので、こちらを使うと良さそうです。CasperJS は公式にあるように $ git clone git://github.com/casperjs/casperjs.git しました。

環境
  • OS: Amazon Linux AMI release 2016.3
  • PhantomJS: 2.1.1
  • CasperJS: 1.1.1

コードを書く

書きました。

変わったところと言えば、注文する商品がアルコールを含む商品扱いされているため、[注文の確定] をする際に

[お客様の年齢確認をさせていただいております。: 20歳未満のお客様の酒類の購入や飲酒は日本の法律により固く禁じられています。お客様が20歳以上の場合は、このチェックボックスをクリックしてから注文を確定してください。]

というチェックボックスにチェックを入れないと [注文を確定する] ボタンをクリックできないところでしょうか。要素名が name="wineNotice" っていうのが面白いですね。

その仕組みを覗いてみると、上記のチェックボックスtrue または false に応じて [注文を確定する] ボタンの span class="a-button a-button-primary continue-button place-order-button-link a-button-span12" style="display: none;"span class="continue-button-blocker a-button a-button-primary a-button-disabled a-button-span12" style="display: inline-block;" の部分が入れ替わって、ボタンが有効化されたり無効化されたりしている都合上、waitForSelector() でクリックできるようになるまで待ってあげる処理が必要でした。display: none;/inline-block; の部分で判定する方法もありかなとは思います。

ちなみに、この処理というか注文フローは全世界共通かというとおそらく違っていて、例えばアメリカだと州によって法律が違うことから、アルコールを含む商品を注文する場合、注文の初期の段階で州を選択しないとカートにも入れられないという状態でした。つまり、このコードの汎用性は非常に乏しいです(かなしみ)。

ところで、コードとは全然関係ない話ですがこのスクリプトで注文しているノンアルコール ビール「龍馬 1865」は、麦芽とホップだけで作られていてノンアルコール ビールなのに結構ビール味であり、しかも他の大手が作っているノンアルコール ビールのように甘味料が入っていない事もあって、ある種のもったりした後味もないのでおすすめです。サントリーのオールフリーなんかは最近のリニューアル後だいぶおいしくなった印象ですが、この龍馬 1865 と比べるとまだまだですし、すべて個人の感想です。

次にしたいこと

  • サーバーレス

    上述の通り、現状では CasperJS の実行環境を EC2 上に構成しているのですが、たったこれだけのために t2.micro とはいえ EC2 インスタンスを起動しているということと、せっかくなのでスケジュールも組み込みたい、ということで Amazon Lambda に組み込めないかなと考えています。

  • Readable Code

    画面遷移数で言うとたったの4ページほどのことなのですが、なぜか Amazon のログイン フォームが Fill() もしくは FillSelector() で対応できなかったので SendKeys()Click() で押し切ったところとか、もう少しブラッシュアップできるのではないかと思っています。

  • 処理の追加

    現状では、予期しないポップアップ(Amazon Prime を使ってみませんか、的なもの)が発生するとそれだけで何も言わずに処理が終わってしまうとか、数量が変更できないとか住所が既定値とか配送日が選択できないとか、いろいろ実装されていると便利な処理がありますので、追加できるといいなと思っています。

  • クレデンシャル情報の暗号化/外部参照

    ベタ書きになっているので取り扱い注意です。ただし、Lambda に載せるとなるとこの辺りどうなるのかな、という感じです(わかりません)。

Appendix: Resurrectio (ver. 0.5) の使用感

Resurrectio は、Chrome Extension の一つで、ブラウザ上で実行した動作を CasperJS のコードに変換してくれるという、夢の様なツールです。ということで試してみたのですが、結論から言うとあまりスクラッチから書く手間を削減できるかというとそんなことはないかな、という印象でした。例えば上述のスクリプトと同じことを Resurrectio でコード化するとこのようになります(最後の注文のクリックは省略)。

テスト利用を想定したコードになっていることはさておき、メールアドレスの入力ステップが認識されていなかったり、クリックしている場所を XPath で表現していたり(気持ちはわかりますし XPath を使うのが悪いわけではないですが)、ナビゲーション要素内のテキストを利用したりしている感じがコンボになって、あまり好きではありませんでした。