headlessブラウザだけログイン画面に飛ばされるサービスがある

headlessブラウザだけログイン画面に飛ばされるサービスがある

Amazonアソシエイトの成果レポートを自動取得するスクリプトが、4回連続で同じ理由で失敗しました。ログには毎回「ログインが切れています」。でも実際にはログインは切れていませんでした。原因はheadless=Trueだったことです。

4回失敗して、一度も成功していなかった

Amazonアソシエイトの成果レポートを自動で取ってくるスクリプトを作りました。結果から言うと、作成してから4回とも同じ理由で失敗しており、一度も成功していません。

厄介だったのは、失敗の仕方が「それらしかった」ことです。ログには毎回、こう記録されていました。

ログインが切れています

このメッセージを見た時点で、私は原因を決めつけていました。セッションが飛んだのだろう、と。だから対処もその方向にしか向かいませんでした。ログイン状態を作り直す、プロファイルを確認する、待ち時間を延ばす。どれも的外れでした。

失敗したこと

「ログインが切れています」というログを信じて、セッション周りばかりを疑い続けたこと。実際にはログインは切れていませんでした。エラーメッセージが指している方向と、本当の原因が違っていたのです。

headless=False にしたら、何事もなく開いた

手詰まりになって、最後に画面ありで動かしてみました。同じブラウザプロファイルのまま、headless=False に変えただけです。

成果ページがそのまま開きました。ログインは求められませんでした。

つまり、headless=True のときだけ、ログイン画面にリダイレクトされていたということです。ログインそのものは最初から生きていて、切れていたことは一度もありませんでした。

実測

4回連続で失敗 → 成功 0回
失敗の理由は4回とも同じ。headless=False にした時点で解決しました。

同じプロファイル、違う結果

条件 結果
headless=True ログイン画面にリダイレクト
headless=False(同一プロファイル) 成果ページがそのまま表示

ブラウザプロファイルは変えていません。変えたのは headless の真偽値ひとつだけです。それだけで挙動が分かれました。

なぜそうなるのかは、私には分かっていません

ここは正直に書きます。headless のときだけリダイレクトされる仕組みが何なのか、私は特定できていません。

私が確認できたのは、次の事実だけです。

  • headless=True だとログイン画面に飛ばされる
  • headless=False だと成果ページが開く
  • プロファイルは同一で、ログインは切れていない
  • サービス側が何を見て判定しているのか
  • headless を回避する確実な方法があるのかどうか
  • 他のサービスでも同じことが起きるのかどうか

これらは分かっていません。推測で埋めることもできますが、それを書くと読んだ人が同じ落とし穴にはまるので、書きません。

注意

「headless だとダメ」という事実を確認しただけで、回避策を見つけたわけではありません。私の環境では headless=False で運用する形に落ち着いています。それが正解かどうかは、まだ判断がついていません。

教訓:エラーメッセージを信じすぎない

この件で一番痛かったのは、時間の使い方を完全に間違えたことです。「ログインが切れています」と書いてあったので、ログインを疑いました。ログを読むという行為自体は正しいのに、そこから先の判断が固定されてしまいました。

もし2回目の失敗の時点で画面ありで開いていれば、その場で終わっていた話です。「ログインが切れている」と読めるエラーでも、まず画面ありで確認してから判断する。これが今回得た唯一で最大の教訓です。

ポイント

headless で失敗したときの確認は、コードを直す前に headless=False にして自分の目で見ること。画面に何が表示されているかが分かれば、ログの文言に引きずられずに済みます。

私が今後やる順番

  1. 失敗ログを読む(ただし結論は出さない)
  2. 同じプロファイルのまま headless=False で再実行する
  3. 画面に実際に何が出ているかを目で確認する
  4. そこで初めて原因を判断する

順番を入れ替えただけですが、今回に限って言えば、これで4回分の失敗が防げたはずです。

うまくいったこと

headless=False に切り替えたら、成果ページがそのまま開きました。プロファイルの作り直しも、ログイン処理の追加も必要ありませんでした。

自動化を組む人へ

headless は便利です。画面を出さずに済むので、サーバー上でもバックグラウンドでも動かせます。ただ、headless であること自体がサービス側の挙動を変える場合がある、という可能性を頭の片隅に置いておく必要があります。少なくとも私が触ったこのケースでは、そうでした。

そして、エラーメッセージは親切なようでいて、こちらの思考を縛ります。今回の「ログインが切れています」は、私のスクリプトが出したログですが、その判定ロジックが見ていたのは「ログイン画面にいるかどうか」だったわけです。画面には確かにログインフォームが出ていた。だからログは間違っていない。ただ、その理由が私の想定と違っただけです。

まとめ

  • Amazonアソシエイトの成果レポート自動取得が4回連続で失敗し、成功は0回だった
  • ログは毎回「ログインが切れています」だったが、実際にはログインは切れていなかった
  • headless=True のときだけログイン画面にリダイレクトされていた
  • 同じプロファイルのまま headless=False にすると、成果ページがそのまま開いた
  • なぜ headless だけ弾かれるのか、その仕組みは特定できていない
  • 「ログインが切れている」と読めるエラーでも、まず画面ありで確認してから判断すること
広告