【Django入門18】ウェブアプリのHTTPリクエストでの操作

ウェブブラウザ以外からのウェブアプリの操作方法の解説ページアイキャッチ

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

今回は、少し解説内容の趣向を変え、ウェブアプリの開発ではなく、ウェブアプリの操作についての説明を行っていきます。

ここまでの Django 入門 においては、ウェブアプリを「ウェブブラウザ」から操作を行うことを前提とした解説を行ってきました。今回は、ウェブブラウザを利用しないウェブアプリの操作について解説していきます。

この操作方法を理解しておけば、自身が開発したウェブアプリを、例えば X や Instagram などのように、ウェブブラウザ以外の iOS アプリ、さらには Android アプリからも操作するようなことができるようになります。

iOSアプリからウェブアプリを操作する様子

ウェブアプリの操作とは

まずは、ウェブアプリの操作の仕組みについて解説していきます。

ウェブアプリの操作 = HTTP リクエストの送信

まずは、この Django 入門 の中で開発してきた掲示板アプリの操作について考えていきたいと思います。

ウェブアプリはマウスで操作する?

この掲示板アプリでは、ページ上部にナビゲーションバーが表示されており、このナビゲーションバー内のリンクをマウスでクリックすることで、そのリンク先のページを表示することができるようになっています。例えば コメント一覧 リンクをクリックすれば、コメント一覧が取得され、それらがページに表示されます。

コメントの取得操作をウェブブラウザから実施する様子

また、この掲示板アプリはコメント投稿フォームからコメントが投稿できるようになっています。このコメント投稿フォームでは、コメントの本文の入力欄と 送信 ボタンが用意されており、入力欄に文字列を入力してから 送信 ボタンをマウスでクリックすれば、その入力した文字列を本文とするコメントがデータベースのテーブルにレコードとして保存され、これによってコメントの投稿が実現されるようになっています。

コメントの投稿操作をウェブブラウザから実施する様子

このように、ここまで私たちが開発してきた掲示板アプリは、マウス操作によって様々な操作を行えるようになっています。

ウェブアプリは HTTP リクエストの送信で操作する

…という風にも考えることができるのですが、ここでは、もう1段階踏み込んで考えてみましょう!

たとえば、コメント一覧 のリンクをクリックすることで、投稿済みのコメント一覧が表示できるのは、なぜでしょうか?

これは、この コメント一覧 をクリックすることで、投稿済みのコメント一覧の取得を要求する HTTP リクエストがウェブブラウザからウェブアプリに対して送信されるからになります。この送信された HTTP リクエストをウェブアプリが受信することで、ウェブアプリが投稿済みのコメント一覧を表示するための HTML を生成し、それをボディとする HTTP レスポンスをウェブブラウザに返却してくれます。さらに、この HTTP レスポンスを受け取ったウェブブラウザが、ボディの HTML に基づいてページを描画することで、投稿済みの一覧が画面に表示されることになります。

ウェブアプリの操作がHTTPリクエストの送信によって実施されることを示す図1

また、送信 ボタンのクリックによってコメントを投稿できる理由も同様です。これも、送信 ボタンのクリックによって、コメントの新規登録を要求する HTTP リクエストがウェブブラウザからウェブアプリに対して送信されるからになります。この送信された HTTP リクエストをウェブアプリが受信することで、ウェブアプリが受信したリクエストに応じたレコードをデータベースのコメントを管理するテーブルに新規登録してくれます(この、コメントを管理するテーブルへのレコードの新規登録がコメントの投稿となります)。

ウェブアプリの操作がHTTPリクエストの送信によって実施されることを示す図2

このように、ウェブアプリは HTTP リクエストを受信することで、その HTTP リクエストの内容に応じた処理や機能を実行するようになっています。したがって、ウェブブラウザからウェブアプリを操作することができるのは、ウェブブラウザがウェブアプリに対して HTTP リクエストを送信しているからと考えることができます。これは掲示板アプリだけでなく、全てのウェブアプリで共通的に言えることになります。

ということで、ウェブアプリの操作とは、ウェブアプリに対して HTTP リクエストを送信することになりますまた、その操作結果は、ウェブアプリから送信されてくる HTTP レスポンスによって得ることができます。

ウェブアプリの操作=HTTPリクエストの送信であることを示す図

スポンサーリンク

ウェブアプリはウェブブラウザ以外からも操作可能

そのため、ウェブアプリは、HTTP リクエストの送信(および HTTP レスポンスの受信)さえできれば、どんなアプリ・ツール・プログラムからでも操作可能ということになります。ただ、HTTP リクエストの送信を行うアプリで一番有名なものはウェブブラウザです。そのため、この Django 入門 もそうであるように、基本的には、まずウェブアプリをウェブブラウザで操作することを前提に開発・動作確認を行っていくことになります。

ですが、前述の通り、HTTP リクエストの送信さえできれば、ウェブブラウザ以外からもウェブアプリは操作可能です。なので、例えば iOS アプリや Android アプリから、そのウェブアプリに適した HTTP リクエストを送信するようにしてやれば、それらのアプリからウェブアプリを操作することが可能となります。また、同様にして、JavaScript や Python スクリプトからウェブアプリを操作することも可能です。

様々なアプリ・プログラムからウェブアプリを操作可能であることを示す図

このように、ウェブアプリは、HTTP リクエストの送信によって操作することが可能なアプリであるため、ウェブブラウザだけでなく、様々なアプリ・ツールからも利用可能となります。

また、このような「ウェブアプリが HTTP リクエストの送信によって操作可能であること」を理解しておくことで、ウェブアプリ開発において様々なメリットが得られます。

まず、先ほどの説明からも分かるように、専用アプリの開発に役立ちます。例えば、X や Instagram は、ウェブブラウザでも操作可能ですが、専用の iOS アプリ・Android アプリからも操作可能ですよね。ウェブアプリに適したリクエストを送信するようアプリを開発することで、X や Instagram 同様に、あなたの開発したウェブアプリ操作用の専用アプリを開発・配信することが可能となります。

また、UI (フロントサイド) の開発の自由度が向上します。基本的に、ウェブブラウザでは、ページやフォーム等の UI は HTML・CSS・JavaScript によって表示されるようになっています。なので、ウェブブラウザに表示される UI は、これらの言語を駆使して開発する必要があります。ですが、ウェブアプリの操作は HTTP リクエストさえ送信できれば実施可能なので、専用のアプリを別の言語を利用して開発しても問題ありません。好きな言語を選んで開発できますので、特に UI (フロントエンド) の開発の自由度が上がります。

様々な言語でウェブアプリを操作するアプリが開発可能であることを示す図

さらに、ウェブアプリの動作確認の効率化も図りやすくなります。これまでウェブアプリに対する各種操作の動作確認は全て、ウェブブラウザ上で手動で行ってきました。ですが、HTTP リクエストを送信することでウェブアプリの操作が可能であるため、HTTP リクエストを送信するスクリプトやツールを別途用意しておくことで、それらの実行のみでウェブアプリの動作確認を実施することが可能となります。特に何回も繰り返し動作確認が必要な場合でも、楽に動作確認を実施することが可能です。

ツールの実行のみでウェブアプリの動作確認が実施可能であることを示す図

こんな感じで、ウェブアプリが HTTP リクエストの送信によって操作可能であることを知っておけば、ウェブアプリを操作するプログラムやアプリの作り方の幅広がりますし、自動でウェブアプリの操作を実現するような発想を持つこともできるようになります。

この、HTTP リクエスト送信によって操作できるという点は、ウェブアプリの重要な特徴となるので是非覚えておきましょう!

HTTP リクエストでのウェブアプリの操作の実現

次に、ウェブブラウザ以外からのウェブアプリの操作の実現方法について解説していきます。

HTTP リクエストの送信

ここまで説明してきたように、ウェブアプリは HTTP リクエストの送信によって操作可能です。

HTTP リクエストのデータフォーマット

簡単に、HTTP リクエストのデータフォーマットについて解説しておきます。

HTTP リクエストのデータフォーマットを図で表すと下図のようなものになります。このように、HTTP リクエストは「リクエストライン」「ヘッダー」「ボディ」の3つの部分から構成され、さらに各部に様々なデータ・フィールドが存在します。

HTTPリクエストのデータフォーマット

特に、このページの解説の中で重要となるのが、上の図でも示したリクエストラインの メソッドURL、さらにヘッダーの CookieX-CSRFToken となります。また、ボディが「送信するデータ」となりますので、データの送信を行う場合はボディも必要となります。

HTTP リクエストの送信の実現

ウェブアプリ以外からウェブアプリを操作するためには、先ほど示したような HTTP リクエストの送信を最初に実現する必要があります。

ウェブアプリの操作のために、まずウェブアプリへのHTTPリクエストの送信を実現する必要があることを示す図

HTTP リクエストの送信さえできれば、どんな手段を使っても良いのですが、HTTP リクエストの送信機能を提供するライブラリも多く存在しますので、それらを利用するのがお手軽だと思います。

例えば、Python であれば、下記のようなライブラリを利用することで簡単に HTTP リクエストの送信を行うことができます。後述の ウェブアプリの操作を行うツールの開発例 の章では、requests を利用して、実際にウェブアプリの操作を HTTP リクエストの送信で実施できるようにしていきます。

  • http.client
  • urllib
  • requests

送信する HTTP リクエストの内容

とりあえず、上記のようなモジュールを利用すれば HTTP リクエストの送信自体は実施できるようになると思います。

で、次にポイントになるのが、「どんな HTTP リクエストを送信すればよいのか?」という点になります。

基本的には、この送信すべき HTTP リクエストの内容は、ウェブアプリによって異なります。ただ、ウェブアプリの操作は大きく分けると下記の2つで、それぞれで送信すべき HTTP リクエストの内容の大枠は決まりますので、この点については次の節で解説していきます。

  • データの取得(HTML の取得)
  • データの送信

また、送信すべき HTTP リクエストの内容は、ウェブブラウザが送信する HTTP リクエストから確認することも可能です。

前述の通り、ウェブブラウザは、マウスでの操作時(ボタンやリンクのクリック時)に、その操作に応じた HTTP リクエストをウェブアプリに対して送信するようになっています。なので、そのウェブブラウザから送信される HTTP リクエストを確認し、その内容を真似た HTTP リクエストを送信するようにすれば、ウェブブラウザからの操作時と同じ操作を、ウェブブラウザ以外のアプリやプログラムから実施することができることになります。つまり、送信する HTTP リクエストの内容が同じであれば、それを誰が送信したとしても、同じ操作が行えるということです。

ウェブブラウザと同じHTTPリクエストを送信すれば、同じ操作をウェブアプリに要求することができることを示す図

なので、どんな HTTP リクエストを送信すればよいか分からない場合は、実際にウェブブラウザでウェブアプリの操作を行い、その操作時に送信される HTTP リクエストを真似て送信するようにしてやれば良いです。

ただ、ウェブブラウザから送信される HTTP リクエストと全く同じ HTTP リクエストを送信するようにする必要はありません。特に、HTTP リクエストのヘッダーに関しては、ポイントとなる部分のみを真似て送信するようにしてやれば良いです。

また、ウェブブラウザから送信される HTTP リクエストは、Google Chrome の「検証ツール」や Microsoft Edge の「開発者ツール」で確認することも可能ですし、下記ページで紹介している Wireshark というアプリで確認することもできます。後述の ウェブアプリの操作を行うツールの開発例 の章では、Chrome を利用して HTTP リクエストを確認する例を紹介していきます。

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

スポンサーリンク

HTTP リクエストでのデータの取得

続いて、HTTP リクエストの送信によるデータの取得方法について解説していきます。

ウェブアプリの操作は、大きく分けて2種類に分けられます。1つ目が「データの取得操作」で、2つ目が「データの送信操作」になります。

まずは、1つ目のデータの取得について解説していきます。

本題に入る前に、少し前置きをしておくと、ウェブブラウザのみから操作されることを想定したウェブアプリの場合は、データの取得操作は「HTML の取得操作」と考えて良いです。

このようなウェブアプリでは、ウェブブラウザでページが表示できるよう、データの表示に関するリクエストが送信された際には HTTP レスポンスのボディとして HTML を返却するようになっています。つまり、このようなウェブアプリから取得可能なデータは基本的には HTML のみです。例えば、この Django 入門 の連載を通して開発してきている掲示板アプリもウェブブラウザのみから操作されることを想定しているため、このアプリから取得できるデータは現状 HTML のみになります。

データの取得操作で取得可能なデータがHTMLであることを示す図

ですが、次回の Django 入門 で説明する API をウェブアプリに搭載することで、HTML 以外のデータをウェブアプリから取得することができるようになります。このページでは、ウェブアプリから取得できるデータが HTML であることを前提に解説を進めますが、ウェブアプリの作り方によっては、HTML 以外のデータを取得することも可能であることは頭の片隅にでも置いておいてください。

GET メソッドの HTTP リクエストを送信する

では、HTTP リクエストの送信によるデータの取得について解説していきます。

基本的には、データの取得操作は、下記のような HTTP リクエストを送信するだけで実現することができます。

  • URL:取得対象を示す URL
  • メソッド:GET

ウェブブラウザからのみ操作されることを想定して開発されたウェブアプリの場合は、URL には「表示対象のページの URL」を指定してやれば良いことになります。

ウェブブラウザ以外からデータの取得操作を行う様子

とりあえず、上記のような HTTP リクエストを送信するようにすれば、URL に対応した HTML を取得することができるようにはなります。ですが、ウェブブラウザ以外のツールやアプリが HTML を取得してもページの表示を行うことは困難ですし、HTML にはタグなどの不要なデータが含まれていますので、HTML を取得した後に目当てとなるデータのみを抽出するための HTML の解析を行うことになります。そして、その抽出したデータを利用して目的の処理を実行するようなことが多いと思います。

この HTML の解析の概要に関しては、後述の HTTP レスポンスの解析 の節で解説します。

HTTP リクエストでのデータの送信

また、ウェブアプリではデータの送信を行う操作も多いです。

例えば、掲示板アプリであれば、コメントの投稿操作はデータの送信操作の1つであり、コメントの投稿者やコメントの本文をウェブアプリに対して送信することで、コメントの投稿をウェブアプリに依頼することになります。また、ユーザー登録に関しても、登録するユーザーの情報をウェブアプリに対して送信することで実現される操作となります。

このように、特に下記ページで説明した CRUD 操作における Create や Update 操作を行う場合は、こういったデータの送信が必要となります。

【Django入門16】CRUDの実現(Create・Read・Update・Delete)

POST メソッドの HTTP リクエストを送信する

このようなデータの送信操作を行うには、下記のような HTTP リクエストを送信する必要があります。

  • URL:データの送信先の URL
  • メソッド:POST
  • ボディ:送信するデータ
  • ヘッダー:
    • Cookie: Set-Cookiecsrftoken
    • X-CSRFTokenSet-Cookiecsrftoken

この「送信するデータ」は、ウェブブラウザでフォームから送信するデータと同じフォーマットのものである必要があります。このようなデータの送信方法については、後述の ウェブアプリの操作を行うツールの開発例 で説明します。

MEMO

今回は、ウェブブラウザから操作されることを前提に開発されたウェブアプリを対象としているため、データの送信操作を行う際にはメソッドに POST を指定することになります

ただし、前述の説明の中でも登場した API が搭載されたウェブアプリの場合は、POST 以外のメソッドの HTTP リクエストの送信が必要になることもあります

Cookie に csrftoken を設定する

特に、上記で示した HTTP リクエストにおいてポイントになるのが「ヘッダー」になります。

Django で開発したウェブアプリでは、特定の条件を満たさない「データの送信操作に対する HTTP リクエスト」が送信されてきた場合、その HTTP リクエストが CSRF 攻撃であると判断され、エラーが発生するようになっています。そして、この場合はデータの送信操作が実施できないことになります。

単にPOSTメソッドのリクエストでデータを送信するとCSRF攻撃と見做されてしまうことを示す図

このエラーを回避するためには、それが CSRF 攻撃でない、すなわち「安全な HTTP リクエスト」であるとウェブアプリに判断されるような HTTP リクエストを送信する必要があります。そして、そのための条件が2つあって、1つ目が、この節の題名にも書いている通り、csrftoken を HTTP リクエストの Cookie に設定しておくことになります。 

この csrftoken は、ウェブアプリから発行されるトークンであり、ウェブアプリに対して GET メソッドの HTTP リクエストを送信すると、それに対する HTTP レスポンスの Set-Cookie のフィールドの値として受け取ることができます。

GETメソッドに対するHTTPレスポンスのSet-Cookieでcsrftokenを受け取ることができることを示す図

なので、データの送信操作を行うためには、まずウェブアプリに対して GET メソッドの HTTP リクエストを送信して csrftoken を受け取り、さらに、その csrftoken をヘッダーの Cookie に設定した上で、HTTP リクエストを送信する必要があることになります。

Cookieへのcsrftokenの設定の仕方の説明図

X-CSRFTokencsrftoken を設定する

2つ目の条件が、先ほど説明した csrftoken を HTTP リクエストのヘッダーの X-CSRFToken に設定しておくことになります。

要は、ウェブアプリに対してデータの送信操作を行うためには、ヘッダーの CookieX-CSRFToken の両方に、ウェブアプリから発行された csrftoken を設定した HTTP リクエストを送信する必要があります。

X-CSRFTokenへのcsrftokenの値の設定

この2つの条件を満たした HTTP リクエストを送信することで、その HTTP リクエストがウェブアプリに安全であると判断されるようになり、データの送信操作を行うことができるようになります。

(参考)csrfmiddlewaretoken を利用する

また、ヘッダーの X-CSRFTokencsrftoken を設定する代わりに、送信するデータに csrfmiddlewaretoken フィールドを追加し、このフィールドの値としてトークンを設定することでも、データの送信を実現することが可能です。

実は、ウェブブラウザでフォームからデータを送信する場合は、こちらの方法が用いられています。

ウェブブラウザでフォームからデータを送信する際にはボディでcsrfmiddlewaretokenを送信するようになっていることを説明する図

これは、ウェブブラウザで取得したフォームの HTML を見てみれば確認できることなのですが、Django で開発したウェブアプリから取得したフォームの HTML には、隠れフィールドとして、値をウェブアプリから発行されたトークンとする csrfmiddlewaretoken フィールドが含まれています。

取得したフォームにcsrfmiddlewaretokenフィールドが存在する様子

そのため、フォームからデータを送信したときには、他のフィールドの値に含めて csrfmiddlewaretoken も送信されことになります。そして、送信されてきたデータに csrfmiddlewaretoken が存在するため、その HTTP リクエストは安全であるとウェブアプリに判断されることになります。

ちなみに、フォームに csrfmiddlewaretoken フィールドが存在するのは、Django でウェブアプリを開発する際に、テンプレートファイルの form タグ内に {% csrf_token %} を記述することになっているからになります。

{% csrf_token %}の記述
<form action="略" method="post">
    {% csrf_token %}
    略
</form>

この {% csrf_token %} を記述しておくことで、この部分が csrfmiddlewaretoken フィールドに置き換えられることになり、それによって CSRF 攻撃と判断されない HTTP リクエストの送信を行うことができるようになっています。

もしかしたら、{% csrf_token %} の記述を忘れていて、フォームからデータを送信した際に下記のようなエラーが発生した経験のある方もおられるかもしれません。これは、送信するデータに csrfmiddlewaretoken フィールドが存在しないため、送信されてきた HTTP リクエストが CSRF 攻撃であると判断されたからになります。

CSRF検証に失敗したため、リクエストは中断されました。

ということで、送信するデータに csrfmiddlewaretoken フィールドを追加することでも、正常なデータの送信操作を実現することは可能です。ただ、この方法では、事前にフォームを取得する HTTP リクエストを送信してフォームを HTTP レスポンスで受け取り、さらに、そのフォームの HTML を解析して csrfmiddlewaretoken フィールドの値を取得するような処理が必要となって面倒です。先に紹介した HTTP レスポンスの Set-Cookieで取得した csrftokenX-CSRFToken に設定する方法の方が楽です。そのため、以降では、データの送信時には X-CSRFTokencsrftoken を設定する方法を採用することを前提に解説を進めます。

HTTP リクエストでのデータの送信のまとめ

ここまでの内容をまとめると、データ送信操作を行う際には、下記のような HTTP リクエストを送信する必要があります。

  • URL:データの送信先の URL
  • メソッド:POST
  • ボディ:送信するデータ
  • ヘッダー:
    • Cookie: Set-Cookiecsrftoken
    • X-CSRFTokenSet-Cookiecsrftoken

ただし、★マークで示したデータに関しては、事前にメソッドが GET の HTTP リクエストをウェブアプリに送信し、その応答となる HTTP レスポンスから取得する必要があります。

これらを送信するスクリプトの例は、次の章の ウェブアプリの操作を行うツールの開発例 で示していきます。

HTTP レスポンスの解析

ここまで説明してきた通り、HTTP リクエストを送信することでウェブアプリの操作を実現することが可能です。さらに、その操作結果や取得したデータは、操作を実施するために送信した HTTP リクエストの応答となる HTTP レスポンスを解析することで得られることになります。

ここでは、この HTTP レスポンスの解析について解説していきます。

HTTP レスポンスのデータフォーマット

まずは、このウェブアプリから受信する HTTP レスポンスのデータフォーマットについて解説しておきます。

HTTP レスポンスのデータフォーマットを図で表すと下図のようなものになります。このように、HTTP レスポンスは「ステータスライン」「ヘッダー」「ボディ」の3つの部分から構成され、さらに各部に様々なデータ・フィールドが存在します。

HTTPレスポンスのデータフォーマット

特に、このページの解説の中で重要となるのが、上の図でも示したステータスラインの ステータスコード、さらにヘッダーの Set-Cookie になります。Set-Cookie に関しては、ここまでの解説の中でも登場しましたね!

あとは、ボディが「取得したデータ」となりますので、特にデータの取得操作を行う場合はボディが重要となります。

結果を知るために受信した HTTP レスポンスの解析が必要

前述の通り、ウェブアプリの操作結果は HTTP レスポンスとして、HTTP リクエストの送信元に返却されることになります。操作結果の詳細を知りたい場合は、この HTTP レスポンスの解析が必要となります。

例えば、HTTP レスポンスの ステータスコード には、操作結果の成功・失敗(及び失敗の理由)を表す値がセットされていますので、操作が成功したかどうかを知るために HTTP レスポンスを解析して ステータスコード を取得する必要があります。

操作結果の判断方法を示す図

他にも、データの送信操作を実現するためには、HTTP レスポンスを解析して Set-Cookie の値を取得するようなことも必要となります。こういった、HTTP レスポンスのステータスラインやヘッダーのデータに関しては、前述でも紹介した「HTTP リクエストを送信するライブラリ」を利用することで、簡単に取得することが可能です。

HTML を解析して必要なデータのみを抽出することも必要

また、ウェブブラウザから操作されることを前提に開発されたウェブアプリの場合、HTTP レスポンスのボディは基本的には HTML となります。なので、特にデータの取得操作を実施した場合は、その HTML を解析し、HTML の中から必要なデータのみを抽出するような処理も必要となります。例えば、コメント一覧の取得操作に対しては、そのコメント一覧をページ表示するための HTML が返却されることになるため、その HTML 内から必要なデータ(コメントの本文やコメントの投稿者など)を取得し、その取得後のデータを利用して処理を実施する必要があることが多いです。

HTMLから必要なデータのみを抽出する様子

HTML の解析の仕方

自力で HTML の解析を行うのは大変なので、この HTML の解析に関してもライブラリを利用して実施するのが良いと思います。Python であれば、HTML の解析用ライブラリとして BeautifulSoup が存在し、これが利用されることが多いです。後述の ウェブアプリの操作を行うツールの開発例 の章では、BeautifulSoup を利用した HTML の解析例を示していきます。

ただし、HTML の具体的な解析の仕方は、結局のところウェブアプリが返却してくる HTTP レスポンスの HTML の構造によって異なります。なので、HTML の解析を行うためには、ウェブアプリが返却する HTML の構造を理解しておく必要があります。これに関しても、実際にウェブブラウザで操作を行い、その操作によって取得される HTML を確認するのが手っ取り早いと思います。また、Django で開発するウェブアプリの場合は、テンプレートファイルで HTML の構造が決まりますので、テンプレートファイルから HTML の構造を理解しておくのでも良いです。

ウェブブラウザで受信したHTMLはウェブアプリのテンプレートファイルからHTML解析の仕方を決める必要があることを説明する図

ここまでの説明内容で既に感じ取っていただいているかもしれませんが、HTML はウェブブラウザでページを表示するのに適したデータではありますが、ウェブブラウザ以外からは扱いにくいデータです。なぜなら、HTML から必要なデータのみを取得したいような場合、上記で説明したように HTML の解析処理が必要になるからです。

そのため、ウェブブラウザ以外が HTTP レスポンスのボディのデータを利用するケースがあるのであれば、HTTP レスポンスのボディを HTML ではなく、解析が不要 or 簡単な形式のデータ、例えば JSON 等とする API を追加で用意して、それを利用するようにするというのも手です。この API に関しては、次回の連載の中で解説を行いたいと思います。

スポンサーリンク

ウェブアプリの操作を行うツールの開発例

ここからは、ウェブアプリの操作が HTTP リクエストによって実施できることを実感していただくため、実際にウェブアプリの操作を行うツールを作成していきたいと思います。

ウェブアプリの作成と起動

まずは、操作対象となるウェブアプリを開発していきたいと思います。

今回は、コメントの投稿と、投稿済みのコメント一覧の表示機能のみを備えた簡単なウェブアプリをまず開発し、その後、そのウェブアプリとウェブブラウザの間でやりとりする HTTP リクエスト・HTTP レスポンスを調べ、さらに、その調べた結果に基づいて、ウェブアプリを操作するツールを開発する例を示していきます。

プロジェクト・アプリの作成

まずは、プロジェクトとアプリを作成していきます。

ターミナルやコマンドプロンプト等のコンソールアプリで適当な作業フォルダに移動した後、下記を実行して request_test というプロジェクトを作成してください。

django-admin startproject request_test

これにより、request_test というフォルダが作成されるはずなので、そのフォルダに移動した後、下記コマンドを実行して forum というアプリを作成してください。

python manage.py startapp forum

次に、今いる request_test フォルダの中に、もう1つ request_test フォルダが存在するはずなので、そのフォルダの中の settings.py を開き、下記のように INSTALLED_APPS のリストの先頭に 'forum', を追加して下さい。

settings.py(アプリの登録)
INSTALLED_APPS = [
    'forum',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

さらに、settings.py と同階層に urls.py が存在するはずなので、この urls.py を下記のように変更してください。

urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('forum/', include('forum.urls'))
]

models.py の作成

次に、forum/models.py を下記のように変更し、コメントを管理するモデルクラス Comment を定義します。

models.py
from django.db import models

class Comment(models.Model):
    author = models.CharField(max_length=32)
    text = models.CharField(max_length=256)

forms.py の作成

続いて、forum/forms.py を新規作成し、さらにファイルに下記を記述してコメント投稿フォーム CommentForm を定義します。

models.py
from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['author', 'text']

views.py の作成

さらに、views.py を下記のように変更し、コメント投稿を行う CommentCreate と、コメント一覧表示を行う CommentList のビューを定義します。

models.py
from .forms import CommentForm
from .models import Comment
from django.views.generic import ListView, CreateView
from django.urls import reverse_lazy

class CommentCreate(CreateView):
    form_class = CommentForm
    template_name = 'forum/comment_form.html'
    success_url = reverse_lazy('list')

class CommentList(ListView):
    model = Comment
    template_name = 'forum/comment_list.html'

テンプレートファイルの作成

次は、CommentCreate から利用するテンプレートファイル comment_form.htmlCommentList から利用するテンプレートファイル comment_list.html を次のように作成し、forum/templates/forum フォルダ内に設置してください。

comment_form.html
<h1>コメント投稿</h1>
<form action="{% url 'create' %}" method="post">
    {% csrf_token %}
    <table >{{ form.as_table }}</table>
    <p><input type="submit" value="送信"></p>
</form>
comment_list.html
<h1>コメント一覧</h1>
<table>
    <thead>
        <tr>
            <th>本文</th><th>投稿者</th>
        </tr>
    </thead>
    <tbody>
        {% for comment in comment_list %}
        <tr>
            <td>{{ comment.text }}</td>
            <td>{{ comment.author }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

urls.py の作成

次は、forum/urls.py を新規作成し、ファイルの中身を下記のように変更してください。ソースコードの変更は以上となります。

forum/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('create/', views.CommentCreate.as_view(), name='create'),
    path('list/', views.CommentList.as_view(), name='list'),
]

マイグレーションの実行

ソースコードの変更が完了したら、次は、startapp コマンドを実行したフォルダと同じフォルダで下記の2つのコマンドを実行し、マイグレーションを行ってください。

python manage.py makemigrations
python manage.py migrate

開発用ウェブサーバーの起動

最後に、下記コマンドを実行して開発用ウェブサーバーを起動してください。

python manage.py runserver

HTTP リクエストと HTTP レスポンスを調べる

ここからウェブアプリを操作するツールの開発を行なっていくことになるのですが、まずは、先ほど開発したウェブアプリをウェブブラウザから操作し、操作時に送受信される HTTP リクエストと HTTP レスポンスを調べていきたいと思います。

HTTP リクエストを送信しても意図した通りの操作が実現できない場合、まずはウェブブラウザで操作を行なって HTTP リクエストを調べ、それを真似て送信する HTTP リクエストを修正するのが手っ取り早いです。また、HTTP レスポンスの解析を行うことになるので、事前にウェブブラウザが受信する HTTP レスポンスを調べ、解析の方針決めを事前に行っておくと、スムーズにツールの開発を進めることができます。

ウェブアプリが送受信するHTTPリクエストとHTTPレスポンスを調べる様子

このように、ウェブブラウザが送受信する HTTP リクエストと HTTP レスポンスを調べることができれば、ウェブブラウザ以外からのウェブアプリの操作の実現に非常に役に立ちます。というか、ウェブアプリを開発するのであれば、こういたデータの調べ方は理解しておいた方が良いです。ここでは、先ほど開発したウェブアプリを例にして、上記のような通信データの調べ方を簡単に説明していきますので、今後のウェブアプリ開発やウェブアプリの操作の実現時に活用していただければと思います。

Chrome の検証機能を起動する

まずは Chrome を起動してください。さらに、右クリックメニューの 検証 をクリックし、Chrome の検証機能を実行しましょう!

ChromeでのHTTPリクエストとHTTPレスポンスの調べ方1

そうすると、Chrome の右側に検証ウィンドウが表示されるはずです。

ChromeでのHTTPリクエストとHTTPレスポンスの調べ方2

このウィンドウでは、Chrome が送受信した HTTP リクエストや HTTP レスポンスを確認することが可能です。さらに、ページに表示されている各要素の HTML のタグとの対応や、各要素に適用されているスタイル等も確認することが可能です。

検証ウィンドウで確認できる項目の説明図

ちなみに、今回は Chrome を利用していますが、Edge でも同様の機能を利用することが可能です。Edge の場合は、右クリックメニューから 開発者ツールで調査する をクリックすることで、同様のウィンドウを開くことができます。ただし、Chrome の場合と Edge の場合とで、タブ名やメニュー名等の文言が若干異なるので、その点は注意してください。

で、今回調べたいのは HTTP リクエストと HTTP レスポンスといったネットワークに関する情報になるなので、検証ウィンドウの上側の ネットワーク タブを開いてください。

ChromeでのHTTPリクエストとHTTPレスポンスの調べ方3

これで前準備は完了です!

コメント投稿操作時のリクエストとレスポンスを調べる

ここから、実際に Chrome で各種操作を実施し、その時に Chrome が送受信する HTTP リクエストと HTTP レスポンスを調べていきます。

最初に、コメント投稿の操作を行っていきたいと思います。

まず、下記 URL を Chrome のアドレスバーに指定してコメント投稿フォームを表示してみてください。

http://localhost:8000/forum/create/

フォームには、下の図のように Author フィールドと Text フィールドが存在しますので、それぞれに適当な投稿者名とコメント本文を入力してください。そして、その後に 送信 ボタンをクリックしてください。

コメント投稿操作時のHTTPリクエストの調べ方1

この 送信 ボタンのクリックによって、検証ウィンドウに表示される情報が、送信 ボタンクリック時に送受信された HTTP リクエストと HTTP レスポンスの情報のものに更新されます。次は、これらの情報を確認していきましょう!

まずは、検証ウィンドウ左下の 名前 欄の create/ をクリックし、続けて ヘッダー をクリックしてヘッダータブを開いてください。この ヘッダー から、直前の操作時に送受信された HTTP リクエストと HTTP レスポンスを調べることが可能です。

コメント投稿操作時のHTTPリクエストの調べ方2

さらに、このヘッダータブにおける、全般 セクションの リクエスト URLリクエスト メソッド を確認してみましょう!

コメント投稿操作時のHTTPリクエストの調べ方3

今回の場合は、下記のように表示されているはずで、これは 送信 ボタンがクリックされた時に送信される HTTP リクエストの URL とメソッドとなります。したがって、ウェブブラウザ以外からコメントの投稿を行う際にも、下記のようなリクエストを送信するようにツールを開発する必要があることになります。

  • リクエスト URLhttp://localhost:8000/forum/create/
  • リクエスト メソッドPOST

次は、リクエスト ヘッダー セクションに存在する Cookie の欄を確認してみてください。ここには、ウェブブラウザが送信した HTTP レスポンスのヘッダーにおける Cookie フィールドのデータが表示されています。このデータの中には、 csrftoken=... の文字列が存在しているはずです。

コメント投稿操作時のHTTPリクエストの調べ方4

この csrftoken は、事前にフォームを表示したときの HTTP レスポンスの Set-Cookie に設定されていたデータとなります。ウェブブラウザ以外からデータの送信操作を行う際にも、このように事前に取得した csrftokenCookie に設定した状態の HTTP リクエストを送信する必要があります。

Cookieへのcsrftokenの設定の仕方の説明図

さらに、次は ペイロード タブを表示してみてください。ここには、送信 ボタンがクリックされた時に送信される HTTP リクエストのボディのデータ、すなわちフォームから送信されたデータが表示されるようになっています。

コメント投稿操作時のHTTPリクエストの調べ方5

ここには、下記の3つのフィールドの値が表示されるはずです。

  • csrfmiddlewaretoken
  • author
  • text

author の値としては、あなたが Author フィールドに入力した文字列、text の値としては、あなたが Text フィールドに入力した文字列がそれぞれ表示されているはずです。これらは、フォームからユーザーに入力してもらった値なので、当然 送信 ボタンのクリック時に送信されるようになっています。そして、このデータをウェブアプリが受け取ることで、コメントのレコードとしてデータベースに保存が行われることになります。

で、それらに加えて、送信されるデータに csrfmiddlewaretoken フィールドが存在することが確認できると思います。(参考)csrfmiddlewaretoken を利用する で解説したように、ウェブブラウザからデータの送信操作が行われる際には、このような csrfmiddlewaretoken フィールドが追加された状態のデータが送信されることになります。これは、ウェブアプリに、送信した HTTP リクエストを CSRF 攻撃ではないと判断させるためです。

前述の通り、この csrfmiddlewaretoken フィールドをデータとして送信する代わりに、HTTP リクエストのヘッダーの X-CSRFToken フィールドに csrftoken の値をセットしておくことでも同様のことが実現可能です。このページでは、X-CSRFToken フィールドに csrftoken の値をセットする方法を採用してウェブアプリを操作するツールを開発していきます。

X-CSRFTokenへのcsrftokenの値の設定

続いて、ペイロード タブの ソースを表示 をクリックしてみてください。実は、先ほど表示されていたのは、ウェブブラウザから送信されたデータそのものではなく、それを辞書のような形式に整形したデータとなります。で、この ソースを表示 をクリックすることで、ウェブブラウザでフォームから実際に送信されたデータを確認することができます。

コメント投稿操作時のHTTPリクエストの調べ方7

各種フィールドの値が & で区切られているところがポイントで、ツールからデータの送信操作を実現する場合も、このような形式のデータをツールから送信する必要があることになります。ちなみに、このようなデータの形式は「URL エンコード」と呼ばれます。

最後に、再度 ヘッダー タブを表示し、全般 セクションの ステータスコード 欄を確認してみてください。

コメント投稿操作時のHTTPレスポンスの調べ方

この ステータスコード 欄の値は 302 となっているはずです。

このコメント投稿フォームでは、コメントの投稿に成功した場合に、HTTP レスポンスとしてリダイレクトレスポンスを返却し、他のページへのリダイレクトを行うようになっています。このリダイレクト先はコメント一覧のページとなっているので、送信 ボタンをクリックした際にコメント一覧が表示されたというわけです。で、このリダイレクトレスポンスのステータスコードは基本的には 302 となります。なので、コメントの投稿に成功したかどうかは、HTTP レスポンスのステータスコードの値が 302 であるかどうかで判断することができます。

ちなみに、コメントの投稿に失敗した場合は、再度コメント投稿フォームが表示されることになり、その時のステータスコードは 200 となります。

ここまでの説明内容をまとめると、先ほど開発したウェブアプリに対するコメント投稿の操作は、下記のような HTTP リクエストを送信することで実現できることになります。

  • URLhttp://localhost:8000/forum/create/
  • メソッドPOST
  • ヘッダー:
    • Cookie: Set-Cookiecsrftoken
    • X-CSRFTokenSet-Cookiecsrftoken
  • ボディ(送信するデータ):
    • author フィールド:フォームの Author フィールドに入力された値
    • text フィールド:フォームの Author フィールドに入力された値

ただし、上記の★マークを付けた項目に関しては、事前にウェブアプリから受け取っておく必要があるため、まず、GET メソッドの HTTP リクエストを送信し、それに対する HTTP レスポンスとして★マーク部分のデータを取得するようにする必要があります。

そのため、事前に下記の HTTP リクエストを送信して★マーク部分のデータを取得し、その後、上記のような HTTP リクエストを送信してコメントの投稿操作を行うようにツールを開発するようにしたいと思います。

  • URLhttp://localhost:8000/forum/create/
  • メソッドGET

コメント一覧取得時のリクエストとレスポンスを調べる

次は、コメント一覧取得時の HTTP リクエストと HTTP レスポンスを調べていきたいと思います。

コメント一覧の取得に関しては、コメントが投稿済みである方が内容を理解しやすくなると思いますので、まずは下記ページで複数のコメントを投稿しておいてください。2、3個コメントが投稿されていればオーケーです。

http://localhost:8000/forum/create/

コメントの投稿が完了したら、下記の URL を Chrome のアドレスバーに入力してコメント一覧ページを表示してください。

http://localhost:8000/forum/list/

コメント一覧ページを表示したら、検証ウィンドウの 名前 欄の list/ をクリックし、Chrome が送受信した HTTP リクエストと HTTP レスポンスを調べていきましょう!

ここでは、ヘッダー をクリックしてヘッダーセクションを表示し、全般 セクションの リクエスト URLリクエスト メソッド を確認してみてください。

コメント取得操作時のHTTPリクエストの調べ方

これらの欄から、コメント一覧ページの取得操作を行うために、ウェブブラウザが下記のようなリクエストを送信していることが確認できます。したがって、ウェブブラウザ以外からコメント一覧ページの取得操作を実施する際にも、下記のようなリクエストを送信するようにする必要があることになります。

  • リクエスト URLhttp://localhost:8000/forum/list/
  • リクエスト メソッドGET

今回のウェブアプリの場合、コメント一覧の取得に関しては、上記のように URL とメソッドを指定した HTTP リクエストを送信するだけで実現することができ、その取得結果は HTTP レスポンスのボディとして得られます。

次は、そのボディを確認してみましょう!

検証ウィンドウの レスポンス タグを開いてみてください。ここに、取得したボディが表示されています。

コメント取得操作時のHTTPレスポンスの調べ方

確認していただければ分かる通り、HTTP レスポンスのボディとして得られるデータは HTML です。もともと、ウェブアプリはウェブブラウザから操作されることを前提とした作りとなっているため、ウェブブラウザでページ表示が行えるよう、HTTP レスポンスのボディは HTML となっています。

そして、この HTML の <table></table> の中に、投稿したコメントの情報が含まれており、とりあえずコメント一覧の取得自体は成功していることが確認できると思います。実際に、この HTML をウェブブラウザで表示すれば、コメント一覧のページを表示することができます。

ただ、ウェブブラウザ以外のツール等から取得したコメントを扱うには、この HTML の形式だと不便です。例えば取得したコメントを全て表示するにしても、この HTML の形式のまま出力してしまうと不要なタグ等が表示されてしまいます。

なので、HTML からの必要なデータのみの抽出が必要となります。

今回の場合、下記のような <table></table> の中にコメントの投稿者とコメントの本文が存在しますので(少し見やすいように整形しています)、

コメント一覧
<table>
    <thead>
        <tr>
            <th>本文</th><th>投稿者</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Hello World</td>
            <td>Yamada Hanako</td>
        </tr>
        <tr>
            <td>Good bye</td>
            <td>Tanaka Jiro</td>
        </tr>
        <tr>
            <td>Nice to meet you</td>
            <td>Sato Saburo</td>
        </tr>
    </tbody>
</table>

下記のように検索を実施していけば、コメントの投稿者とコメントの本文のみを取得することが可能です。そして、これらの取得したデータを扱うようにすれば、不要なタグ等を含まない、必要なデータのみ(コメントの投稿者とコメントの本文のみ)を扱うことができるようになります。

  1. table タグを検索
  2. 1. で見つかったタグ内から tbody タグを検索
  3. 2. で見つかったタグ内から全ての tr タグを検索
  4. 3. で見つかった各タグ内から全ての td タグを検索
  5. 4. で見つかった各タグのテキストを下記のように取得
    • 1つ目の td タグのテキスト:「コメント本文」として取得
    • 2つ目の td タグのテキスト:「コメント投稿者」として取得

このデータの取得の具体的な処理に関しては後述で示すスクリプトの中で示していきますが、前述でも紹介した BeautifulSoup を利用することで、簡単に上記の取得を実現することができます。

ただし、上記のような手順で必要なデータが取得できるのは、今回用意した HTML のような構造である場合のみで、結局 HTML の構造に合わせて取得手順を変更する必要があります。なので、ウェブブラウザ以外からのウェブアプリの操作を実現するためには、例えば先ほど示したような手順で事前にウェブアプリから受信できる HTML の構造を理解しておく必要あります。そして、BeautifulSoup を利用すれば、それなりに簡単に狙ったデータの取得を実現することができると思います。

コメント一覧の取得の操作についてまとめると、この操作は下記のような HTTP リクエストを送信することで実現できることになります。

  • URLhttp://localhost:8000/forum/list/
  • メソッドGET

ただし、取得した HTML からコメントの投稿者やコメントの本文等のみを取得したい場合は、別途 HTML の解析を行う必要があります。

少し説明が長くなりましたが、ここまで説明してきたように、HTTP リクエストの送信によってウェブアプリの操作を行うプログラムを開発する際には、ウェブブラウザが実際に送受信している HTTP リクエスト・HTTP レスポンスが参考になります。なので、こういったプログラムを開発する上では、ここで示したような、ウェブブラウザの送受信する HTTP リクエスト・HTTP レスポンスの調べ方は理解しておくとよいと思います!

スポンサーリンク

ツールの開発(CUI)

操作対象のウェブアプリが用意でき、さらにツールが送受信すべき HTTP リクエストや HTTP レスポンスに関しても調べることができましたので、次は、ウェブアプリの操作を行うツールの開発に移りたいと思います。

必要なライブラリのインストール

今回は、HTTP リクエストの送信用のライブラリとして requests を利用し、さらに HTML 解析用のライブラリとして Beautifulsoup を利用していきます。

そのため、これらのライブラリが未インストールの方は、事前にライブラリのインストールを行っておいてください。

requests に関しては下記コマンドで、

python -m pip install requests

Beautifulsoup に関しては下記コマンドでインストール可能です。

python -m pip install beautifulsoup4

requests の使い方

一応、簡単に各ライブラリの使い方を説明しておきます。まずは requests の使い方を解説します。

requests の基本的な使い方は「HTTP リクエストのメソッドに応じた関数を実行し、その関数の返却値として HTTP レスポンスを受け取る」になります。

この requests では、HTTP リクエストのメソッド名に応じた関数が定義されています。そして、これらの関数を実行することで、その関数に応じたメソッドの HTTP リクエストを送信することが可能です。今回利用するのは下記の2つの関数になります。

  • requests.get:メソッドが GET の HTTP リクエストを送信する
  • requests.post:メソッドが POST の HTTP リクエストを送信する

これらの関数の返却値は HTTP レスポンスであり、つまりは、これらの関数は HTTP リクエストの送信だけでなく、その応答となる HTTP レスポンスの受信まで行ってくれます。

requestsライブラリの説明

また、この返却値の HTTP レスポンスからは、ボディのデータや各種ヘッダーの値を取得することが可能です。例えば、これらの関数の返却値を response とすれば、HTTP レスポンスの Set-Cookie の値は response.cookies で取得できますし、ボディのデータは response.text で取得可能です。

requestsの関数の返却値から取得可能なデータを説明する図

さらに、これらの関数では url 引数を指定することで、その送信する HTTP リクエストの URL を設定することができます。この url に指定する URL は、絶対パス形式で指定する必要があります。

他にも、下記のような引数を追加で指定することが可能で、これらの引数の指定によって、送信する HTTP リクエストの内容の詳細を設定することができます。

  • data:送信するデータ
  • headers:ヘッダーにセットするデータ
  • cookies:クッキーにセットするデータ

ウェブブラウザでのフォームからのデータの送信を模擬する場合は、data には辞書を指定してやれば良いです。それにより、コメント投稿操作時のリクエストとレスポンスを調べる でも示した下図のような、各種フィールドが & で区切られた形式に変換されたデータが送信されることにになります。 

コメント投稿操作時のHTTPリクエストの調べ方7

また、allow_redirects 引数によって、HTTP リクエストの送信によってリダイレクトレスポンスを受け取った時に、自動的にリダイレクト先に対する HTTP リクエストを送信するか否かを設定することが可能です。allow_redirects=True を指定した場合 or デフォルトの場合は、自動的なリダイレクト先への HTTP リクエストの送信が有効となります。この場合は、requests の関数は、自動的なリダイレクト先への HTTP リクエストに対する HTTP レスポンスを返却することになります。

allow_redirects=Trueを指定した場合のrequestsライブラリの動作

つまり、allow_redirects=True を指定した場合 or デフォルトの場合、関数の返却値でリダイレクトレスポンスを受け取ったかどうかを判断できません。それに対し、コメントの投稿の成功 or 失敗は、リダイレクトレスポンスを受け取ったかどうかで判断する必要があるので、コメントの投稿操作を実施する際の HTTP リクエスト送信時には allow_redirects=False を指定する必要があります。

BeautifulSoup の使い方

BeautifulSoup の基本的な使い方は「HTML を解析し、その解析結果から特定のタグを取得する or 特定のタグの情報を取得する」になります。

HTML の解析自体は、BeautifulSoup() を実行することで実施できます。BeautifulSoup() は、第1引数に解析対象の HTML を、第2引数に 'html.parser' を指定して実行します。BeautifulSoup() の返却値は解析結果のオブジェクトとなり、このオブジェクトに下記のメソッドを実行させることで、HTML から特定のタグを検索して取得することができます。

  • find メソッド:引数で指定した条件に合致するタグを HTML の先頭から検索し、最初に見つけたタグのオブジェクトを返却する
  • find_all メソッド:引数で指定した条件に合致するタグを HTML から検索し、見つかったタグのオブジェクト全てを要素とするリストを返却する(正確にはリストではないですが、簡単のためリストとして説明します)

さらに、上記のメソッドから返却されるタグのオブジェクトの内側にもタグが存在する場合、取得したタグのオブジェクトに上記のメソッドを実行させることで、その内側のタグのオブジェクトを取得することもできます。これを繰り返すことで、目当てのタグのオブジェクトを取得することができるようになります。

BeautifulSoupの使い方の説明図

このように、上記のメソッドを駆使して目当てのタグのオブジェクトを取得し、さらに、そのタグのオブジェクトの attrs データ属性から、そのタグの特定の属性の値を取得したり、get_text メソッドによって、そのタグのテキストを取得したりする、というのが基本的な BeautifulSoup の使い方となります。

BeautifulSoupでのタグの属性やテキストの取得方法

もちろん、BeautifulSoup には、もっと様々な使い方で HTML から目当てのデータを取得することが可能なのですが、今回は上記のような基本的な使い方のみで目当てのデータを取得するようにしていきます。

コメントの投稿操作

では、ここから実際にツールを開発していきたいと思います。まずはコメントの投稿操作を実施する関数を定義していきます。

コメント投稿操作時のリクエストとレスポンスを調べる で説明した通り、コメントの投稿操作を実施するためには、下記のような HTTP リクエストを送信する必要があります。

  • URLhttp://localhost:8000/forum/create/
  • メソッドPOST
  • ヘッダー:
    • Cookie: Set-Cookiecsrftoken
    • X-CSRFTokenSet-Cookiecsrftoken
  • ボディ(送信するデータ):
    • author フィールド:フォームの Author フィールドに入力された値
    • text フィールド:フォームの Author フィールドに入力された値

また、上記の★マーク部分の値は、事前に GET メソッドの HTTP リクエストを送信し、その応答となる HTTP レスポンスから取得する必要があります。そのため、下記の HTTP リクエストを事前に送信し、それに対する HTTP レスポンスを取得してから、上記の HTTP リクエストを送信してコメントの投稿操作を行います。

  • URLhttp://localhost:8000/forum/create/
  • メソッドGET

このコメントの投稿操作を実施する関数の例は下記の comment_create となります。comment_create には、第1引数でコメントの投稿者、第2引数でコメントの本文をそれぞれ文字列で指定する必要があります。

comment_create
import requests

scheme = 'http://'
hostname = 'localhost:8000'

def comment_create(author, text):
    # コメント投稿フォームのURLを作成
    url = scheme + hostname + '/forum/create/'

    # csrftokenの取得
    response = requests.get(url=url)

    # 送信するデータを作成
    post_data = {
        'author': author,
        'text': text
    }

    headers = {
        'X-CSRFToken': response.cookies['csrftoken']
    }

    # コメントの投稿を実施
    response = requests.post(
        url=url,
        data=post_data,
        headers=headers,
        cookies=response.cookies,
        allow_redirects=False
    )
    
    # コメント投稿結果を確認
    if response.status_code == 302:
        result = True
    else:
        result = False

    return result

ここまでの説明の通り、ポイントは最初に requests.get を実行して response を取得している点になります。この response は HTTP レスポンスであり、response.cookies が、そのレスポンスのヘッダーにおける Set-Cookie となります。そして、この Set-Cookie には csrftoken が設定されていることになります。

そのため、この response.cookies を、コメントの投稿操作を行う時に実行する requests.postcookies 引数にそのまま指定してやれば、下記を満たすことができることになります。

  • Cookie: Set-Cookiecsrftoken

さらに、response.cookies['csrftoken'] により、Set-Cookie に設定された csrftoken の値を取得することが可能です。 そのため、コメントの投稿操作を行う時に実行する requests.post の headers 引数に {'X-CSRFToken': response.cookies['csrftoken']} を指定するようにすれば、下記を満たすことができることになります。

  • X-CSRFTokenSet-Cookiecsrftoken

このように、requests.postcookies 引数と headers 引数を指定することで、ウェブアプリに「安全である」と判断される HTTP リクエストを送信することが可能となります。

コメント一覧取得の操作

続いて、コメント一覧の取得の操作を実施する関数を定義していきます。

前述の通り、コメント一覧は下記の HTTP リクエストの送信に対する HTTP レスポンスとして取得することが可能です。

  • URLhttp://localhost:8000/forum/list/
  • メソッドGET

ただし、このコメント一覧は HTML として取得されることになるので、コメントのみを扱うためには、その HTML を解析して必要なデータのみを抽出することが必要となります。

で、今回取得できる HTML の構造の場合は、下記のように検索を実施していくことで、最終的にコメントの本文とコメントの投稿者を取得することができます。

  1. table タグを検索
  2. 1. で見つかったタグ内から tbody タグを検索
  3. 2. で見つかったタグ内から全ての tr タグを検索
  4. 3. で見つかった各タグ内から全ての td タグを検索
  5. 4. で見つかった各タグのテキストを下記のように取得
    • 1つ目の td タグのテキスト:「コメント本文」として取得
    • 2つ目の td タグのテキスト:「コメント投稿者」として取得

今回定義する関数では、投稿済みの全コメントに対して「コメント本文」と「コメント投稿者」のそれぞれを値とする辞書を作成し、それらを要素とするリストを返却するようにしていきたいと思います。

このようなコメント一覧の取得操作を実施する関数の例は、下記の comment_list となります。また、get_list は、引数で指定された HTML から各コメントの投稿者と本文のみを抽出し、それらを値とする辞書のリストを返却する関数になります。

comment_list
import requests
from bs4 import BeautifulSoup

scheme = 'http://'
hostname = 'localhost:8000'

def get_list(html):
    # HTMLを解析
    soup = BeautifulSoup(html, 'html.parser')

    # tableタグを1つ取得
    table = soup.find('table')

    # 取得したタグ内のtbodyタグを1つ取得
    tbody = table.find('tbody')

    # 取得したタグ内のtrタグを全て取得
    trs = tbody.find_all('tr')

    result_list = []

    # 各trタグに対するループ
    for tr in trs:

        # trタグ内のtdタグを全て取得
        tds = tr.find_all('td')

        # 1つ目のtdタグのテキストを本文として取得
        text = tds[0].get_text()

        # 2つ目のtdタグのテキストを投稿者として取得
        author = tds[1].get_text()


        # 投稿者と本文の値をセットした辞書をリストに追加
        result_list.append(
            {
                'author': author,
                'text': text
            }
        )

    return result_list

def comment_list():
    # コメント一覧のURLを作成
    url = scheme + hostname + '/forum/list/'

    # コメント一覧を取得
    response = requests.get(url=url)

    # HTMLを解析してコメントのリストを取得
    comments = get_list(response.text)

    return comments

コメントの取得自体は requests.get で実施することになりますが、必要なデータのみを取得するために get_list 関数を実行するようにしています。get_list 関数では、tabletbodytr という風に、目当てのタグまで1段階ずつタグの検索領域を狭める形で必要なデータを抽出するようにしていますが、findfind_all を上手く使いこなすことで、もっと簡単に必要なデータのみを抽出することも可能です。また、HTML の各タグに id を設定すれば、id を指定して目当てのタグを一度の検索で取得することも可能となり、目当てのタグの取得を楽に実現することができるようになります。

このページでは、このあたりの BeautifulSoup の使い方の詳細に関しては説明しませんが、まずは BeautifulSoup を利用することで、HTML の解析・目当てのタグの取得や必要なデータの抽出を行うことが可能であることは是非覚えておいてください。

ツール(CUI)のスクリプト

先ほど示した関数を含め、コメントの投稿操作及びコメント一覧の取得操作を行うツールのスクリプトを下記に示しておきます(分割して示した関数を1つのコードにまとめ、さらに main 関数を追加しただけです)。

request_tool_cui.py
import requests
from bs4 import BeautifulSoup

scheme = 'http://'
hostname = 'localhost:8000'

def get_list(html):
    # HTMLを解析
    soup = BeautifulSoup(html, 'html.parser')

    # tableタグを1つ取得
    table = soup.find('table')

    # 取得したタグ内のtbodyタグを1つ取得
    tbody = table.find('tbody')

    # 取得したタグ内のtrタグを全て取得
    trs = tbody.find_all('tr')

    result_list = []

    # 各trタグに対するループ
    for tr in trs:

        # trタグ内のtdタグを全て取得
        tds = tr.find_all('td')

        # 1つ目のtdタグのテキストを本文として取得
        text = tds[0].get_text()

        # 2つ目のtdタグのテキストを投稿者として取得
        author = tds[1].get_text()


        # 投稿者と本文の値をセットした辞書をリストに追加
        result_list.append(
            {
                'author': author,
                'text': text
            }
        )

    return result_list

def comment_list():
    # コメント一覧のURLを作成
    url = scheme + hostname + '/forum/list/'

    # コメント一覧を取得
    response = requests.get(url=url)

    # HTMLを解析してコメントのリストを取得
    comments = get_list(response.text)

    return comments

def comment_create(author, text):
    # コメント投稿フォームのURLを作成
    url = scheme + hostname + '/forum/create/'

    # csrftokenの取得
    response = requests.get(url=url)
    csrftoken = response.cookies['csrftoken']

    # 送信するデータを作成
    post_data = {
        'author': author,
        'text': text
    }

    headers = {
        'X-CSRFToken': csrftoken
    }

    # コメントの投稿を実施
    response = requests.post(
        url=url,
        data=post_data,
        headers=headers,
        cookies=response.cookies,
        allow_redirects=False
    )
    
    # コメント投稿結果を確認
    if response.status_code == 302:
        result = True
    else:
        result = False

    return result


def main():
    author = input('投稿者:')
    comment = input('本文:')

    if not comment_create(author, comment):
        print('コメント投稿に失敗しました')
        return
    
    comments = comment_list()
    print(comments)


main()

ツール(CUI)の動作確認

続いて、先ほど作成したツールの動作確認を行っておきましょう!

まず、先ほど示したソースコードを request_tool_cui.py という名前で保存してください。

続いて、ターミナルやコマンドプロンプト等のコンソールアプリを2つ起動し、一方のコンソールアプリで ウェブアプリの作成と起動 で開発したウェブアプリを起動してください(既に起動済みであれば、この手順は不要です)。ウェブアプリの起動は、プロジェクトフォルダの中で下記を実行することで実施することができます。

% python manage.py runserver

続いて、もう一方のコンソールアプリで、request_tool_cui.py を保存したフォルダに移動して下記コマンドを実行してください。これにより、先ほど作成したツールが起動することになります。

% python request_tool_cui.py

ツールが起動すると、下記のようにコメント投稿者と本文の入力が促されますので、適当なものを入力してエンターキーを押してください。

投稿者:YamadaHanako
本文:HelloWorld

これにより、これらの入力値を引数として comment_create が実行され、コメント投稿操作を実施する HTTP リクエストが送信されることになります。さらに、そのコメント投稿操作に成功した場合、続いて comment_list が実行されてコメント一覧の取得が実施されます。そして、最後に、下記のような各コメントの本文と投稿者を値とする辞書のリストが標準出力に出力されます。この出力されるリストの中に、これまでに投稿したコメントや、先ほどツールから入力したコメントの投稿者・本文が含まれていることが確認できると思います。

[{'author': 'Yamada Taro', 'text': 'こんにちは!'}, {'author': 'Tanaka Jiro', 'text': 'こんばんは!'}, {'author': 'YamadaHanako', 'text': 'HelloWorld'}]

また、下記の URL をウェブブラウザで開いてコメント一覧の内容を確認すれば、先ほど標準出力に出力された結果が、ウェブアプリに表示されるコメント一覧と一致していることが確認できると思います。

http://localhost:8000/forum/list/

つまり、先ほど標準出力に出力されたリストはウェブアプリで管理されているコメントの一覧であり、HTTP リクエストの送信によって、コメントの一覧の取得操作が実施できていることが確認できたことになります。さらに、リストの最後の要素はツールから HTTP リクエストの送信によって投稿したコメントとなりますので、これより、HTTP リクエストの送信によってコメントの投稿操作が実施できたことが確認できたことになります。

このような動作確認結果から、ウェブアプリは、HTTP リクエストの送信によって操作することが可能であることを実感していただけたのではないかと思います。

ウェブアプリ操作用 GUI アプリの開発

次は、先ほど開発したツールを GUI 化(ユーザーインターフェースをグラフィカルにする)していきたいと思います。

ウェブアプリを操作する GUI アプリを開発し、それでウェブアプリを実際に操作してみることで、ウェブブラウザ以外の GUI アプリからウェブアプリを操作可能であること、さらに、それを簡単に自身の手で開発できることを、より深く実感していただけると思います。

今回は、GUI 化は tkinter によって行います。tkinter に関しては下記ページで紹介していますので、興味のある方は下記ページを参照してください。

tkinter解説ページのアイキャッt PythonでTkinterを使ってめちゃくちゃ簡単にGUIアプリを作る

簡単な例を示したいため、今回はコメントの投稿操作のみを行うアプリを開発することとしたいと思います。また、先ほど示した comment_create はそのまま利用します。なので、プログラムの形態は異なりますが、結局は先ほど動作確認したツールと同様の HTTP リクエストの送信によってウェブアプリの操作を行うことになります。

ウェブアプリ操作用 GUI アプリのソースコード

早速、ウェブアプリ操作用 GUI アプリのソースコードを紹介したいと思います。上記のようなアプリは、次のソースコードにより実現することができます。

request_tool_gui.py
import requests
import tkinter
from tkinter import messagebox

scheme = 'http://'
hostname = 'localhost:8000'

def comment_create(author, text):
    # コメント投稿フォームのURLを作成
    url = scheme + hostname + '/forum/create/'

    # csrftokenの取得
    response = requests.get(url=url)
    csrftoken = response.cookies['csrftoken']

    # 送信するデータを作成
    post_data = {
        'author': author,
        'text': text
    }

    headers = {
        'X-CSRFToken': csrftoken
    }

    # コメントの投稿を実施
    response = requests.post(
        url=url,
        data=post_data,
        headers=headers,
        cookies=response.cookies,
        allow_redirects=False
    )
    
    # コメント投稿結果を確認
    if response.status_code == 302:
        result = True
    else:
        result = False

    return result

class RequestTest:
    def __init__(self, master):
        self.master = master

        self.create_widgets()

    def create_widgets(self):
        self.label_author = tkinter.Label(
            self.master,
            text='投稿者',
            font=('', 20)
        )
        self.label_author.grid(column=0, row=0, padx=10, pady=10)

        self.label_text = tkinter.Label(
            self.master,
            text='本文',
            font=('', 20)
        )
        self.label_text.grid(column=0, row=1, padx=10, pady=10)

        self.entry_author = tkinter.Entry(
            self.master,
            font=('', 20)
        )
        self.entry_author.grid(column=1, row=0, padx=10, pady=10)

        self.entry_text = tkinter.Entry(
            self.master,
            font=('', 20)
        )
        self.entry_text.grid(column=1, row=1, padx=10, pady=10)

        self.send_button = tkinter.Button(
            self.master,
            text='送信',
            font=('', 20),
            command=self.post
        )
        self.send_button.grid(column=0, columnspan=2, row=3, padx=10, pady=10)

    def post(self):
        author = self.entry_author.get()
        text = self.entry_text.get()

        if comment_create(author, text):
            messagebox.showinfo(
                title='コメントの投稿結果',
                message='コメントの投稿に成功しました!'
            )
        else:
            messagebox.showerror(
                title='コメントの投稿結果',
                message='コメントの投稿に失敗しました...'
            )


main_window = tkinter.Tk()

app = RequestTest(main_window)

main_window.mainloop()

前述の通り、コメントの投稿操作を行う comment_create は、コメントの投稿操作 で示したものと同じです。

この関数を、tkinter を利用して、送信 ボタンがクリックされたときに 投稿者 の入力欄と 本文 の入力欄に入力された文字列を引数に指定して実行するようにしています。

このページでは tkinter に関する説明は省略させていただきますが、tkinter の使い方に関しては本サイトの下記で詳しく解説していますので、興味のある方は是非読んでみてください。

https://daeudaeu.com/category/python/tkinter/tkinter_tutorial/

ウェブアプリ操作用 GUI アプリの動作確認

続いて、このスクリプトで起動する GUI アプリの動作確認を行っていきたいと思います。

上記のソースコードを request_tool_gui.py という名前で保存し、ツール(CUI)の動作確認 のとき同様に、ウェブアプリを起動した状態でコンソールアプリから下記コマンドでスクリプトを実行してみてください。

% python request_tool_gui.py

すると、下図のようなウィンドウが表示されると思います。

ウェブアプリを操作するGUIアプリの見た目

そして、このウィンドウの各種フィールドに文字列を入力し、さらに 送信 ボタンをクリックすれば、ウェブアプリに対して HTTP リクエストが送信されてコメントの投稿操作を実施することができます。

ただ、このアプリでは、投稿したコメントを確認することができないので、コメントが投稿できたかどうかはウェブブラウザで下記 URL を開いて確認してみてください。おそらく、各種フィールドに入力したコメントが投稿されていることを確認できるはずです。

http://localhost:8000/forum/list/

今回開発したアプリは見た目も悪く、機能的にも陳腐なものになりますが、それでも、上記の動作確認を通じて、ウェブアプリがウェブブラウザ以外の GUI アプリからも操作可能だという点を感じ取っていただけたのではないかと思います。

また、今回は tkinter を利用して GUI アプリを開発しましたが、もちろん他のライブラリ・さらには他の言語を利用したアプリからもウェブアプリの操作は可能です。なので、適切な HTTP リクエストの送信を行うようにさえすれば、当然 iOS アプリや Android アプリからも、あなたが開発したウェブアプリの操作が可能ということになります。

ウェブアプリの特徴の1つは、ここまで説明してきたように、HTTP リクエストの送信によって操作できるという点にあります。なので、リクエストの送信さえ行えば、好きなようにフロントサイド(UI)を開発することが可能です。ウェブブラウザからしか操作できなくて物足りなさを感じていた方もおられるかもしれませんが、そうではないので安心してください。

ただし、ウェブアプリは、ウェブブラウザから操作できるという点も重要な特徴の1つであり、これによってユーザーの使用する環境に関わらずウェブアプリの操作が行えるようになっています。なので、まずは、ウェブブラウザから操作されることを前提にウェブアプリを作りこんでいき、ある程度ウェブアプリが開発できたタイミングで、ウェブブラウザ以外からウェブアプリを操作するツールやアプリの開発に取り組んでいけば良いのではないかと思います。

掲示板アプリを HTTP リクエストで操作する

先ほども簡易的な掲示板アプリを作成し、それを HTTP リクエストで操作するツール・アプリを開発してきましたが、次は Django 入門 の連載を通じて開発してきている「掲示板アプリ」を HTTP リクエストで操作する例を示していきたいと思います。

どちらも掲示板アプリであり、ここでも実現するのは、基本的にはコメントの投稿操作とコメント一覧の取得操作となります。なので、Django 入門 の連載を通じて開発してきている「掲示板アプリ」においても、今まで説明してきた内容と同様の手順で、HTTP リクエストでの操作を実現することが可能です(送受信する HTTP リクエストや HTTP レスポンスが多少異なるので、それに合わせた変更は必要となります)。

ただ、今回の操作対象とする掲示板アプリはログイン機能を備えており、このログインを実施しないとコメントの投稿操作やコメント一覧の取得は実施できません。なので、これらの操作を行う前にログイン操作が必要となります。そして、このログインした状態を維持しながら、コメントの投稿操作やコメント一覧の取得を実施する必要があるという点がポイントとなります。

また、今回操作対象とするウェブアプリは、前回の連載の 掲示板アプリで静的ファイルを扱う で開発した掲示板アプリとなります。この掲示板アプリのプロジェクトは下記で公開していますので、必要に応じてこちらからプロジェクトを取得して動作確認に利用してください。

https://github.com/da-eu/django-introduction/releases/tag/django-staticfile

スポンサーリンク

掲示板アプリを操作するツール

ということで、早速掲示板アプリの操作を行うツールのソースコードを紹介していきます。前述の通り、今回ツールから実施できるようにする操作はコメントの投稿とコメント一覧の取得、さらに、これらを行うために事前に実施するログインとなります。

ツールのスクリプト

このツールのスクリプトは下記のようになります。

forum_request.py
import requests
from bs4 import BeautifulSoup

scheme = 'http://'
hostname = 'localhost:8000'

def get_list(html):
    # HTMLを解析
    soup = BeautifulSoup(html, 'html.parser')

    # tableタグを1つ取得
    table = soup.find('table')

    # 取得したタグ内のtbodyタグを1つ取得
    tbody = table.find('tbody')

    # 取得したタグ内のtrタグを全て取得
    trs = tbody.findAll('tr')

    result_list = []

    # 各trタグに対するループ
    for tr in trs:

        # trタグ内のtdタグを全て取得
        tds = tr.findAll('td')

        # 1つ目のtdタグのテキストを本文として取得
        text = tds[0].get_text()

        # 2つ目のtdタグのテキストを投稿者として取得
        author = tds[1].get_text()


        # 投稿者と本文の値をセットした辞書をリストに追加
        result_list.append(
            {
                'author': author,
                'text': text
            }
        )

    return result_list

def comment_list(session):
    # コメント一覧のURLを作成
    url = scheme + hostname + '/forum/comments/'

    # コメント一覧を取得
    i = 1
    while True:
        url_p = url + '?p=' + str(i+1)
        response = session.get(url=url_p)
        status_code = response.status_code
        
        if status_code != 200:
            break
        
        html = response.text
        i += 1
        

    # HTMLを解析してコメントのリストを取得
    comments = get_list(html)

    return comments

def comment_create(session, text):
    # コメント投稿フォームのURLを作成
    url = scheme + hostname + '/forum/post/'

    # csrftokenを取得
    response = session.get(url=url)

    headers = {
        'X-CSRFToken': response.cookies['csrftoken']
    }

    # 送信するデータを作成
    post_data = {
        'text': text
    }

    # コメントの投稿を実施
    response = session.post(
        url=url,
        data=post_data,
        headers=headers,
        allow_redirects=False
    )
    
    # コメント投稿結果を確認
    if response.status_code == 302:
        result = True
    else:
        result = False

    return result

def login(session, username, password):
    # ログインフォームのURLを作成
    url = scheme + hostname + '/forum/login/'

    # csrftokenを取得
    response = session.get(url=url)

    headers = {
        'X-CSRFToken': response.cookies['csrftoken']
    }

    # 送信するデータを作成
    post_data = {
        'username': username,
        'password': password
    }

    # ログインを実施
    response = session.post(
        url=url,
        data=post_data,
        headers=headers,
        allow_redirects=False
    )
    
    # ログイン結果を確認
    if response.status_code == 302:
        result = True
    else:
        result = False

    return result

def main():
    
    # セッションオブジェクトを生成
    session = requests.Session()

    # ログインを最初に実施
    username = input('ユーザー名:')
    password = input('パスワード:')
    
    if not login(session, username, password):
        print('ログインに失敗しました')
        return

    comment = input('本文:')

    # クッキーを保持したセッションオブジェクトでコメント投稿
    if not comment_create(session, comment):
        print('コメント投稿に失敗しました')
        return
    
    # クッキーを保持したセッションオブジェクトでコメント一覧取得
    comments = comment_list(session)

    print(comments)


main()

ログイン状態を維持したままのリクエストの送信

ウェブアプリの操作を行うツールの開発例 で開発したツールとの決定的な違いは、HTTP リクエストを送信するのを Session クラスのオブジェクトから実施するようにした点になります。

ウェブアプリの操作を行うツールの開発例 では、下記のように requests ライブラリが提供する関数を実行するようにしていましたが、

  • GET メソッドの HTTP リクエストの送信:requests.get
  • POST メソッドの HTTP リクエストの送信:requests.post

今回は下記のように Session クラスのインスタンスである session から Session クラスのメソッドを実行するようにしています。

  • GET メソッドの HTTP リクエストの送信:session.get
  • POST メソッドの HTTP リクエストの送信:session.post

Django で開発したウェブアプリのログインでは、ログインに成功した場合、ログイン操作を行う HTTP リクエストに対する HTTP レスポンスの Set-Cookie に、ログイン中であることを示すための sessionid がセットされるようになります。なので、その sessionidCookie にセットした HTTP リクエストを送信することで、そのリクエストの送信者がログイン中であると判定され、ログイン中でないと実施不可な操作も実施できるようになります。

ログインを維持した状態のウェブ操作の実現方法の説明図

ただ、ログイン後の全ての HTTP リクエストの送信時に上記のような Cookie の設定が必要となって面倒です。

この面倒さを解消するために、上記のスクリプトでは Session クラスのオブジェクトからメソッドを実行して HTTP リクエストを送信するようにしています。

Session クラスのインスタンスは、受け取った HTTP レスポンスの Set-Cookie の値を保持し、次以降の HTTP リクエストの送信時には、その保持した Cookie を送信するようになっています。なので、ウェブアプリの操作を行うツールの開発例 で示したスクリプトのように、HTTP リクエストの送信時に実行する関数の cookies 引数に、事前に受け取った HTTP レスポンスの Set-Cookie を指定するような実装が不要となります。

requests.Sessionクラスの説明図

つまり、Session クラスのインスタンスからメソッドを実行させてログインを実施すれば、後は、そのインスタンスから HTTP リクエストを送信すれば、Cookie 引数を指定しなくても、CookiesessionId がセットされた状態のリクエストが送信されることになります。そして、HTTP リクエストの送信者はログイン中であるとウェブアプリに判断されることになります。

また、Session クラスのインスタンスでは、sessionId だけでなく、HTTP レスポンスで受け取った Set-Cookie そのものが保持されるため、 csrftoken の値も保持されることになります。なので、ウェブアプリの操作を行うツールの開発例 で示したスクリプトも、Session クラスのインスタンスを利用することでもっとシンプルなものにすることが可能です。

ウェブアプリに合わせた変更

後は、ウェブアプリの操作を行うツールの開発例 で示したスクリプトとの違いを簡単に説明しておくと、まずログイン操作を実施しているのは login 関数で、送信するデータは異なるものの、基本的にはコメントの投稿時と同様の処理でログインも実現することができます。

さらに、掲示板アプリでは、コメントの投稿者に関しては「リクエストを送信してきたユーザー」が自動的にセットしてデータベースに保存されるようになっているため、コメント投稿時に送信するデータには author フィールドは不要となります。

また、掲示板アプリでは、下記ページで解説しているページネーションを利用し、コメントを複数のページに分割して表示するようにしています。最後に投稿したコメントは最後のページに表示されるため、コメントの取得は、最後のページに表示されるコメントに対して実施するようにしています(HTTP リクエストを、404 エラーの HTTP レスポンスが返却されてくるまで繰り返し行い、最後のページに表示されるコメントの一覧のみを取得している)。

Djangoにおけるページネーションの解説ページアイキャッチ 【Django入門13】ページネーションの基本

このように、ウェブアプリの操作を行うツールの開発例 で開発したウェブアプリと、今回操作対象としているウェブアプリとで、受信することを期待している HTTP リクエストや送信する HTTP レスポンスが違うため、この違いに応じて、ウェブアプリを操作する側のプログラムも、送信する HTTP リクエストや HTTP レスポンスの扱い方の変更が必要となります。

ツールの動作確認

次に、ツールを使って実際にウェブアプリを操作してみましょう!

動作確認の準備

まず、先ほど示したスクリプトを forum_request.py というファイル名で保存してください。

続いて、コンソールアプリを2つ起動し、一方のコンソールアプリで掲示板アプリを起動してください。掲示板アプリの test_project フォルダ(上側の階層の test_project)に移動し、下記コマンドを実行することで掲示板アプリが起動することになります。

% python manage.py runserver

ただし、初めて掲示板アプリを利用するという方は、データベースおよびテーブルを作成するため、上記のコマンドを実行する前に次の2つのコマンドを実行しておく必要があります。

% python manage.py makemigrations
% python manage.py migrate

また、ツールで操作を行うためには、事前にユーザー登録を実施しておく必要があります。このユーザー登録の手順については、下記ページの 動作確認 の節で解説していますので、この節を参考にしてユーザー登録を行っておいてください。

ログインの実現方法の解説ページアイキャッチ 【Django入門10】ログイン機能の実現

ログイン

掲示板アプリが起動したら(必要に応じてマイグレーションとユーザー登録も必要)、次は、もう一方のコンソールアプリで forum_request.py を保存したフォルダに移動し、下記コマンドを実行してください。

% python forum_request.py

このコマンドを実行すると、まずログインを行うためのユーザー名とパスワードが入力されるようになっています。ここには、掲示板アプリで登録したユーザーのユーザー名とパスワードを入力してください。

ユーザー名:username
パスワード:password

入力したユーザー名とパスワードでログインに成功した場合は、下記のように、コメントの本文の入力受付が行われるようになっています。

本文:

ログインに失敗した場合は、下記のように、ログインに失敗したことを示すメッセージが出力されてツールが終了するようになっていますので、この場合はユーザー名とパスワードの見直しを行ってください(パスワード等を忘れた場合は、ウェブブラウザから新たにユーザーを登録し、その登録したユーザーでログインするのが早いと思います)。

ログインに失敗しました

また、下記のような例外が発生した場合、そもそも掲示板アプリが起動していない可能性があるので、前述で示した runserver コマンドが実行中であるかどうかを確認してみてください。

対象のコンピューターによって拒否されたため、接続できませんでした。

コメントの投稿とコメント一覧の取得

前述の通り、ログインに成功した場合は、下記のように投稿するコメント本文の入力受付が行われます。次は、ここに文字列を入力し、実際にコメントの投稿を行ってみてください。

本文:

本文を入力してエンターキーを押せば、コメント投稿操作を行う HTTP リクエストが送信され、コメントの投稿が行われることになります。さらに、続けてコメント一覧の取得操作を行う HTTP リクエストが送信され、取得したコメントの一覧が、辞書を要素とするリストとして標準出力に出力されます。

[{'author': 'TanakaJiro', 'text': 'Good bye'}, {'author': 'YamadaHanako', 'text': 'Hello world'}]

この出力されるリストの最後が、投稿したコメントのものと一致していれば、コメントの投稿操作及びコメントの一覧取得操作を HTTP リクエストの送信によって実施できたことが確認できたことになります。

前述の通り、この掲示板アプリでは、投稿済みコメントが複数のページに分割して表示されるようになっており、先ほど作成したツールからは最後のページに表示されるコメントの一覧のみの取得が行われることになります。なので、投稿済みのコメントに対して取得できるコメントの数が少ない場合がありますが、そういう作りとしているだけで、ツールやウェブアプリに不備があるというわけではないので安心してください。

また、今回はコメントの投稿とコメント一覧の取得(&ログイン)のみを実施するツールの紹介を行いましたが、もちろん、掲示板アプリに実装されている機能(例えばコメントの更新やコメントの削除など)であれば、それらも HTTP リクエストの送信によって実施することが可能です。

現状の掲示板アプリの課題

ということで、Django 入門 の連載を通じて開発してきている「掲示板アプリ」も HTTP リクエストの送信によって操作可能であることが確認できました。もちろん、この掲示板アプリだけでなく、どんなウェブアプリでも HTTP リクエストの送信によって操作可能です。そもそも、HTTP リクエストの送信によって操作可能でなければ、ウェブブラウザからの操作も行えないことになりますので…。

ただ、この掲示板アプリのように、HTTP リクエストの応答となる HTTP レスポンスによって取得できるデータが HTML の場合、その HTML を解析して必要なデータを抽出する処理が必要となり、ウェブブラウザ以外からのウェブアプリの操作の実装が複雑になります。

なので、ウェブブラウザ以外からの操作を想定するウェブアプリでは、HTML 以外のデータを取得可能な API を用意しておくことが多いです。例えば、その API から JSON 形式のデータを返却できるようにしておき、さらに必要なデータのみをそのデータに含ませるようにしておけば、HTML の解析が不要になってウェブブラウザ以外からの操作が容易になります。また、データの送信を行う API においては、送信するデータも JSON 形式とすることで、ウェブアプリの入力と出力のデータの形式が統一され、さらに操作しやすいウェブアプリとなります。

HTTPリクエストとHTTPレスポンスのボディをJSONとする様子

そして、このような API を公開することで、そのウェブブラウザ操作用のツールや iOS アプリ・Android アプリも開発が容易になりますし、ウェブブラウザでのページ表示においても、JavaScript を導入して API を利用することで、ページ内の特定のデータを定期的に更新したり、さらに JavaScript からのデータの送信も容易に実現できるようになります。要は、API を提供することで、ウェブブラウザ以外からの操作が容易となります。

ということで、次は、この API を Django で開発するウェブアプリから提供する方法について解説していきたいと思います!

スポンサーリンク

まとめ

このページでは、ウェブアプリのウェブブラウザ以外からの操作について解説しました!

ウェブアプリは、HTTP リクエストの送信によって操作することが可能で、この特徴を利用することで、ウェブアプリを iOS アプリや Android アプリ等からも操作することができるようになります。このページの内容で一番覚えておいていただきたいのは、この点になります。

また、特に Django で開発するウェブアプリは CSRF 対策が施されているため、データの送信操作を行う際にはヘッダー・クッキーを適切に設定して HTTP リクエストを送信する必要があります。このあたりのポイントもしっかり覚えておきましょう!

ただし、特にウェブアプリに対してデータの取得操作を行う場合、取得できるデータが HTML だと、その操作側でのデータの扱いが複雑になります。具体的には、その HTML を解析して必要なデータを取得する処理が必要となります。

なので、ウェブブラウザ以外からの操作を想定したウェブアプリでは API を提供し、その API を使ってウェブアプリを操作してもらうようにすることが多いです。次は、この API について解説していきますので、是非次回の連載も読んでみてください!

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