HTTPS化編で「常駐したのはトンネルだけ。アプリ本体の自動起動は別問題」と書いた。その本体側、いちばんの難所が 証券アプリへの自動ログインだ。
今回はこれを、まず検証用の Windows VM で実装・検証した。本番のさくらVPSへ載せて常駐させるところは、長くなるので**続編(VPS版)**に分ける。
検証環境について
| 今回(検証) | 本番(続編) | |
|---|---|---|
| ハード | Mac (Apple Silicon) + Parallels の Windows VM | さくらの VPS for Windows Server |
| 目的 | 仕組みを作って動かす | 常駐運用(毎朝自動・無人) |
この「検証環境が Apple Silicon + Retina」という点が、後述するハマりの主な発生源になる(本番VPSでは起きないものもある)。が、踏んでおいたおかげで仕組みは頑健になった。
なぜ自動ログインが必要か
自作の自動売買システム Logical225 は、発注先に au カブコム証券の kabuステーションAPI を使う。これは Windows 上のローカルアプリが提供するAPIで、アプリにログインしている間だけ応答する。
やっかいなのは、このアプリが 毎朝6時すぎに強制ログアウトされること。再ログインには:
- 口座番号・パスワード
- 2要素認証(メールに届く6桁コード)
が必要。無人で売買を回すには、毎朝この再ログインを自動でこなす仕組みが要る。APIにログイン機能は無いので、GUIを自動操作するしかない。
方針
- pyautogui で画面要素を画像マッチしてクリック/入力
- 2FAの6桁は メールを IMAP で読んで抽出し自動入力
- (本番では)毎朝6:30に タスクスケジューラで実行
毎朝6:30 起動
└─ kabu_auto_login.py
1. kabuステーション再起動
2. 口座番号・パスワード入力 → ログイン(2FAメール送信)
3. メールから6桁を取得 → 入力
4. パスキー案内をスキップ → ログイン完了 → API再開
シンプルに見える。が、地雷原だった。特に学びの多かったものを抜粋する。
ハマり①: ウィンドウが「0.4倍」で描画される
テンプレート画像は等倍で撮ったのに、スクリプトから起動するとスクショ上で約0.4倍に縮小描画され、まったく一致しない。しかも実行ごとに倍率が揺れる。
犯人は検証環境(Apple Silicon Mac + Parallels の Retina ミラー)のDPI仮想化。DPIに無頓着なアプリを、DPI-awareな自プロセスから起動すると、スクショ空間と描画スケールがズレる。
対処は合わせ技:
- プロセスを per-monitor DPI aware (v2) にする
- 起動はシェル経由にしてDPIコンテキストを継承させない
- それでもダメなら起動後にウィンドウを数pxリサイズして等倍再描画を強制
# 起動直後、+2px → 元に戻す。これだけで等倍に再描画される
MoveWindow(hwnd, x, y, w + 2, h + 2, True); time.sleep(0.6)
MoveWindow(hwnd, x, y, w, h, True)
これは検証環境(Retina)固有の罠で、本番VPS(通常DPI)では起きない見込み。だが踏んだおかげで、倍率が揺れても耐えるマルチスケール対応まで入り、仕組みが頑健になった。
ハマり②: 状態で見た目が変わるUIは画像マッチに向かない
入力欄は 通常/フォーカス(オレンジ枠)/エラー(赤枠) で見た目が激変する。画像マッチが不安定になる。
対処は 見た目の変わらないボタン(「次へ」等)を基準にして、その上に固定オフセットで欄をクリックする方式。さらに、入力するとエラー表示の増減でレイアウトが上下してボタン座標がズレるので、入力後にボタンを再検出してからクリックする。
ハマり③: 「成功」の誤検知
極めつけ。ログには「ログイン成功」と出るのに、実画面はパスキー案内で止まっていた。画像マッチがログイン後画面のテンプレを別の場所に**誤マッチ(偽陽性)**していた。
対処は、成功判定を画像ではなくウィンドウタイトルで行うこと。ログイン中の窓は「ログイン」、成功後は「kabuステーション …」。確定的な信号なら誤検知しない。
def logged_in_by_title():
return any("kabuステーション" in w.title for w in get_all_windows() if w.title)
他にも「直近ログイン時は2FAが省略されてパスキー画面に飛ぶ」など分岐が必要な罠があり、2FA画面/パスキー案内/ログイン完了のどれが来ても対応するよう作り込んだ。
検証環境では動いた
最終的に、検証VM上で ログイン → 2FA入力 → ウィンドウタイトルで成功確証 まで一気通貫で動くようになった。「アプリにログインするだけ」が、DPI・UI状態・認証フローの多層の罠でここまで膨らむとは思わなかった。
学び
- GUI自動化はDPIが全て。座標とスクショのピクセルが一致しない前提で設計する
- 状態で変わるUIは画像マッチしない。不変な要素(ボタン・タイトル)を基準に相対操作する
- 成功判定は最も確実な信号で。画像マッチの偽陽性は怖い
次回予告: VPS版(本番常駐)
検証で仕組みは固まった。続編では、これを本番のさくらVPSに載せて毎朝・無人で回すところをやる:
- タスクスケジューラで毎朝6:30に実行(
LogonType=Interactive・多重起動禁止・失敗時は数回で打ち切り) - 自動ログオンでコンソールセッションを生かす(RDPを切断するとGUIが描画されず動かないため)
- そして Logical225 本体の常駐(PM2) と、実発注のテスト
「VPSを再起動しても、人が触らずに自動売買が再開する」状態が、いよいよ最後のピースだ。
シリーズ: