0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Playwright の launchPersistentContext に storageState を渡しても Cookie は1つも注入されない

0
Posted at

この記事は「ドキュメントに書いてあること」と「実際に測った結果」の差を整理した検証ログです。Playwright でブラウザログインを自動化している人向け。

Playwright でログイン済みセッションを使い回す方法は2系統あります。

  • storageState: Cookie / LocalStorage を JSON に書き出して注入する
  • launchPersistentContext: ブラウザプロファイルをディレクトリごと永続化する

公式 API リファレンスでは launchPersistentContext のオプションにも storageState があるので、「両方渡せば引っ越しできるはず」——と思って実装したら、ログイン画面にリダイレクトされました。

原因を測ったら、想像より単純な話でした。

検証環境: Windows 11 / Playwright 1.55 / channel: 'chrome' (Chrome 140) / 対象サービス: Qiita


測り方: 同じ storageState を3通りで注入する

Qiita にログイン済みのプロファイルから context.storageState() で JSON を保存し、以下の3パターンで https://qiita.com/settings/notifications(ログイン必須ページ)を開きました。

# 方法 意図
A browser.newContext({ storageState }) 普通の context に注入
B launchPersistentContext(新規dir, { storageState }) 空のプロファイルに注入
C launchPersistentContext(ログイン時のdir) プロファイル丸ごと再利用

結果: B だけログインできない

検証結果サマリー

方法 結果
A: newContext + storageState ✅ 設定画面が開いた
B: persistentContext(新規dir) + storageState ❌ /login にリダイレクト
C: persistentContext(元dir) ✅ 設定画面が開いた

B が失敗するのは「Cookie の有効期限が切れた」系ではありません。保存した JSON の Cookie はすべて有効期限内で、A では同じファイルがちゃんと効いています。


原因: Cookie が1つも注入されていなかった

persistent context を起動して context.cookies() を見ると、こうなります。

const ctx = await chromium.launchPersistentContext('.fresh-profile', {
  channel: 'chrome',
  storageState: '.qiita-session.json', // Cookie 8件入り
});

console.log(await ctx.cookies('https://qiita.com'));
// → []  ← 空。storageState がサイレントに無視される

渡したはずの Cookie がゼロ件。 エラーも警告も出ず、ただ注入されません。
newContext 側は同じファイルで全件注入されます。つまり挙動はこうです。

API storageState
browser.newContext({ storageState }) 注入される
launchPersistentContext(dir, { storageState }) 注入されない

型定義上は storageState を受け取れるので、書けてしまうのが罠です。channel: 'chrome'(実 Chrome)で再現を確認しています。bundled Chromium では挙動が違う可能性はあります。


正しい構成: プロファイル dir を「鍵」として運用する

persistent context を使うなら、storageState に頼らずログインしたディレクトリ自体を再利用するのが正解です。

正しい構成

// 初回: headed で起動して人間がログイン
const ctx = await chromium.launchPersistentContext('.session-qiita', {
  channel: 'chrome',
  headless: false,
});

// 2回目〜: 同じ dir を指定するだけでログイン済み
const ctx2 = await chromium.launchPersistentContext('.session-qiita', {
  channel: 'chrome',
  headless: true, // OK
});

サービス × アカウント単位でディレクトリを分けるのが運用のコツです。

.session-note-ryuhat/      ← note アカウントA
.session-qiita-ryuhat/     ← Qiita アカウントA
.session-twitter-ryuhat2/  ← X アカウントB

storageState が有効な場面

newContext 系にだけ使う、と割り切ると整理しやすいです。

  • ✅ browser.newContext({ storageState }) — テスト・スクレイピングの使い捨てセッション
  • ✅ CI で secrets から注入して認証済みテストを回す
  • ❌ launchPersistentContext への注入 — 効かない
  • ❌ persistent dir と storageState の併用 — storageState 側が無視される

まとめ

  • launchPersistentContext に storageState を渡しても Cookie は注入されない(1件も)
  • ログインが必要な persistent context では、ログインしたプロファイル dir をそのまま再利用する
  • ドキュメントに載っている引数でも、対象 API では無視されることがある——疑ったら context.cookies() で数えるのが一番早い

自動投稿・スクレイピング・E2E でセッション管理を組むときの参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?