タイトル: cookieの値の設定と取得
SEOタイトル: Python で Cookie を扱う|requests の Session と http.cookies
| この記事の要点 |
|
Session を使うのが基本
Cookie は「1 回のリクエストの設定」ではなく「やり取りをまたいで持ち回る状態」です。requests.Session を使うと、サーバーから返ってきた Cookie を自動で保存し、次のリクエストに付けてくれます。
import requests
session = requests.Session()
# 1. ログイン。返ってきたセッション Cookie が session に保存される
session.post("https://example.com/login",
data={"username": "taro", "password": "secret"},
timeout=10)
# 2. 以降のリクエストには自動で付く
res = session.get("https://example.com/mypage", timeout=10)
print(res.status_code)
print(session.cookies.get_dict()) # {'sessionid': 'abc123'}
session.close()
requests.get() を単発で呼ぶ方法では Cookie が保持されないため、ログインが必要なページは必ず 401 / ログイン画面に戻されます。
Cookie を明示的に設定する
import requests
# その 1 回だけ付ける
res = requests.get("https://example.com/",
cookies={"lang": "ja", "theme": "dark"},
timeout=10)
# Session に常設する(以降すべてのリクエストに付く)
session = requests.Session()
session.cookies.set("lang", "ja")
session.cookies.set("sessionid", "abc123",
domain="example.com", path="/")
# ヘッダーとして直接書くこともできるが、Session の管理から外れるので非推奨
res = requests.get(url, headers={"Cookie": "lang=ja; theme=dark"}, timeout=10)
domain を指定しないと、そのリクエストのホストにだけ送られます。複数のサブドメインをまたぐ場合は明示してください。
受け取った Cookie を読む
res = requests.get("https://example.com/", timeout=10)
print(res.cookies.get_dict()) # そのレスポンスで設定されたものだけ
print(res.cookies.get("sessionid")) # 無ければ None
print(res.headers.get("Set-Cookie")) # 生のヘッダー文字列
# 属性まで見たいときは 1 個ずつ走査する
for c in res.cookies:
print(c.name, c.value, c.domain, c.path, c.secure, c.expires)
| 書き方 | 返るもの |
|---|---|
res.cookies | そのレスポンスで新しく設定された Cookie |
session.cookies | これまでに蓄積されたすべての Cookie |
res.request.headers["Cookie"] | 実際に送信した Cookie ヘッダー |
「送ったつもりが送られていない」場合は 3 番目を確認します。ドメインやパスが合っていないと、保持されていても送信対象から外れます。
削除と更新
session.cookies.set("lang", "en") # 同じ名前なら上書き
del session.cookies["lang"] # 1 個削除
session.cookies.clear() # 全削除(ログアウト相当)
session.cookies.clear("example.com") # ドメイン単位で削除
print("lang" in session.cookies.get_dict()) # False
ログイン状態をファイルに保存する
import http.cookiejar
import os
import requests
JAR_PATH = "cookies.txt"
jar = http.cookiejar.LWPCookieJar(JAR_PATH)
if os.path.exists(JAR_PATH):
jar.load(ignore_discard=True) # 前回の Cookie を復元
session = requests.Session()
session.cookies = jar # Session に差し込む
session.get("https://example.com/mypage", timeout=10)
jar.save(ignore_discard=True) # セッション Cookie も含めて保存
ignore_discard=True を付けないと、ブラウザを閉じたら消える種類の Cookie が保存されません。保存したファイルはログイン情報そのものなので、権限を絞り、リポジトリに入れないでください。
サーバー側で Cookie を返す
Web アプリを自作する場合は Set-Cookie ヘッダーを組み立てます。標準ライブラリの http.cookies が属性のエスケープまで面倒を見てくれます。
from http.cookies import SimpleCookie
cookie = SimpleCookie()
cookie["sessionid"] = "abc123"
cookie["sessionid"]["path"] = "/"
cookie["sessionid"]["max-age"] = 3600
cookie["sessionid"]["httponly"] = True # JavaScript から読めなくする
cookie["sessionid"]["secure"] = True # HTTPS のときだけ送らせる
cookie["sessionid"]["samesite"] = "Lax" # 別サイトからの送信を制限
print(cookie.output(header="Set-Cookie:"))
# Set-Cookie: sessionid=abc123; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure
# 受け取ったヘッダーを解析する
incoming = SimpleCookie("lang=ja; theme=dark")
print(incoming["lang"].value) # ja
| 属性 | 意味 | 推奨 |
|---|---|---|
HttpOnly | JavaScript から読めなくする | セッション ID には必ず付ける |
Secure | HTTPS のときだけ送る | 本番では付ける |
SameSite | 他サイト由来のリクエストで送るか | Lax が既定的。決済系は Strict |
Max-Age / Expires | 有効期限 | 省略するとブラウザを閉じるまで |
Path / Domain | 送信対象の範囲 | 広げすぎない |
よくある詰まりどころ
- Session を使っていない — 単発の
requests.get()では Cookie が引き継がれない - リダイレクト先で消える —
allow_redirects=Falseにして途中のSet-Cookieを確認する - ログインが JavaScript 経由 — フォーム POST ではなく API を叩いている。ブラウザの開発者ツールで実際のリクエストを見る
- CSRF トークンが必要 — ログインページを一度 GET してトークンを取り出し、POST に含める
- 日本語や記号が入る値 —
urllib.parse.quote()でエンコードしてから入れる
関連
- 文法 — 親カテゴリ
- httpリクエスト(curl)をする方法
- Responseオブジェクトの中身の確認
- Webスクレイピング
- cookieの値の設定と取得 — Django での扱い