RequestsでSessionモード

# 概要
ログインを必要とするWebサイトの情報をRequestsを用いて取得しようとする際、その都度GETやPOSTでアクセスするとセッションが途切れてしまい毎回ログイン処理をしないといけません。
これを回避するためにRequestsはSessionモードをサポートしています。
具体的にはcookieを保持しつつurllib3のconnectionpoolモジュールを使用し、基盤となるTCP接続を再利用していくようです。
アクセスにかかる負荷(サーバー側がデータベースにアクセスする時間)の軽減やパフォーマンスの大幅な向上などが期待されます。

# 試してみよう
リアルタイムフライト追跡の過去データを公開しているFlightAware[^1]からANA109便のフライト履歴を読み込むコードを書いてみます。
ログインしていない場合は2週間分、ログイン後は3か月分のフライト履歴が見れます。
`Requests.Session()`を記述することでSessionモードが有効になります。

# サンプルコード
### ログイン処理なし
```python:nologin.py
import requests as rq

st = rq.get("https://ja.flightaware.com/live/flight/ANA106/history/160")
print(st.text)
```


```console:console
<!DOCTYPE HTML>
<html dir="LTR" lang="ja" class="responsive-full">
 <!--
Looking at the source?  Great!
  FlightAware is looking for UI/UX, web, and backend developers, mathematicians and electrical engineers.

・
・
・

... <strong>ベーシックユーザー（登録は無料で簡単です！）は3 monthsの履歴を見ることができます。 <a href="/account/join">登録する</a></strong> ...
```

なんか褒められました。
ベーシックユーザーなんちゃらかんちゃらの表示がなくなって3ヶ月分の履歴が表示されるようにします。

### Session使用
```python:session.py
import requests as rq

ses = rq.Session()
st = ses.post("https://ja.flightaware.com/account/session", 
              params={'flightaware_username':'{登録ユーザー名}',
                      'flightaware_password':'{登録パスワード}',
                      'mode':'login'})
print('login_status:'+str(st.status_code))

st = ses.get("https://ja.flightaware.com/live/flight/ANA106/history/160")
print(st.text)
```

{登録ユーザー名}と{登録パスワード}はFlightAwareに登録した任意の文字列です。
3ヶ月分のフライト履歴が表示できていると思います。
別のページにアクセスしてもちゃんとログイン状態が保持されています。

### Session未使用

```python:nosession.py
import requests as rq

st = rq.post("https://ja.flightaware.com/account/session", 
              params={'flightaware_username':'{登録ユーザー名}',
                      'flightaware_password':'{登録パスワード}',
                      'mode':'login'})
print('login_status:'+str(st.status_code))

st = rq.get("https://ja.flightaware.com/live/flight/ANA106/history/160")
print(st.text)
```

```console:console
login_status:200
<!DOCTYPE HTML>
<html dir="LTR" lang="ja" class="responsive-full">
・
・
・
... <strong>ベーシックユーザー（登録は無料で簡単です！）は3 monthsの履歴を見ることができます。 <a href="/account/join">登録する</a></strong> ...
```

Sessionモードでない場合

### with構文との併用
Sessionはコンテキストマネージャとしても使用できるようです。

```python:nosession.py
import requests as rq

with rq.Session() as s:
    st = s.post("https://ja.flightaware.com/account/session", 
              params={'flightaware_username':'{登録ユーザー名}',
                      'flightaware_password':'{登録パスワード}',
                      'mode':'login'})
    print('login_status:'+str(st.status_code))

    st = s.get("https://ja.flightaware.com/live/flight/ANA106/history/160")
    print(st.text)
```

この場合、未処理の例外が発生してもwithブロックが終了するとすぐにセッションが確実に閉じられます。
基本的にはこっちを使った方がいいかも？

### パラメタの削除
辞書型になっているパラメータから値を削除したい場合は単にそのキーの値をNoneに設定します。
自動的に省略されます。

```python:.py
p={'flightaware_username':'{登録ユーザー名}',
        'flightaware_password':'{登録パスワード}',
        'mode':'login'}

p['mode']=None

with rq.Session() as s:
    st = s.post("https://ja.flightaware.com/account/session", params=p)
    print('login_status:'+str(st.status_code))

    st = s.get("https://ja.flightaware.com/live/flight/ANA106/history/160")
    print(st.text)
```

上のコードでは必要なパラメタが削除されているためログインに失敗します。


# 参考サイト
http://docs.python-requests.org/en/master/user/advanced/ (Requests公式/Advanced)

[^1]: https://ja.flightaware.com/