Help us understand the problem. What is going on with this article?

Python3 requestsを使ってログインする

More than 1 year has passed since last update.

問題

Webサイトへのログイン/ログアウトを自動化したいが、
訳あってSeleniumが使えない。
Robobrowsermechanicalsoupだとログアウトのリンクが選択できない。
まあ、制約などがなければ普通はSeleniumを使うよね。
さて、困った。
その時の備忘録。

ググってみると、requestsモジュールを使用して
必要なフォームパラメータをpostしてやるとログインできるぜ!
っといった記事を多く目にした。
よし!参考になる!以前自作したWebアプリで実験。

試した環境など

・Python 3.6.7
・CentOS7
requestsモジュールのインストール

ログイン

まずは対象のログインフォームのソースを確認。

login.html
<form action="/login" accept-charset="UTF-8" method="post">
     <input name="utf8" type="hidden" value="✓">
     <input type="hidden" name="authenticity_token" value="SmPba8H6cRcKKH/hK5DAyyONn/LGWD7vPIMM4eJDQH3FIzu55qhYsJXOnub0xQaVguMH4O4qI5a0hAtyHSkZUg==">

      <div class="form-group">
        <label for="session_email">メールアドレス</label>
        <input class="form-control" type="email" name="session[email]" id="session_email">
      </div>

      <div class="form-group">
        <label for="session_password">パスワード</label>
        <input class="form-control" type="password" name="session[password]" id="session_password">
      </div>

      <input type="submit" name="commit" value="ログイン" class="btn btn-primary btn-block" data-disable-with="ログイン">
</form>

pythonのソースはこんな感じ。

login.py
import requests
import time

session = requests.session()
session.get(url)

login_data = {
   'UTF-8': '✓',
   'session[email]': メールアドレス,
   'session[password]': パスワード,
}

login = session.post(login url, data=login_data)
time.sleep(2) # 少し時間を置いてみる
print(login.text)

ムム、ログイン出来ない。
ん?フォームにはauthenticity_tokenというのがある。
これも必要かな?
ちなみにChromeデべロッパーツールでもpost時にフォームから何が送られているか確認できる。
ただ、authenticity_tokenはサイトアクセス毎にランダムで変わるね。
さて、どうやってこの隠れキャラを取得しようか?

requests以外に入れたモジュール

BeautifulSoup4
Webスクレイピングなんかでよく使われているらしい。

以下の様してみた。

login.py
import requests
import time
from bs4 import BeautifulSoup

session = requests.session()
response = session.get(url)

# BeautifulSoupオブジェクト作成(token取得の為)
bs = BeautifulSoup(response.text, 'html.parser')

login_data = {
   'UTF-8': '✓',
   'session[email]': メールアドレス,
   'session[password]': パスワード,
}

# tokenの取得
authenticity_token = bs.find(attrs={'name':'authenticity_token'}).get('value')

# 取得したtokenをpostするパラメータに追加
login_data['authenticity_token'] = authenticity_token

login_data = session.post(login url, data=login_data)
time.sleep(2)
print(login.text)

あれ?ダメでした。。
Chromeデべロッパーツールを確認するとcookie内にセッションIDがあるみたい。
こいつのチェックに弾かれている訳ですな。
じゃあ、cookieを取得してpostしてみよう。

login.py
import requests
import time
from bs4 import BeautifulSoup

session = requests.session()
response = session.get(url)

bs = BeautifulSoup(response.text, 'html.parser')

login_datadata = {
   'UTF-8': '✓',
   'session[email]': メールアドレス,
   'session[password]': パスワード,
}

authenticity_token = bs.find(attrs={'name':'authenticity_token'}).get('value')

login_data['authenticity_token'] = authenticity_token

# cookieの取得
response_cookie = response.cookies
print(response_cookie)
#<RequestsCookieJar[<Cookie _hogehoge_session=長いので省略

# post時にcookieを追加
login = session.post(login url, data=login_data, cookies=response_cookie)
time.sleep(2)
print(login.text)

おお!ログイン出来た。

ログアウト

ログアウトのhtmlはどうなっているか確認。
うん、フォームですらない。

logout.html
<a rel="nofollow" data-method="delete" href="/logout">ログアウト</a>

とりあえすhref="/logout"にフォーカスを当てたらログアウト時のURLがわかるので、
こいつにpostしてみる。
post時に送信されるデータをChromeデべロッパーツールで確認する。

login.py
# ログアウト時に送られるデータ
logout_data = {
    '_method': 'delete',
    'authenticity_token': なにかのtoken 
}

またtokenかよ。
htmlを眺めているとheadタグ内に以下のtokenが埋め込まれてた。

logout.html
<meta name="csrf-token" content="TTAEq+OCmvxSwoj98XrC08g8XtUMOLVc25xzojfu6SqKRCmNeERFgMKMJcD7pILtWvgxwhk2bueQo1ATouh/UA==">

これかな?
とりあえず手動でログアウトしてみてその際にauthenticity_tokenに入っている
tokenと照らし合わせてみると一致していた。
いや〜頼りになるなぁ〜Chromeデべロッパーツール。
なので、こいつをBeautifulSoupで取得してpostしてみる。

login.py
# metaに埋め込まれているtokenを取得
csrf_token = bs.find(attrs={'name': 'csrf-token'}).get('content')

# ログアウト時に送られるデータ
logout_data = {
    '_method': 'delete',
    'authenticity_token': csrf_token # 取得したtokenをセット 
}

logout = session.post(logout url, data=logout_data)
time.sleep(2)
print(logout.text)

おお!ログアウト出来た!
cookieはいらない様です。

全ソース

login.py
import requests
import time
from bs4 import BeautifulSoup

# セッションの作成
session = requests.session()
response = session.get(url) # ログインしたいurlを引数に入れる

# token取得用にBeautifulSoupを作成
# ちなみにパーサは'html.parser'より'lxml'の方が高速らしいが別途installが必要
bs = BeautifulSoup(response.text, 'html.parser')

# ログイン時にpostするデータを定義
# ボタン要素は無くても問題ない
login_data = {
   'UTF-8': '✓',
   'session[email]': メールアドレス,
   'session[password]': パスワード,
}

# tokenを取得
authenticity_token = bs.find(attrs={'name':'authenticity_token'}).get('value')

# 取得したtokenをログイン時にpostするデータに追加する
login_data['authenticity_token'] = authenticity_token

# cookieの取得
response_cookie = response.cookies

# ログインurl, 送信するデータ、cookieをセットしてpostする
login = session.post(login url, data=login_data, cookies=response_cookie)
time.sleep(2)

# ログイン後のソースを取得
print(login.text)

# ログアウト処理
# ログアウト時に必要なtokenを取得
csrf_token = bs.find(attrs={'name': 'csrf-token'}).get('content')

# ログアウト時にpostするデータを定義
logout_data = {
    '_method': 'delete',
    'authenticity_token': csrf_token 
}

# ログアウトurl, 送信するデータをセットしてpostする
logout = session.post(logout url, data=logout_data)
time.sleep(2)

# ログアウト後のソースを取得
print(logout.text)

そんな訳で初投稿 & 汚いソースではありますが、
requests + (BeautifulSoup)でもログイン、ログアウトが実現できる様です。
ですが正直なところ、セキュアなサイトだと出来ないかもしれませんね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした