![見出し画像](https://assets.st-note.com/production/uploads/images/20545178/rectangle_large_type_2_b96d8e8491f6b6d2c24616255b8c01ea.jpeg?width=1200)
HTTPリクエストをプログラムする(Using Python to Access Web Data: Week 3)
引き続き、ミシガン大学がCoursera上で開講しているPython for Everybody Specializationの第3コース、Using Python to Access Web Dataを受講した記録です。前回のWeek 2では、正規表現を学びました。
Week 3では、Pythonにあるsocketライブラリを使ってネットワークに接続し、サーバ上のデータを読み取るプログラミングを学んでいきます。
<テキストの範囲>
Chapter 12: Networked Programs
1.ネットワーク・アーキテクチャ概論
ネットワークを介したデータのやり取りは、ユーザ側から見てアプリケーションを皮切りに幾つもの層でのデータ変換が行われ、通信できる形でネットワーク上を通っていきます。いわゆるOSI 7階層参照モデルと言われるものです。詳しくは以下のリンクをご参照ください。
実際のデータの送受信はIP(internet protocol)という形式を通じてで行われますが、IPにおける通信はデータが欠損することがあり、欠損しているデータは何か、欠損しているものを再送してもらうなどといった制御が必要になります。それが、トランスポート層の役割であり、トランスポート層で取り扱われる通信方式(TCP: Transport Control Protocol)が重要になってきます。(かなりざっくりとした説明ですが…)
この講義では、ネットワークに関する深い議論は避け、TCPという方式でネットワークに接続し、相手側のアプリケーションとやり取りをすることを考えていきます。
ネットワークに接続するための「電話機」となるのが、ソケットと呼ばれるものです。アプリケーションから送信されるデータやリクエストは、ソケットを使って遠く離れたサーバ等に送られます。
電話機を使って、サーバに電話をかけるがごとく通信のリクエストをするためには、電話番号、つまりアドレスが必要となります。さらに、どんな種類の通信をするかによって、内線番号、ポートが必要となります。通信しようとしている先がWebサーバであるか、メールサーバであるかによって、ポートは異なります。
電話をかける場合:電話番号を押す→内線番号を押す→応答する
通信をする場合:アドレスを指定する→ポートを指定する→応答する
基本的に、HTTPという通信を行ってWebサーバに接続する場合は80というポートが用いられます(8080が使われることもあります)。よりセキュアな通信形式であるHTTPS通信の場合は、ポート443が使われることが多いようです。
この週で取り扱われるHTTPとTCP接続に関する詳細は、以下のページが概念的に分かりやすいかと思います。
2.Pythonでソケット通信をやってみる
Pythonに備わっているsocketライブラリをインポートすると、数行で通信ができるプログラムが書けます。
import socket
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #...[1]
mysock.connect(('data.******.org', 80)) #...[2]
なんとこれだけです。簡単ですね。[1]では、mysockというオブジェクトを作成しています。いわゆる電話機を作る命令です。
[2]で実際に接続をしています。connectメソッドはホスト(アドレス)とポートを指定します。この例では、data.******.orgというホストのWebサーバであるポート80に接続しています。ただし、これだけでは電話をかけただけですので、実際にデータのやり取りは行っていません。
実際にどのような通信をやるかは、アプリケーションによって異なります。つまり、先に述べたOSI 7階層モデルのアプリケーション層でのデータ通信の方法に依存します。Webサーバに接続し、Webに関するデータ(いわゆるハイパーテキスト)の通信方法を決めているのが、HTTP(Hypertext Transfer Protocol)です。これにより、HTMLやRSSなど、HTTP通信でさまざまなデータが送受信できることになります。ホームページをリクエストするURL(Uniform Resource Locator)と呼ばれる表記法は世界共通で、
http://www.google.com/index.html
のように、プロトコル名、ホスト名、ファイル名の形式で記述されます。
では、実際にブラウザ上ではどのようなデータのやり取りが行われているのでしょうか?ユーザがブラウザ上でリンクのボタン(例えば筆者のnoteのトップページ)をクリックすると、GETという命令がブラウザ上で処理されます。すると、ソケットを通じてWebサーバにアクセスし、指定されたURLのデータを取得をリクエストします。Webサーバは、リクエストに応じてデータを同じソケットでブラウザに返します。HTMLファイルであれば、タグが付けられたテキストファイルになります。実際のHTMLファイルは、以下のような構成になっています(出典:https://www.w3schools.com/html/)
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
3.PythonでHTTPリクエストを作ってみる
Pythonプログラムでは、socketライブラリに送信や受信をするメソッドも完備されています。先のセクションで電話機を作り、電話をかけるところまでできましたので、次はいよいよWebサーバにHTTPリクエストをし、受信したデータを表示するところを学びましょう。
電話をかけた後のGETリクエストは、以下のように作ります。
GET (URL名) HTTP1.0\r\n\r\n
\r\n\r\nというのは、コマンドラインに命令を打ち込むように、GETの命令を書き込んだ後、改行を2回繰り返す指示です。具体的なプログラム例は、以下のとおりです。
import socket
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('data.******.org', 80))
cmd = 'GET http://data.******.org/test.txt HTTP1.0\r\n\r\n'.encode() #...[1]
mysock.send(cmd) #...[2]
while True:
data = mysock.recv(512) #...[3]
if (len(data) < 1): #...[4]
break
print(data.decode()) #...[5]
mysock.close() #...[6]
プログラムが少し長くて大変ですが、頑張りましょう。
上の3行は、先のセクションと同じです。[1]の変数cmdでは、HTTP形式でのデータを取得するための準備を行っています。.encode()という指示と、[5]でみられる.decode()に関する説明は次のセクションで行います。
[1]で作成した命令文を実際に[2]で送信します。次に、無限ループを構成している中で[3]でデータをWebサーバから受信します。
[3]にあるrecv()の中の数値は、受け取るデータのサイズです。すなわち、どれくらいの大きさのデータを一度に受信するかというものです。ひとまず512という数値を入れていますが、PythonのHOWTOドキュメントの解説によれば4096や8192が一般的に使われているようです。
ファイルが終端まで到達したかは、[4]で判定しています。受信したデータの長さが1未満(つまり受信するファイルはもうない状態)になれば、breakで無限ループを抜け出します。
[5]の.decode()はひとまず無視して、受信するデータがまだあり、無限ループが続いている限りその内容をprintで表示していきます。
Webサーバとの通信を終えるには、[6]のようにソケットのcloseメソッドを用いて、「受話器を置」きます。
4.ブラウザ上でどのようなやり取りが行われているか見る
Chromeブラウザでは、非常に便利な機能として「デベロッパー ツール」というものが備わっています。
これを用いて、Webブラウザが実際にどのような命令を出しているのかを見ることができます。デベロッパー ツールを開いた状態でメニュー上のNetworkを選択し、その下のHeadersを選択すると、General上でリクエストしたURL、リクエストしたメソッド(GETと書かれているはず)、ステータスコードやアドレスなどが記載されています。
実際にWeb上からデータを取得する際には、HTMLやCSSなどのファイルには記載されていないメタデータと呼ばれるデータがファイルより先に受信しています。このツールを用いて、GETリクエストをした後で実際にどのようなメタデータを受信しているかを確認することができます。
今回のエントリはここまで。あまりプログラミングした感じはしませんでしたが、後の講義で行き詰った時に何度も振り返った非常に重要な講義でした。
次のWeek 4ではWeb上からデータを自動取得するエンジンを作っていきます。それでは、次回のエントリもお楽しみに!
この記事が気に入ったらサポートをしてみませんか?