【Python】requestsモジュールでPOSTメソッドのリクエストを送信(ウェブアプリの操作)

requestsモジュールでのウェブアプリの操作の仕方の解説ページアイキャッチ

このページにはプロモーションが含まれています

このページでは、requests モジュールの使い方の応用編として、Django で開発されるウェブアプリを利用して POST メソッドのリクエスト送信の実践を行っていきたいと思います!

requests モジュール自体については下記ページで解説していますので、requests モジュールを使ったことのない方は下記ページを事前に読んでおくことをオススメします。

requestsモジュールの解説ページアイキャッチ【Python】reqeustsモジュールについて解説

上記ページでも requests モジュールの使用例を示しているのですが、基本的には GET メソッドのリクエストの送信例を示すページとなっています。このページでは、POST メソッドのリクエストの送信の例を示していきます。

また、ページの冒頭でも触れたように、今回は Django を利用し、Django が提供する管理画面に対してログインやユーザー作成等を requests モジュールから行う例を示していきます。もちろん、ログイン等のウェブアプリの操作はユーザーが手動で実施することも可能です、ですが、requests モジュールから POST メソッドを送信してウェブアプリの操作が行えるようになれば、そのスクリプトを定期的に実行するようにするだけでウェブアプリの動作確認等を自動的に・定期的に実施可能となるメリットが得られます。

requestsモジュールからウェブアプリの操作を行う例

ということで、このページでは、まず requests からのウェブアプリ操作を実現する考え方について説明したのちに、Django の導入手順を簡単に説明し、その後 Django を利用してウェブアプリ(といっても管理画面のみを持つアプリ)を作成する手順を説明していきたいと思います。そして、その後に、実際に作成したウェブアプリへの操作を requests モジュールからの POST メソッドの送信によって実現する例を示していきたいと思います。

ちょっと難易度は高めですし、Django の管理画面ならではのリクエストを送信するための実装なども必要になるのですが、それでも読み進めていただければ requests モジュールから POST メソッドのリクエストの送信の仕方や、送信するときの注意点などを理解していただけると思います。

requests からのウェブアプリの操作

では、まずは requests からのウェブアプリの操作を実現する考え方について説明していきます。

最初に断っておくと、下記ページでも説明しているように、あくまでも requests は HTTP リクエストを送信し、その HTTP レスポンスを受信するモジュールです。

requestsモジュールの解説ページアイキャッチ【Python】reqeustsモジュールについて解説

それに対し、ウェブアプリは通常ウェブブラウザから操作が行われるアプリとなります。例えば X (旧 Twitter) であればウェブブラウザから操作が可能であり、ウェブアプリの1つであると考えることができます。

MEMO

多くのウェブアプリの場合、iOS 用・Android 用等の専用クライアントアプリを利用して操作することも可能ですが、今回はウェブブラウザからの操作に焦点を当てて説明していきます

このように、ウェブアプリがウェブブラウザから操作可能なのは、ウェブブラウザがユーザーの操作に応じた HTTP リクエストをウェブアプリに対して送信するようになっているからになります。そして、その HTTP リクエストを受け取ったウェブアプリがそのリクエストに応じた処理を実行します。

例えばユーザーによってウェブブラウザからツイートが行われたのであれば、ツイートを新規登録するためのリクエストがウェブブラウザからウェブアプリに送信され、それを受け取ったウェブアプリが送信されてきたツイートを新規登録する感じになります。

ウェブブラウザから送信されたHTTPリクエストに応じた処理をウェブアプリが実行する様子

ここで重要なのは、ウェブアプリはウェブブラウザからの操作に応じた処理を行うのではなく受信した HTTP リクエストに応じた処理を行うという点になります。つまり、ウェブブラウザからでなく、あなた自身が実装したスクリプトから HTTP リクエストを送信したとしても、そのリクエストに応じた処理をウェブアプリが行なってくれます。

MEMO

リクエストのヘッダーにはリクエスト送信元のブラウザの情報などが含まれており、その情報によってリクエストを拒否するようなサーバーやアプリもあります

この場合は、スクリプトから実行するとリクエストが拒否される場合があります

そして、その HTTP リクエストを送信するモジュールの1つが requests になります。つまり、Python スクリプトから requests を利用してウェブブラウザ操作時に送信される HTTP リクエストと同じものを送信してやれば、ウェブブラウザからの操作と同等の操作を Python スクリプトから実現することが可能となります。

Pythonスクリプトから送信されたHTTPリクエストに応じた処理をウェブアプリが実行する様子

ただし、ウェブアプリはどんなリクエストでも受け付けるというわけではありません。そして、ウェブアプリが受け付け可能な HTTP リクエストはウェブアプリによって異なります。特に POST メソッドの場合は、送信するリクエストのボディが「ウェブアプリの期待するもの」である必要がある点に注意が必要です。

ウェブブラウザで操作する場合、ボタンのクリック等を行なった際には基本的にウェブアプリが受け付け可能な HTTP リクエストが送信されることになります。こういったボタンのクリック時に送信される HTTP リクエストはウェブアプリによって提供される HTML 等に基づいて生成されます。そして、この HTML 等はウェブアプリ側から提供されるものであり、ウェブアプリが受け付け可能なリクエストが送信されるように作られています。そのため、ウェブブラウザでウェブアプリの操作を行う場合はユーザーが意識しなくてもウェブアプリが受け付け可能なリクエストが自動的に送信されるようになっています。

ウェブブラウザが送信するHTTPリクエスト

その一方で requests モジュールの場合、HTTP リクエストの送信自体は関数を実行するだけで実現できますが、どんなリクエストのデータを送信するかは Python スクリプトの実装によって決まります。具体的には実行する関数や引数によって決まります。したがって、requests モジュールを利用する場合はウェブアプリが受付可能な HTTP リクエストが送信されるようにスクリプトを実装する必要があります。デタラメな実装で HTTP リクエストを送信してもウェブアプリからエラーが返却されることになって操作が行えません。

では、具体的にどうやって実装すれば良いかというと、その実装の仕方の1つは「ウェブブラウザからのウェブアプリ操作時に送信される HTTP リクエストを真似る」になります。前述の通り、ウェブアプリが操作可能なのはウェブブラウザから HTTP リクエストが送信されるからで、さらに、その HTTP リクエストはウェブアプリが受け付け可能な HTTP リクエストになります。

したがって、例えばウェブブラウザからの操作時にウェブブラウザから送信される HTTP リクエストのデータの中身を確認し、そのデータと同等のものが送信できるように Python スクリプトを実装すれば、ウェブブラウザで操作した時と同様の HTTP リクエストがウェブアプリに送信できることになります。そして、この場合はウェブブラウザからの操作時と同等の操作を行うことができます。

そのため、例えばウェブアプリへのログインを requests モジュールから行うためには、まずウェブブラウザからウェブアプリへのログインを実施し、その際にウェブブラウザから送信されるリクエストのデータの確認を行います。そして、そのデータと同等のリクエストが requests モジュールから送信されるように Python スクリプトの実装を行う、といった感じの流れになります。

ウェブブラウザから送信されるHTTPリクエストと同じデータをrequestsモジュールから送信する様子

面倒ですが、一度 Python スクリプトの実装を行なっておけば、あとはそのスクリプトを実行するだけで同様の操作が行えるようになります。ですので、定期的に同様の操作を行なったり、自動的に何回も繰り返し行なったりすることができるようになります。

また、ウェブブラウザから送信される通信データは下記ページで紹介している Wireshark 等のツールを利用することで確認可能です。ただ、通信データが暗号化されている可能性があるので、その点は注意が必要となります。今回用意するウェブアプリでは通信データが暗号化されていないので通信データは簡単に確認可能です。

WindowsでのWiresharkの使い方やインストール方法の解説ページアイキャッチWiresharkのインストール方法と使い方【Windows編】 WiresharkのMacでのインストール方法の説明ページアイキャッチ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 というフォルダが作成されるはずです。

MEMO

django-admin が上手く利用できない場合は下記ページを参考にしてください

django-adminが実行できない場合の対処法の解説ページアイキャッチ【Python/Django】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 の解説やインストール手順の説明は下記ページで行なっています。

WindowsでのWiresharkの使い方やインストール方法の解説ページアイキャッチWiresharkのインストール方法と使い方【Windows編】 WiresharkのMacでのインストール方法の説明ページアイキャッチWiresharkのインストール方法とChmodBPFでの権限設定【Mac編】

Wireshark インストール後に Wireshark を起動して Loopback; lo0Adapter for loopback traffic capture 等の loopback という単語が含まれているインターフェースを選択すれば、自分自身の PC に対して送信される通信データが Wireshark でキャプチャされるようになります。先ほど作成したウェブアプリは、あなたの PC 上で動作していますので、このようにインターフェースを選択することで、あなたの PC 上で動作しているウェブブラウザと、あなたの PC 上で動作しているウェブアプリとの間でやりとりされる通信データがキャプチャ可能となります。

Wiresharkでウェブブラウザとウェブアプリ間の通信データをキャプチャする様子

さらに、Wireshark のウィンドウ上部にある入力バーに http と入力してエンターキーを押せば、通信プロトコルが HTTP である通信データのみが Wireshark のウィンドウ上側のリストに表示されるようになります。これにより、ウェブブラウザ操作時にウェブブラウザとウェブアプリとの間でやりとりされる HTTP リクエストや HTTP レスポンスが WIreshark で観察しやすくなります。

Wireshark上にHTTPの通信データのみを表示する様子

ログイン操作を行う

では、先ほど作成したウェブアプリの管理画面にウェブブラウザでログイン操作を行い、その際に送信されるリクエストのデータを確認していきたいと思います。

その後、requests モジュールで同様のリクエストのデータを送信して requests モジュールからの管理画面へのログインを実現していきます。

ログイン操作時の通信データの確認

まずは、ウェブブラウザを起動し、下記 URL を開いてみましょう。これは先ほど作成したウェブアプリにおける管理画面へのログインページの URL となります。

http://localhost:8000/admin/login/

URL を開けば下の図のようなログインフォームが表示されると思います。

ログインフォームが表示される様子

このログインフォームの Username Password の入力欄それぞれに ユーザーの作成 で作成したユーザーのユーザー名(YamadaHanako)とパスワード(yh123456)を入力して Log in ボタンをクリックすればログインが実行されることになります。そして、この時に送信されるデータを requests モジュールから送信してやればログインを行うことも可能となります。

ということで、まずはログイン操作を手動で実施し、その時の通信データの内容を確認したいと思います。Wireshark を動作させた状態でログイン操作を実施すれば、ウェブブラウザで表示中のページが /admin/login/ から /admin/ に遷移して管理画面が表示されることになります。そして、Wireshark の画面では下の図のように6つの通信データがキャプチャされたことが確認できます。

ログイン操作時に送受信される通信データ

この6つの通信データは、上から順に次のような意味を持つ通信データとなります。

  1. ウェブブラウザからの /admin/login/ への GET メソッドのリクエスト
  2. ウェブブラウザへの /admin/login/ の表示用データのレスポンス
  3. ウェブブラウザからの /admin/login/ への POST メソッドのリクエスト(ログインのリクエスト)
  4. ウェブブラウザへのログイン許可および /admin/ へのリダイレクトレスポンス
  5. ウェブブラウザからの /admin/ への GET メソッドのリクエスト
  6. ウェブブラウザへの /admin/ の表示用データのレスポンス

1. と 2. によってログインフォームが表示され、3. と 4. によってログインが行われ、5. と 6. によってログイン状態でないと表示できない管理画面が表示されることになります。

ウェブブラウザからのログイン操作によって送信されるリクエストは 3. のものになります。したがって、この 3. で送信されるリクエストを requests モジュールから送信してやれば、ログインが実施されて 4. のレスポンスが得られると考えられます。

ということで、3. で送信されるリクエストのデータの詳細を確認してみましょう!

このデータで注目すべき点は3つあります。

1つ目は、ログインを行うためのユーザー情報として "username"="YamadaHanako""password"="yh123456" がデータに含まれているという点になります。このデータはボディに存在しています。これらはログインフォームに入力したものなので、これらのデータが送信されているのは納得だと思います。

usernameとpasswordが送信されている様子

2つ目は、ボディに "csrfmiddlewaretoken"="略" というデータも存在しているという点になります。これは何のデータなのでしょうか?ちなみに、"next"="/admin/" というデータも存在しますが、これはログイン後に表示するページのパス(URL)を示すものなので、ここでは特に注目はしません。

csrfmiddlewaretokenが送信されている様子

3つ目は、ヘッダーフィールドの Cookiecsrftoken="略" が存在している点になります。

csrftokenが送信されている様子

つまり、ログインフォームからログインを行う際には usernamepassword だけでなく、csrfmiddlewaretoken も含めたボディのリクエストがウェブブラウザから送信されています。そして、ヘッダーフィールドの Cookie にも csrftoken がセットされた状態でリクエストが送信されています。

ログインフォームだけ見ると、ログインに必要な情報は usernamepassword のみに思えますが、実はボディに csrfmiddlewaretoken が存在しなければログインに失敗することになります。また、ヘッダーフィールドの Cookie にも csrftoken が存在しない場合もログインに失敗します。

つまり、Django のアプリの管理画面にログインするためには、ボディに下記の3つのフィールドが必要で、さらに Cookiecsrftoken もセットしておく必要があります。したがって、requests モジュールからログインを行う際にも、これらの情報を含めたデータをリクエストとして送信する必要があることになります。

  • username
  • password
  • csrfmiddlewaretoken

ちなみに、csrfmiddlewaretokencsrftoken が必要なのはウェブアプリ側にセキュリティ対策が講じられているからになります。Django のアプリでは、これらの情報がリクエストに存在しない場合にフォームからのデータ送信を受け付けないようになっていますが、別のアプリではもっと他のセキュリティ対策が講じられている可能性もあります。なので、どんなアプリでも上記のような情報が必要になるというわけではありません。重要なのは、目的のアプリに応じたリクエストの送信を行うことになります。

で、usernamepassword フィールドの値としては ユーザーの作成 で作成したユーザーのユーザー名(YamadaHanako)とパスワード(yh123456)を設定してやれば良いです。

じゃあ csrfmiddlewaretokencsrftoken の値は何にすれば良いかというと、実はこれらの値はログインフォームを表示する際にウェブアプリからのレスポンスとして受け取っています。

ここで、2. の通信データに注目すると、下の図のように csrfmiddlewaretoken の値がボディとなる HTML の中に埋め込まれています。

csrfmiddlewaretokenがログインフォーム表示用HTMLに含まれている様子

また、csrftoken も Cookie にセットされた状態で受け取っていることが確認できます。

csrftokenがログインフォーム表示用HTMLのレスポンスのヘッダーに含まれている様子

なので、ログインフォームの表示のリクエストに対するレスポンスを受け取ってこれらの値を取得し、これらの値を含めてリクエストを送信してやれば、ウェブアプリからログイン操作した時と同様の通信データが送信できることになります。したがって、このようなデータを送信してやることで、ウェブブラウザからではなく requests モジュールからのログインが実現できることになります。

requestsモジュールからウェブブラウザから送信されるHTTPリクエストと同じHTTPリクエストを送信する様子

このログイン実施後に重要となるのが、ログイン中であることを示すデータになります。ウェブブラウザの場合、そのデータをログインのリクエストに対するレスポンスで受け取り、ログイン後に送信されるリクエストにはそのデータが自動的に付加されるようになっています。そのため、ログインしていないとアクセス不可なページであっても、一度ウェブブラウザからログインを行なっておけば、以降はログインなしでウェブブラウザから表示可能となります。

ログイン状態であることを示すデータが送信される様子

それに対し、requests モジュールの場合は、requests モジュールの利用者(開発者)が明示的にログイン中であることを示すデータをリクエストにセットしてリクエストを送信するように実装する必要があります。

そして、このログイン中であることを示すデータは、Django の管理画面の場合はリクエストのヘッダーフィールドにおける Cookiesessionid になります。この sessionid はログインのリクエストに対するレスポンスのヘッダーフィールドの Set-Cookie にセットされています。

sessionidがログインのリクエストに対するレスポンスで指定される様子

なので、この sessionid を取得し、それをヘッダーフィールドの Cookie にセットしたリクエストを送信するようにすれば、ログイン中でないとアクセス不可なページも requests モジュールからアクセス可能となります。

requestsモジュールからsessionidを付加したリクエストを送信する様子

逆に、この sessionidCookie にセットせずにリクエストを送信した場合、ウェブアプリには非ログイン中のユーザーであるとみなされることになるので注意してください。

長々と説明しましたが、内容をまとめると、先ほど行なったウェブブラウザでの操作を requests モジュールから行うようにするためには、下記で示した処理を Python スクリプトから実装してやれば良いことになります。

  1. /admin/login/ に対するリクエストを requests.get で送信
  2. requests.get の返却値からレスポンスを取得
    • csrfmiddlewaretokenCookie を取得
  3. Cookie をセットした状態で、/admin/login/ に対するリクエストに下記のフィールドを持つボディをセットして requests.post で送信
      • Username=ユーザー名
      • Password=パスワード
      • csrfmiddlewaretoken=2. で取得した値
  4. requests.post の返却値からレスポンスを取得
    • sessionid を含む Cookie を取得
  5. Cookie をセットした状態で /admin/ に対するリクエストを requests.get で送信
  6. requests.get の返却値から /admin/ の HTML が取得されていることを確認

前述の通り、/admin/ はログイン状態でないとページの表示(HTML の取得)ができません。そのため、6. で /admin/ の HTML が取得できればログインに成功したと考えられます。

requests モジュールからのログイン操作

では、ここまで説明した内容を踏まえて requests モジュールからのログイン操作を実際に行っていきたいと思います。

先ほど示した流れに基づいた処理をスクリプトとして実装すれば良いので、結論としては下記のようなスクリプトを実装してやれば良いことになります。

login.py
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モジュールの解説ページアイキャッチ【Python】reqeustsモジュールについて解説

また、requests.getrequests.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 メソッドのリクエストを送信することができます。

Cookieへのcsrftokenの設定
# /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 メソッドのリクエストのボディには、ログインするために必要なデータ(具体的には usernamepassword)だけでなく csrfmiddlewaretoken も必要となります。この csrfmiddlewaretokenlogin_url に対する GET メソッドのリクエストに対するレスポンスのボディ(HTML)に埋め込まれていますので、それを取得してリクエストのボディにセットする必要があります。この辺りを行なっているのが下記となります。

ボディへのcsrfmiddlewaretokenの設定
# /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 からの返却値 responsecookies データ属性には csrftoken だけでなく sessionid がセットされていることになります。この sessionid は「リクエストを送信してきたクライアントがログイン中であることを示すデータ」となるため、この sessionid を次回からのリクエストの送信時にヘッダーフィールドの Cookie に指定できるよう、下記で cookies を管理するグローバル変数である cookies を response.cookies で更新するようにしています。

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 フィールドが存在しない、usernamepassword が間違っているような場合は requests.post を実行した際にログインに失敗することになります。そして、この場合は requests.post からの返却値 responsecookies データ属性には sessionid がセットされないことになります。したがって、ログインに成功したか失敗したかは response.cookies に  sessionid フィールドが存在するかどうかで判断することが可能です。

login 関数の引数に指定する usernamepassword を変更してみたり、ボディから csrfmiddlewaretoken を削除したりしてみればログインに失敗する様子を確認することもできます。

また、ここまで説明を避けてきましたが、requests モジュールの関数の引数に指定している allow_redirects=False は自動的なリダイレクトを禁止するための設定となります。この引数を指定しないとログイン直後やログイン失敗時に他の URL にリダイレクトするためのリクエストが requests.postrequests.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/) に対してもアクセスに成功し、この場合は関数の返却値の responsestatus_code200 となります。

ログイン状態でのアクセス
# /admin/のHTMLを取得
response = requests.get(admin_url, cookies=cookies, allow_redirects=False)
if response.status_code != 200:
    # HTMLの取得に失敗した場合
    return None

cookies をセットしていない or cookiessessionid がセットされていない場合はクライアントが非ログイン状態であると判断されて強制的にログインページにリダイレクトされることになります。そして、この場合の status_code302 となります。この辺りもソースコードを変更してみれば実際に動作を確認していただけると思いますし、この結果から、sessionid がログイン状態であることを示す証明書のようなものになっていることも理解していただけると思います。

スポンサーリンク

ユーザーの追加を行う

もう1つの例として、管理画面からユーザーの追加を行う操作を requests モジュールで実現する例を示していきたいと思います。

管理画面にログインした状態のウェブブラウザであれば、下記の URL を開けばユーザー追加フォームが表示されることになります。

http://localhost:8000/admin/auth/user/add/

ユーザー追加フォームは下図のような画面となります。

ユーザー追加フォーム

このフォームの UsernamePasswordPassword 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 モジュールからのログイン操作 で示したものと全く同じとなります。引数に ユーザーの作成 で作成したユーザーの usernamepassword を指定して login 関数を実行してログインを行い、ログイン中であることを示す sessionid を含む Cookie を取得してグローバル変数 cookies にセットしています。

したがって、このグローバル変数 cookies を引数に指定して requests モジュールの関数を実行することで、ログイン中のクライアントからのリクエストであることをアプリ側に示すことができます。そして、これによって非ログイン状態で行えない操作も実施できるようになります。

なので、あとはユーザー追加フォームの URL に対して get 関数で GET メソッドのリクエストを送信して HTML を取得し、その HTML から取得した csrfmiddlewaretokenusernamepassword1password2 と一緒に post 関数の POST メソッドのリクエストで送信してやればユーザーの追加を行うことができることになります。

これを行なっているのが上記スクリプトにおける add_user 関数になります。この関数の第1引数に追加したいユーザーのユーザー名、第2引数に追加したいユーザーのパスワードを指定して実行すれば、第1引数に指定したユーザー名が username、第2引数に指定したパスワードが password1password2 にセットされ、さらに 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 モジュールでの自動化に挑戦してみてください!

同じカテゴリのページ一覧を表示