Protractor + WebDriver で楽天銀行と Gmail にログインして入出金明細を保存

motemen.hatenablog.com

上記のリポジトリに Pull Request を出させてもらった。それがこちら。

github.com

  1. (Gmail等に) IMAP でログインしてメールを監視
  2. 楽天銀行にログインしてワンタイムパスワードのメールを送信
  3. ワンタイムパスワードが書かれたメールが来るまで browser.wait() + protractor.promise.defer() *1 で待つ
  4. ワンタイムパスワードでログインして入出金明細を TSV ファイルとして保存 *2

みたいなことしてます。

正直 Protractor のデバッグが一番大変だった。 変な場所で expect() してて全然関係ないテストでコケたりしてた。 デバッグは正直勘で進めてしまったのでよくない。 ちゃんと詳細なログとか取れる方法があるかもっと調べればよかった。

Windows 対応

ついでに既存の npm run-scripts の Windows 対応もした。

github.com

本文終わり。以下は調べたことです。

実装中に調べたこと

参考にしたページ

iconv を Windows でビルドするための環境構築

この2つのサイトがとっかかりとしてはとても助かったんだけど、一つまずい箇所がある。 それは {stream}.on('data', ...) に来たバッファから文字列を検索してるけど、dataの時に渡されるデータは細切れなので、 iconv の変換時に不正なバイトとしてエラーになる可能性がある (なった)。 あと潜在的に検索文字列の途中で切れてたら検索に引っかからない。 なのでこのようにした。

      stream.on("data", function(chunk) {
        body += chunk;
      });
      stream.on("end", function() {
        body = converter.convert(body).toString();
        // FIXME: body にはヘッダ部も含まれているため RFC822 に則ってちゃんとパースする?
        if (/ワンタイムキー[  ]*[::][  ]*([a-zA-Z0-9]+)/.test(body)) {
          var otKey = RegExp.$1;
          console.log('ワンタイムキーを本文から取得成功:' + otKey);
          deferred.fulfill(otKey);
        } else {
          console.log('ワンタイムキーを本文から取得失敗');
          deferred.reject();
        }
      });

以下は init.cmd の Node 関連の内容。

rem # Node
set PATH=C:\Program Files\nodejs;%USERPROFILE%\AppData\Roaming\npm;%PATH%

rem # ================ Prerequisites for Node ================
rem # https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md

rem # Visual Studio
rem # set PATH=C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;%PATH%
set PATH=C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;%USERPROFILE%\.dnx\bin;C:\Program Files\Microsoft DNX\Dnvm\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;%PATH%

rem # Python 2.7
set PATH=C:\Python27;C:\Python27\Scripts;%PATH%

rem # ================ Prerequisites for Node ================

browser.wait()

If your page does manual bootstrap Protractor will not be able to load your page using browser.get. Instead, use the base webdriver instance - browser.driver.get. This means that Protractor does not know when your page is fully loaded, and you may need to add a wait statement to make sure your tests avoid race conditions.

(2段階認証を使っている場合) アプリパスワードを生成

2段階認証を使っている場合はパスワードをそのまま入力したのではログインできない。 アプリパスワードというアプリ固有のパスワードを発行する必要がある。

node.js - Authentication issue with node imap and node mail lister - Stack Overflow

https://support.google.com/accounts/answer/6010255

この設定は、2 段階認証プロセスが有効になっているアカウントでは利用できません。こうしたアカウントで安全性の低いアプリにアクセスするには、アプリケーション固有のパスワードが必要です。 ヘルプ

https://www.google.com/settings/security/lesssecureapps

発行されたパスワードをそのままアカウントのパスワードとして渡せば認証される。

*1:最初 new Promise() 使ってたけど Protractor で用意されてるこっち使った方が良さそうだったのでこっち使った

*2:ここらへんは元のサンプルコードに則らせてもらったというかコピペさせてもらった