このページでは、requests
モジュールの使い方の応用編として、Django で開発されるウェブアプリを利用して POST
メソッドのリクエスト送信の実践を行っていきたいと思います!
requests
モジュール自体については下記ページで解説していますので、requests
モジュールを使ったことのない方は下記ページを事前に読んでおくことをオススメします。
上記ページでも requests
モジュールの使用例を示しているのですが、基本的には GET
メソッドのリクエストの送信例を示すページとなっています。このページでは、POST
メソッドのリクエストの送信の例を示していきます。
また、ページの冒頭でも触れたように、今回は Django を利用し、Django が提供する管理画面に対してログインやユーザー作成等を requests
モジュールから行う例を示していきます。もちろん、ログイン等のウェブアプリの操作はユーザーが手動で実施することも可能です、ですが、requests
モジュールから POST
メソッドを送信してウェブアプリの操作が行えるようになれば、そのスクリプトを定期的に実行するようにするだけでウェブアプリの動作確認等を自動的に・定期的に実施可能となるメリットが得られます。
ということで、このページでは、まず requests
からのウェブアプリ操作を実現する考え方について説明したのちに、Django の導入手順を簡単に説明し、その後 Django を利用してウェブアプリ(といっても管理画面のみを持つアプリ)を作成する手順を説明していきたいと思います。そして、その後に、実際に作成したウェブアプリへの操作を requests
モジュールからの POST
メソッドの送信によって実現する例を示していきたいと思います。
ちょっと難易度は高めですし、Django の管理画面ならではのリクエストを送信するための実装なども必要になるのですが、それでも読み進めていただければ requests
モジュールから POST
メソッドのリクエストの送信の仕方や、送信するときの注意点などを理解していただけると思います。
Contents
requests
からのウェブアプリの操作
では、まずは requests
からのウェブアプリの操作を実現する考え方について説明していきます。
最初に断っておくと、下記ページでも説明しているように、あくまでも requests
は HTTP リクエストを送信し、その HTTP レスポンスを受信するモジュールです。
それに対し、ウェブアプリは通常ウェブブラウザから操作が行われるアプリとなります。例えば X (旧 Twitter) であればウェブブラウザから操作が可能であり、ウェブアプリの1つであると考えることができます。
多くのウェブアプリの場合、iOS 用・Android 用等の専用クライアントアプリを利用して操作することも可能ですが、今回はウェブブラウザからの操作に焦点を当てて説明していきます
このように、ウェブアプリがウェブブラウザから操作可能なのは、ウェブブラウザがユーザーの操作に応じた HTTP リクエストをウェブアプリに対して送信するようになっているからになります。そして、その HTTP リクエストを受け取ったウェブアプリがそのリクエストに応じた処理を実行します。
例えばユーザーによってウェブブラウザからツイートが行われたのであれば、ツイートを新規登録するためのリクエストがウェブブラウザからウェブアプリに送信され、それを受け取ったウェブアプリが送信されてきたツイートを新規登録する感じになります。
ここで重要なのは、ウェブアプリはウェブブラウザからの操作に応じた処理を行うのではなく受信した HTTP リクエストに応じた処理を行うという点になります。つまり、ウェブブラウザからでなく、あなた自身が実装したスクリプトから HTTP リクエストを送信したとしても、そのリクエストに応じた処理をウェブアプリが行なってくれます。
リクエストのヘッダーにはリクエスト送信元のブラウザの情報などが含まれており、その情報によってリクエストを拒否するようなサーバーやアプリもあります
この場合は、スクリプトから実行するとリクエストが拒否される場合があります
そして、その HTTP リクエストを送信するモジュールの1つが requests
になります。つまり、Python スクリプトから requests
を利用してウェブブラウザ操作時に送信される HTTP リクエストと同じものを送信してやれば、ウェブブラウザからの操作と同等の操作を Python スクリプトから実現することが可能となります。
ただし、ウェブアプリはどんなリクエストでも受け付けるというわけではありません。そして、ウェブアプリが受け付け可能な HTTP リクエストはウェブアプリによって異なります。特に POST
メソッドの場合は、送信するリクエストのボディが「ウェブアプリの期待するもの」である必要がある点に注意が必要です。
ウェブブラウザで操作する場合、ボタンのクリック等を行なった際には基本的にウェブアプリが受け付け可能な HTTP リクエストが送信されることになります。こういったボタンのクリック時に送信される HTTP リクエストはウェブアプリによって提供される HTML 等に基づいて生成されます。そして、この HTML 等はウェブアプリ側から提供されるものであり、ウェブアプリが受け付け可能なリクエストが送信されるように作られています。そのため、ウェブブラウザでウェブアプリの操作を行う場合はユーザーが意識しなくてもウェブアプリが受け付け可能なリクエストが自動的に送信されるようになっています。
その一方で requests
モジュールの場合、HTTP リクエストの送信自体は関数を実行するだけで実現できますが、どんなリクエストのデータを送信するかは Python スクリプトの実装によって決まります。具体的には実行する関数や引数によって決まります。したがって、requests
モジュールを利用する場合はウェブアプリが受付可能な HTTP リクエストが送信されるようにスクリプトを実装する必要があります。デタラメな実装で HTTP リクエストを送信してもウェブアプリからエラーが返却されることになって操作が行えません。
では、具体的にどうやって実装すれば良いかというと、その実装の仕方の1つは「ウェブブラウザからのウェブアプリ操作時に送信される HTTP リクエストを真似る」になります。前述の通り、ウェブアプリが操作可能なのはウェブブラウザから HTTP リクエストが送信されるからで、さらに、その HTTP リクエストはウェブアプリが受け付け可能な HTTP リクエストになります。
したがって、例えばウェブブラウザからの操作時にウェブブラウザから送信される HTTP リクエストのデータの中身を確認し、そのデータと同等のものが送信できるように Python スクリプトを実装すれば、ウェブブラウザで操作した時と同様の HTTP リクエストがウェブアプリに送信できることになります。そして、この場合はウェブブラウザからの操作時と同等の操作を行うことができます。
そのため、例えばウェブアプリへのログインを requests
モジュールから行うためには、まずウェブブラウザからウェブアプリへのログインを実施し、その際にウェブブラウザから送信されるリクエストのデータの確認を行います。そして、そのデータと同等のリクエストが requests
モジュールから送信されるように Python スクリプトの実装を行う、といった感じの流れになります。
面倒ですが、一度 Python スクリプトの実装を行なっておけば、あとはそのスクリプトを実行するだけで同様の操作が行えるようになります。ですので、定期的に同様の操作を行なったり、自動的に何回も繰り返し行なったりすることができるようになります。
また、ウェブブラウザから送信される通信データは下記ページで紹介している Wireshark 等のツールを利用することで確認可能です。ただ、通信データが暗号化されている可能性があるので、その点は注意が必要となります。今回用意するウェブアプリでは通信データが暗号化されていないので通信データは簡単に確認可能です。
Wiresharkのインストール方法と使い方【Windows編】 Wiresharkのインストール方法とChmodBPFでの権限設定【Mac編】もちろん、ウェブアプリの仕様として各操作時に期待するリクエストが公開されているような場合もあります。例えば REST API などが実装されている場合、その仕様が公開されていることが多いです。この場合は、通信データを実際に確認しなくても、その仕様に合ったリクエストが送信されるように Python スククリプトを実装すれば良いです。
とりあえず、requests
モジュールからウェブアプリの操作が行える理由については大体理解していただけたのではないかと思います。以降の説明では、まずウェブアプリを準備した後、実際に requests
モジュールからウェブアプリの操作を行う例を示していきます。
ウェブアプリの準備
まずは事前準備として requests
モジュールからの操作対象となるウェブアプリを作成し、そのウェブアプリの起動を行なっていきたいと思います。
このウェブアプリは Django を利用して作成するため、事前に Django をインストールする必要があります。
そのため、requests
モジュールの使用例を示す前に、まず下記の3つの手順について説明していきます。
既に Django のインストールが完了しているという方は、ウェブアプリの作成 までスキップしていただいて問題ありません。
スポンサーリンク
Django のインストール
では、まずは Django のインストールを行なっていきましょう。Django も requests
や他のモジュール同様に pip
でインストールを行うことができます。
具体的には、下記のコマンドを実行することで Django のインストールが行われます。
% python -m pip install django
ウェブアプリの作成
Django がインストールされれば、次はウェブアプリの作成を行なっていきます。
今回は手順を簡単にするため、管理画面のみを持つウェブアプリを作成します。Django の管理画面ではユーザーの作成等の操作を行うことが可能です。また、この Django の管理画面を利用するためには事前にログインを行なっておく必要があります。そして、このページでは、最終的にはこういった手順をウェブブラウザではなく requests
モジュールから行うための実装について説明していきます。
ということで、まずはウェブアプリを作成していきましょう!Django をインストールすれば django-admin
が利用可能になっており、この django-admin
を利用してウェブアプリを作成することができます。
まずは、適当な作業フォルダに移動したのち、下記のコマンドを実行してください。アプリの作成自体はこれで完了です。
% django-admin startproject requests_test
これにより、今いる作業フォルダの中に request_test
というフォルダが作成されるはずです。
django-admin
が上手く利用できない場合は下記ページを参考にしてください
次は下記コマンドを実行して、この requests_test
の中に移動してください。
% cd requests_test
ウェブアプリの起動
続いて、管理画面を利用するために必要となる準備を行い、その後にウェブアプリの起動を行なっていきます。
マイグレーションの実施
まず、下記コマンドを実行してマイグレーションという操作を実施してください。これにより、管理画面からユーザーの作成や削除等の操作を行うことができるようになります(データベースの中にユーザー管理用のテーブルが作成されます)。
% python manage.py migrate
ユーザーの作成
また、管理画面を利用するためにはログインが必要です。このログインを行うため、ログイン用のユーザーの作成が必要となります。このユーザー作成を行うため、まずは下記コマンドを実行します。
% python manage.py createsuperuser
上記コマンドを実行すればユーザー名とメールアドレスとパスワードの入力が促されます。ここでは、ユーザー名を YamadaHanako
、メールアドレスを hanako@example.com
、パスワードを yh123456
としたいと思います。ということで、これらの入力を行ってユーザー作成を進めてください。パスワードは2回同じものを入力する必要があります。
下記のように Superuser created successfully.
と表示されればユーザーの作成に成功したことになります。
Username (leave blank to use 'daeu'): YamadaHanako Email address: hanako@example.com Password: Password (again): Superuser created successfully.
これ以降、ウェブアプリの管理画面にログインする際には、ここで作成したユーザーを利用してログインを行うことになります。
ウェブアプリの起動
以上で、ウェブアプリを起動するための事前準備は完了したことになります。続いて、下記コマンドを実行してウェブアプリを起動しましょう!
% python manage.py runserver
上記コマンドを実行すればウェブアプリが起動し、コマンドがずっと実行された状態となります。ウェブアプリを終了させたい場合は、このコマンドを ctrl
+ c
の入力で終了させてやれば良いです。とりあえず、ここではウェブアプリを起動したままにしておきましょう。
ウェブアプリが起動中の間は、ウェブブラウザや requests
モジュールからの HTTP リクエストを受け付けてくれるようになっています。
スポンサーリンク
requests
からのウェブアプリの操作例
ウェブアプリの用意ができたため、次は実際に requests
を利用してウェブアプリを操作する例を示していきたいと思います。
requests からのウェブアプリの操作 で説明したように、基本的にはウェブブラウザからの操作は requests
モジュールからのリクエストの送信で代替できます。
ただし、requests
モジュールから送信する HTTP リクエストをウェブブラウザからの操作時に送信される HTTP リクエストと同等のものにする必要があるため、まずはウェブブラウザでウェブアプリの操作を行ってリクエストのデータを確認し、それを requests
モジュールから送信するように Python スクリプトを実装していくようにしていきたいと思います。
(参考)Wireshark の設定
ウェブブラウザ操作時に送信される HTTP リクエストを確認するため、以降の解説では、私の PC 上の Wireshark というツールででキャプチャした通信データを紹介していきます。ご自身の PC での Wireshark のインストールや起動は必須ではありませんが、解説内容に合わせてご自身で実際に Wireshark を利用していただければ Wireshark や通信についての勉強もすることができると思います。
ここでは、ウェブブラウザ操作時に送信される HTTP リクエストを確認するための Wireshark の準備について説明します。Wireshark の利用が不要であるという方は、次の ログイン操作を行う までスキップしていただければと思います。
まず、前述でも簡単に紹介しましたが、Wireshark の解説やインストール手順の説明は下記ページで行なっています。
Wiresharkのインストール方法と使い方【Windows編】 Wiresharkのインストール方法とChmodBPFでの権限設定【Mac編】Wireshark インストール後に Wireshark を起動して Loopback; lo0
や Adapter for loopback traffic capture
等の loopback
という単語が含まれているインターフェースを選択すれば、自分自身の PC に対して送信される通信データが Wireshark でキャプチャされるようになります。先ほど作成したウェブアプリは、あなたの PC 上で動作していますので、このようにインターフェースを選択することで、あなたの PC 上で動作しているウェブブラウザと、あなたの PC 上で動作しているウェブアプリとの間でやりとりされる通信データがキャプチャ可能となります。
さらに、Wireshark のウィンドウ上部にある入力バーに http
と入力してエンターキーを押せば、通信プロトコルが HTTP である通信データのみが Wireshark のウィンドウ上側のリストに表示されるようになります。これにより、ウェブブラウザ操作時にウェブブラウザとウェブアプリとの間でやりとりされる HTTP リクエストや HTTP レスポンスが WIreshark で観察しやすくなります。
ログイン操作を行う
では、先ほど作成したウェブアプリの管理画面にウェブブラウザでログイン操作を行い、その際に送信されるリクエストのデータを確認していきたいと思います。
その後、requests
モジュールで同様のリクエストのデータを送信して requests
モジュールからの管理画面へのログインを実現していきます。
ログイン操作時の通信データの確認
まずは、ウェブブラウザを起動し、下記 URL を開いてみましょう。これは先ほど作成したウェブアプリにおける管理画面へのログインページの URL となります。
http://localhost:8000/admin/login/
URL を開けば下の図のようなログインフォームが表示されると思います。
このログインフォームの Username
と Password
の入力欄それぞれに ユーザーの作成 で作成したユーザーのユーザー名(YamadaHanako
)とパスワード(yh123456
)を入力して Log in
ボタンをクリックすればログインが実行されることになります。そして、この時に送信されるデータを requests
モジュールから送信してやればログインを行うことも可能となります。
ということで、まずはログイン操作を手動で実施し、その時の通信データの内容を確認したいと思います。Wireshark を動作させた状態でログイン操作を実施すれば、ウェブブラウザで表示中のページが /admin/login/
から /admin/
に遷移して管理画面が表示されることになります。そして、Wireshark の画面では下の図のように6つの通信データがキャプチャされたことが確認できます。
この6つの通信データは、上から順に次のような意味を持つ通信データとなります。
- ウェブブラウザからの
/admin/login/
へのGET
メソッドのリクエスト - ウェブブラウザへの
/admin/login/
の表示用データのレスポンス - ウェブブラウザからの
/admin/login/
へのPOST
メソッドのリクエスト(ログインのリクエスト) - ウェブブラウザへのログイン許可および
/admin/
へのリダイレクトレスポンス - ウェブブラウザからの
/admin/
へのGET
メソッドのリクエスト - ウェブブラウザへの
/admin/
の表示用データのレスポンス
1. と 2. によってログインフォームが表示され、3. と 4. によってログインが行われ、5. と 6. によってログイン状態でないと表示できない管理画面が表示されることになります。
ウェブブラウザからのログイン操作によって送信されるリクエストは 3. のものになります。したがって、この 3. で送信されるリクエストを requests
モジュールから送信してやれば、ログインが実施されて 4. のレスポンスが得られると考えられます。
ということで、3. で送信されるリクエストのデータの詳細を確認してみましょう!
このデータで注目すべき点は3つあります。
1つ目は、ログインを行うためのユーザー情報として "username"="YamadaHanako"
と "password"="yh123456"
がデータに含まれているという点になります。このデータはボディに存在しています。これらはログインフォームに入力したものなので、これらのデータが送信されているのは納得だと思います。
2つ目は、ボディに "csrfmiddlewaretoken"="略"
というデータも存在しているという点になります。これは何のデータなのでしょうか?ちなみに、"next"="/admin/"
というデータも存在しますが、これはログイン後に表示するページのパス(URL)を示すものなので、ここでは特に注目はしません。
3つ目は、ヘッダーフィールドの Cookie
に csrftoken="略"
が存在している点になります。
つまり、ログインフォームからログインを行う際には username
と password
だけでなく、csrfmiddlewaretoken
も含めたボディのリクエストがウェブブラウザから送信されています。そして、ヘッダーフィールドの Cookie
にも csrftoken
がセットされた状態でリクエストが送信されています。
ログインフォームだけ見ると、ログインに必要な情報は username
と password
のみに思えますが、実はボディに csrfmiddlewaretoken
が存在しなければログインに失敗することになります。また、ヘッダーフィールドの Cookie
にも csrftoken
が存在しない場合もログインに失敗します。
つまり、Django のアプリの管理画面にログインするためには、ボディに下記の3つのフィールドが必要で、さらに Cookie
に csrftoken
もセットしておく必要があります。したがって、requests
モジュールからログインを行う際にも、これらの情報を含めたデータをリクエストとして送信する必要があることになります。
username
password
csrfmiddlewaretoken
ちなみに、csrfmiddlewaretoken
や csrftoken
が必要なのはウェブアプリ側にセキュリティ対策が講じられているからになります。Django のアプリでは、これらの情報がリクエストに存在しない場合にフォームからのデータ送信を受け付けないようになっていますが、別のアプリではもっと他のセキュリティ対策が講じられている可能性もあります。なので、どんなアプリでも上記のような情報が必要になるというわけではありません。重要なのは、目的のアプリに応じたリクエストの送信を行うことになります。
で、username
と password
フィールドの値としては ユーザーの作成 で作成したユーザーのユーザー名(YamadaHanako
)とパスワード(yh123456
)を設定してやれば良いです。
じゃあ csrfmiddlewaretoken
と csrftoken
の値は何にすれば良いかというと、実はこれらの値はログインフォームを表示する際にウェブアプリからのレスポンスとして受け取っています。
ここで、2. の通信データに注目すると、下の図のように csrfmiddlewaretoken
の値がボディとなる HTML の中に埋め込まれています。
また、csrftoken
も Cookie にセットされた状態で受け取っていることが確認できます。
なので、ログインフォームの表示のリクエストに対するレスポンスを受け取ってこれらの値を取得し、これらの値を含めてリクエストを送信してやれば、ウェブアプリからログイン操作した時と同様の通信データが送信できることになります。したがって、このようなデータを送信してやることで、ウェブブラウザからではなく requests
モジュールからのログインが実現できることになります。
このログイン実施後に重要となるのが、ログイン中であることを示すデータになります。ウェブブラウザの場合、そのデータをログインのリクエストに対するレスポンスで受け取り、ログイン後に送信されるリクエストにはそのデータが自動的に付加されるようになっています。そのため、ログインしていないとアクセス不可なページであっても、一度ウェブブラウザからログインを行なっておけば、以降はログインなしでウェブブラウザから表示可能となります。
それに対し、requests
モジュールの場合は、requests
モジュールの利用者(開発者)が明示的にログイン中であることを示すデータをリクエストにセットしてリクエストを送信するように実装する必要があります。
そして、このログイン中であることを示すデータは、Django の管理画面の場合はリクエストのヘッダーフィールドにおける Cookie
の sessionid
になります。この sessionid
はログインのリクエストに対するレスポンスのヘッダーフィールドの Set-Cookie
にセットされています。
なので、この sessionid
を取得し、それをヘッダーフィールドの Cookie
にセットしたリクエストを送信するようにすれば、ログイン中でないとアクセス不可なページも requests
モジュールからアクセス可能となります。
逆に、この sessionid
を Cookie
にセットせずにリクエストを送信した場合、ウェブアプリには非ログイン中のユーザーであるとみなされることになるので注意してください。
長々と説明しましたが、内容をまとめると、先ほど行なったウェブブラウザでの操作を requests
モジュールから行うようにするためには、下記で示した処理を Python スクリプトから実装してやれば良いことになります。
/admin/login/
に対するリクエストをrequests.get
で送信requests.get
の返却値からレスポンスを取得csrfmiddlewaretoken
とCookie
を取得
Cookie
をセットした状態で、/admin/login/
に対するリクエストに下記のフィールドを持つボディをセットしてrequests.post
で送信-
Username=ユーザー名
Password=パスワード
csrfmiddlewaretoken=2. で取得した値
-
requests.post
の返却値からレスポンスを取得sessionid
を含むCookie
を取得
Cookie
をセットした状態で/admin/
に対するリクエストをrequests.get
で送信requests.get
の返却値から/admin/
の HTML が取得されていることを確認
前述の通り、/admin/
はログイン状態でないとページの表示(HTML の取得)ができません。そのため、6. で /admin/
の HTML が取得できればログインに成功したと考えられます。
requests
モジュールからのログイン操作
では、ここまで説明した内容を踏まえて requests
モジュールからのログイン操作を実際に行っていきたいと思います。
先ほど示した流れに基づいた処理をスクリプトとして実装すれば良いので、結論としては下記のようなスクリプトを実装してやれば良いことになります。
import requests
import re
login_url = 'http://localhost:8000/admin/login/'
admin_url = 'http://localhost:8000/admin/'
cookies = None
def login(username, password):
global cookies
# /admin/login/のHTMLをGETリクエストで取得
response = requests.get(login_url, allow_redirects=False)
if response.status_code != 200:
# HTMLの取得に失敗した場合
return False
# csrftokenがセットされたCookieでcookiesを更新
cookies = response.cookies
# HTMLに埋め込まれたcsrfmiddlewaretokenを取得
pattern = 'name="csrfmiddlewaretoken" value="(.+)"'
csrfmiddlewaretoken = re.search(pattern, response.text).group(1)
# usernameとpasswordに加えてcsrfmiddlewaretokenをPOSTリクエストで送信
data = {
'username': username,
'password': password,
'csrfmiddlewaretoken': csrfmiddlewaretoken,
}
response = requests.post(login_url, cookies=cookies, data=data, allow_redirects=False)
if 'sessionid' not in response.cookies:
# ログインに失敗した場合
return False
# sessionidがセットされたCookieでcookiesを更新
cookies = response.cookies
return True
def get_admin():
# /admin/のHTMLを取得
response = requests.get(admin_url, cookies=cookies, allow_redirects=False)
if response.status_code != 200:
# HTMLの取得に失敗した場合
return None
return response.text
def main():
if not login('YamadaHanako', 'yh123456'):
print('ログインに失敗しました')
return False
html = get_admin()
if html is None:
print('ページの表示に失敗しました')
return False
print(html)
main()
上記スクリプトの解説を簡単に行っておきます。
まず、下記ページでも解説しているとおり、requests
モジュールを利用した場合、requests.get
の実行により GET
メソッドのリクエストを、requests.post
の実行により POST
メソッドのリクエストをそれぞれ送信することが可能です。
また、requests.get
や requests.post
には引数 cookies
を指定することが可能で、これにより送信するリクエストのヘッダーフィールド Cookie を指定することが可能です。
さらに、これらの関数では返却値としてレスポンスのデータを取得することが可能で、このデータの cookies
データ属性にはサーバー側から提供される Cookie を得ることができます。前述の通り、ログインフォームを表示する際には Cookie として csrftoken
がサーバーから送られてきます。さらに、ログインを行う際には、この csrftoken
を Cookie にセットした状態でログインに必要なデータの送信を行う必要があります。
そのため、下記のように login
関数の前半では、まず login_url
(ログインフォーム表示ページの URL) への GET
メソッドのリクエストを送信し、そのレスポンスによって得られる Cookie (response.cookies
) をグローバル変数 cookies
に参照させるようにしています。そしてその後、login_url
への POST
メソッドのリクエストを送信する際に引数へ cookies=cookies
を指定するようにしています。これにより、サーバーから送信されてきた Cookie がヘッダーフィールドにセットされた POST
メソッドのリクエストを送信することができます。
# /admin/login/のHTMLをGETリクエストで取得
response = requests.get(login_url, allow_redirects=False)
〜略〜
# csrftokenがセットされたCookieでcookiesを更新
cookies = response.cookies
〜略〜
response = requests.post(login_url, cookies=cookies, data=data, allow_redirects=False)
さらに、POST
メソッドのリクエストのボディには、ログインするために必要なデータ(具体的には username
と password
)だけでなく csrfmiddlewaretoken
も必要となります。この csrfmiddlewaretoken
は login_url
に対する GET
メソッドのリクエストに対するレスポンスのボディ(HTML)に埋め込まれていますので、それを取得してリクエストのボディにセットする必要があります。この辺りを行なっているのが下記となります。
# /admin/login/のHTMLをGETリクエストで取得
response = requests.get(login_url, allow_redirects=False)
〜略〜
# HTMLに埋め込まれたcsrfmiddlewaretokenを取得
pattern = 'name="csrfmiddlewaretoken" value="(.+)"'
csrfmiddlewaretoken = re.search(pattern, response.text).group(1)
# usernameとpasswordに加えてcsrfmiddlewaretokenをPOSTリクエストで送信
data = {
'username': username,
'password': password,
'csrfmiddlewaretoken': csrfmiddlewaretoken,
}
response = requests.post(login_url, cookies=cookies, data=data, allow_redirects=False)
そして、ログインに成功した場合、上記で実行している requests.post
からの返却値 response
の cookies
データ属性には csrftoken
だけでなく sessionid
がセットされていることになります。この sessionid
は「リクエストを送信してきたクライアントがログイン中であることを示すデータ」となるため、この sessionid
を次回からのリクエストの送信時にヘッダーフィールドの Cookie に指定できるよう、下記で cookies
を管理するグローバル変数である cookies
を response.cookies
で更新するようにしています。
response = requests.post(login_url, cookies=cookies, data=data, allow_redirects=False)
if 'sessionid' not in response.cookies:
# ログインに失敗した場合
return False
# sessionidがセットされたCookieでcookiesを更新
cookies = response.cookies
以降、リクエストを送信する際には上記で更新されたグローバル変数 cookies
を引数に指定して関数を実行することで、自身がログイン中であることをウェブアプリに対して伝えることができるようになり、非ログイン状態ではアクセスが拒否されるような URL へのリクエストも成功するようになります。
逆に、引数に cookies
を指定しなかったり、指定した cookies
に sessionid
がセットされていない場合は、リクエスト元のクライアントが非ログイン状態と判断されることになるので注意してください。
また、上記のようにヘッダーフィールドの Cookies に csrftoken
がセットされていない、ボディに csrfmiddlewaretoken
フィールドが存在しない、username
や password
が間違っているような場合は requests.post
を実行した際にログインに失敗することになります。そして、この場合は requests.post
からの返却値 response
の cookies
データ属性には sessionid
がセットされないことになります。したがって、ログインに成功したか失敗したかは response.cookies
に sessionid
フィールドが存在するかどうかで判断することが可能です。
login
関数の引数に指定する username
や password
を変更してみたり、ボディから csrfmiddlewaretoken
を削除したりしてみればログインに失敗する様子を確認することもできます。
また、ここまで説明を避けてきましたが、requests
モジュールの関数の引数に指定している allow_redirects=False
は自動的なリダイレクトを禁止するための設定となります。この引数を指定しないとログイン直後やログイン失敗時に他の URL にリダイレクトするためのリクエストが requests.post
や requests.get
から自動的に送信されるようになって処理の流れが分かりにくくなるため(つまり1回の関数実行で複数のリクエストが送信される)、allow_redirects=False
を指定するようにしています。
さて、前述の通り、login
関数の最後の cookies = response.cookies
によって、グローバル変数 cookies
の参照する Cookie には sessionid
がセットされています。したがって、この cookies
を引数に指定してリクエストを送信すれば、非ログイン状態でアクセス不可な URL にもアクセス可能となります。
この非ログイン状態でアクセス不可な URL が /admin/
となります。そして、この URL への GET
メソッドのリクエストを送信しているのが get_admin
関数となります。
この関数では、requests.get
を実行する際に引数 cookies=cookies
を指定しており、ここで指定する cookies
には sessionid
がセットされています。したがって、ログイン状態でないとアクセスが拒否される admin_url
(/admin/
) に対してもアクセスに成功し、この場合は関数の返却値の response
の status_code
が 200
となります。
# /admin/のHTMLを取得
response = requests.get(admin_url, cookies=cookies, allow_redirects=False)
if response.status_code != 200:
# HTMLの取得に失敗した場合
return None
cookies
をセットしていない or cookies
に sessionid
がセットされていない場合はクライアントが非ログイン状態であると判断されて強制的にログインページにリダイレクトされることになります。そして、この場合の status_code
は 302
となります。この辺りもソースコードを変更してみれば実際に動作を確認していただけると思いますし、この結果から、sessionid
がログイン状態であることを示す証明書のようなものになっていることも理解していただけると思います。
スポンサーリンク
ユーザーの追加を行う
もう1つの例として、管理画面からユーザーの追加を行う操作を requests
モジュールで実現する例を示していきたいと思います。
管理画面にログインした状態のウェブブラウザであれば、下記の URL を開けばユーザー追加フォームが表示されることになります。
http://localhost:8000/admin/auth/user/add/
ユーザー追加フォームは下図のような画面となります。
このフォームの Username
・Password
・Password confirmation
それぞれにユーザー名・パスワード・パスワード(確認用)を入力してフォーム右下にある SAVE
ボタンをクリックすれば、ユーザーの追加を行うことができるようになっています。
また、ユーザー追加後に画面左側のメニューから Users
をクリックすれば、
ユーザー一覧が表示されて先ほど追加したユーザーが存在することも確認できます。ちなみに、下図では二人のユーザーが表示されており、一方は ユーザーの作成 で追加したユーザーです。ユーザーの作成 で追加したユーザーは管理者権限を持っており管理画面へのログインを行うことができます。
requests
モジュールからのユーザー追加
では、先ほど示したこのユーザー追加の一連の流れを requests
モジュールで実現していきたいと思います。
実行する処理の流れを整理しておくと、まずユーザー追加フォームの URL に対して GET
リクエストを送信して HTML を取得し、さらに追加したいユーザー名やパスワード等をセットしたボディを POST
リクエストで送信します。上手く通信が行われればユーザーの追加を行うことができます。ちなみに、最初に GET
リクエストを送信して HTML を取得するのは、その HTML に埋め込まれた csrfmiddlewaretoken
を取得するためになります。
さらに、ユーザー一覧リストのページの URL に対して GET
リクエストを送信して HTML を取得し、その HTML の中に追加したユーザー名の文字列が存在するかどうかを確認します。存在すれば、本当にユーザーが追加されていたことが確認できます。
これらの操作は全て Django のアプリの管理画面で行われるものであり、この管理画面はクライアントがログイン状態でないと使用できません。したがって、クライアントがログイン状態であることをアプリに示すために、Cookie には sessionid
が必要となります。今回実装するスクリプトにおいて、この点がポイントの1つになるかと思います。
あとは、ユーザー追加フォームからデータを送信する際にはログインフォームからデータの送信時と同様に csrfmiddlewaretoken
も一緒に送信する必要があります。そのため、一度ユーザー追加フォームのページの URL に対して GET
メソッドのリクエストを送信して HTML を取得し、その HTML に埋め込まれた csrfmiddlewaretoken
を取得して他のデータと一緒に送信を行う必要があります。
この辺りの送信すべきデータに関しては、ログイン操作時の通信データの確認 の時のように実際にウェブブラウザで操作を行なってみることで確認することが可能です。
ということで、上記の内容を踏まえて作成した requests
モジュールからユーザーの追加を行うスクリプトの例が下記となります。
import requests
import re
login_url = 'http://localhost:8000/admin/login/'
add_user_url = 'http://localhost:8000/admin/auth/user/add/'
list_user_url = 'http://localhost:8000/admin/auth/user/?all='
cookies = None
def login(username, password):
global cookies
# /admin/login/のHTMLをGETリクエストで取得
response = requests.get(login_url, allow_redirects=False)
if response.status_code != 200:
# HTMLの取得に失敗した場合
return False
# csrftokenがセットされたCookieでcookiesを更新
cookies = response.cookies
# HTMLに埋め込まれたcsrfmiddlewaretokenを取得
pattern = 'name="csrfmiddlewaretoken" value="(.+)"'
csrfmiddlewaretoken = re.search(pattern, response.text).group(1)
# usernameとpasswordに加えてcsrfmiddlewaretokenをPOSTリクエストで送信
data = {
'username': username,
'password': password,
'csrfmiddlewaretoken': csrfmiddlewaretoken,
'next': '/admin/'
}
response = requests.post(login_url, cookies=cookies, data=data, allow_redirects=False)
if 'sessionid' not in response.cookies:
# ログインに失敗した場合
return False
# sessionidがセットされたCookieでcookiesを更新
cookies = response.cookies
return True
def add_user(username, password):
# sessionidがセットされたCookieを指定してリクエストを送信
response = requests.get(add_user_url, cookies=cookies)
if response.status_code != 200:
return False
# HTMLに埋め込まれたcsrfmiddlewaretokenを取得
pattern = 'name="csrfmiddlewaretoken" value="(.+)"'
csrfmiddlewaretoken = re.search(pattern, response.text).group(1)
# 各種フィールドの値とcsrfmiddlewaretokeを送信
data = {
'username': username,
'password1': password,
'password2': password,
'csrfmiddlewaretoken': csrfmiddlewaretoken,
}
response = requests.post(add_user_url, cookies=cookies, data=data, allow_redirects=False)
if response.status_code != 302:
return False
return True
def check_user(username):
# sessionidがセットされたCookieを指定してリクエストを送信
response = requests.get(list_user_url, cookies=cookies)
if response.status_code != 200:
return False
# 受信したHTMLに追加したユーザーの名前が存在するかどうかを確認
if response.text.find(username) == -1:
return False
return True
def main():
if not login('YamadaHanako', 'yh123456'):
print('ログインに失敗しました')
return False
username = 'YamadaJiro'
password = 'jiro1234'
if not add_user(username, password):
print('ユーザーの作成に失敗しました')
return False
if check_user(username):
print('ユーザーの作成に成功しています')
else:
print ('ユーザーが見つかりません')
main()
少しスクリプトが長いですが、login
関数に関しては requests モジュールからのログイン操作 で示したものと全く同じとなります。引数に ユーザーの作成 で作成したユーザーの username
と password
を指定して login
関数を実行してログインを行い、ログイン中であることを示す sessionid
を含む Cookie を取得してグローバル変数 cookies
にセットしています。
したがって、このグローバル変数 cookies
を引数に指定して requests
モジュールの関数を実行することで、ログイン中のクライアントからのリクエストであることをアプリ側に示すことができます。そして、これによって非ログイン状態で行えない操作も実施できるようになります。
なので、あとはユーザー追加フォームの URL に対して get
関数で GET
メソッドのリクエストを送信して HTML を取得し、その HTML から取得した csrfmiddlewaretoken
を username
・password1
・password2
と一緒に post
関数の POST
メソッドのリクエストで送信してやればユーザーの追加を行うことができることになります。
これを行なっているのが上記スクリプトにおける add_user
関数になります。この関数の第1引数に追加したいユーザーのユーザー名、第2引数に追加したいユーザーのパスワードを指定して実行すれば、第1引数に指定したユーザー名が username
、第2引数に指定したパスワードが password1
と password2
にセットされ、さらに HTML から取得したトークンが csrfmiddlewaretoken
にセットされた状態のデータが送信されることになります。
上記のスクリプトでは第1引数に 'YamadaJiro'
、第2引数に 'jiro1234'
を指定して add_user
関数を実行しているため、これらをユーザー名とパスワードとするユーザーが追加されることになります。
この add_user
関数の実行によってユーザーの追加は行われるのですが、ユーザーの追加が本当に行われたかが分かりにくいので、最後に check_user
関数を実行することで引数に指定したユーザー名のユーザーが追加されていることを確認するようにしています。
check_user
関数では、まずユーザーの一覧リストを表示するページの URL に対して GET
メソッドのリクエストを送信して HTML を取得しています。このユーザーの一覧リストを表示するページに関してもログイン中でないとアクセスできないようになっているため、この際も get
関数の引数に cookies=cookies
を指定しておく必要があります。続いて、その HTML に対して引数 username
に指定された文字列の探索を行うようにしています。。
ここで、add_user
で追加したユーザーと同じユーザー名を引数に指定してやれば、add_user
で追加したユーザーのユーザー名が一覧リストを表示するページ内に存在するかどうかを確認することができます。そして、存在すれば、add_user
でのユーザーの追加に成功していることが確認できるというわけです。
正直言うと、この check_user
関数での確認方法は甘いです。この check_user
関数では、ユーザー一覧リスト内に存在しなくてもページ内に追加したユーザー名と一致する文字列が存在すればユーザーの追加に成功したと判断されてしまうことになります。この問題を解決するためには、ユーザー一覧リストにおけるユーザー名のフィールド(カラム)に対してのみ文字列の探索をを行うようにするような処理が必要になります。
ですが、まぁ今回は requests
モジュールの使い方に焦点を当てた解説となっており、HTML を取得して解析すればいろんなことが実現できることさえ理解していただければ良いと考えているので、そこまで探索方法に関してはこだわらずに簡単な例のみを示すようにしています。
ということで、requests
モジュールからウェブアプリの操作を行う例の紹介は以上となります。今回はログインとユーザーの追加を行う例のみを示しましたが、同様にウェブブラウザから送信されるリクエストと同様のデータを requests
モジュールから送信するようにしてやればユーザーの削除やログアウトなども requests
モジュールから行うことができるようになります。また、一度スクリプトを実装してやれば、そのスクリプトを実行するだけで同様の操作を再現することができるようになり、定期的なウェブアプリの動作確認なども自動化することも実現可能です。
今回は Django のウェブアプリに特化した説明となりましたが、ウェブアプリの操作を requests
モジュールから行う際の勘所は掴んでいただけたのではないかと思います。他のウェブアプリの場合もウェブブラウザから送信されるデータを真似て requests
モジュールから送信するようにしてやれば requests
モジュールから操作できるようになるものも多いと思いますので、是非いろんなウェブアプリの requests
からの操作に挑戦してみてください!
まとめ
このページでは、requests
モジュールからの Django で開発されるウェブアプリの操作例の紹介を行いました!
ウェブアプリは受信した HTTP リクエストに応じた処理を行うアプリですので、ウェブブラウザからだけでなく、HTTP リクエストを送信可能な requests
モジュールからも操作することができます。考え方としては単純で、ウェブブラウザからの操作時に送信される HTTP リクエストと同じデータを requests
モジュールを送信してやるだけです。これでウェブブラウザから行う操作と同様の操作を requests
モジュールから実現することができます。
今回は Django のウェブアプリの操作例のみを示しましたが、同様の考え方で様々なウェブアプリを requests
モジュールから操作可能で操作や動作確認の自動化なども行うことができます。是非、いろんなウェブアプリの操作の requests
モジュールでの自動化に挑戦してみてください!