52
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-04-11

#問題
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)でもログイン、ログアウトが実現できる様です。
ですが正直なところ、セキュアなサイトだと出来ないかもしれませんね。

52
55
1

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
52
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?