HTTPとAJAXのおさらい
はじめに
ここらへんの知識が足りてないことを痛感することが多いので、ここではHTTPとAJAXのおさらいをまとめておく。参考文献はAutomated Data Collection with R。
HTTP
Webサイトからデータを得るということは、webサービスとサーバーが通信していることになる。この通信時の規格がHTTP(Hypertext Transfer Protocol)。クライアントとサーバーの基本的なやり取りをwww.r-datacollection.coml
を例にまとめる。このサイトにアクセスすると、ブラウザがHTTPクライアントとして機能し、クライアントDNSサーバーに、渡されているURLを更にわたすことで、www.r-datacollection.com
に対応するIPアドレスを受け取る。このIPアドレスを使って、TCP/IP経由でHTTPリクエストを送り、要求されたHTTPサーバーはHTTPレスポンスを返すことで接続を確立する。www.r-datacollection.com.index.html
であれば、ブラウザはindex.html
を要求し、これが返されることで、ブラウザの画面に表示される。
HTTPメッセージ
www.r-datacollection.com
を例に、HTTPメッセージを見てみる。まず、www.r-datacollection.com
をIPアドレスに変換し、接続をポート80で確立。その後に、サーバーに対して、リクエストGETを送っている。HTTP/1.1 200 OK
の部分から、HTTPレスポンスが返り、コンテンツが返され、Connection #0
でクライアントが接続を閉じる。
$ curl -v http://www.r-datacollection.com * Trying 64.111.125.36:80... * TCP_NODELAY set * Connected to www.r-datacollection.com (64.111.125.36) port 80 (#0) > GET / HTTP/1.1 > Host: www.r-datacollection.com > User-Agent: curl/7.65.3 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Sun, 15 Mar 2020 01:49:21 GMT < Server: Apache < Upgrade: h2 < Connection: Upgrade < Vary: Accept-Encoding,User-Agent < Transfer-Encoding: chunked < Content-Type: text/html; charset=UTF-8 < <!DOCTYPE html> <html> <head> 【略】 </html> * Connection #0 to host www.r-datacollection.com left intact
HTTPメッセージのテンプレ
HTTPメッセージのリクエストはこうなっている。
HTTPメッセージのレスポンスはこうなっている。
HTTPのリクエスト
下記が代表的なHTTPのリクエスト。
リクエスト | 内容 |
---|---|
GET | サーバーからリソースを取得 |
POST | メッセージボディを使って、データないし、ファイルを送り、サーバーからリソースを取得 |
HEAD | GET リクエストと同じ。開始行とヘッダーのみ取得 |
PUT | リクエストメッセージのボディをサーバーに保存 |
DELETE | サーバーからリソースを削除 |
TRACE | メッセージがサーバーに届く経路を取得 |
CONNECT | ネットワークの接続を確立 |
OPTIONS | サポートされるHTTPメソッドを取得 |
最も代表的なのはGRTとPOSTで、ボディの指定が異なる。GETはボディに何も指定しないが、POSTはデータを送信するためにボディを利用する。HTMLドキュメントなどを貰う場合はGETで間に合うが、フォームの入力が必要な場合などはPOSTでデータを送信する。
HTTPを扱うRパッケージ
代表的なHTTPを扱うRパッケージはRCurl
とhttr
パッケージの2つ。RでWebの通信をできる背景にはCで書かれているlibcurl
ライブラリの存在が大きい。libcurl
ライブラリをRで使えるようにしているのが、RCurl
パッケージ。このおかげで、HTTPヘッダの指定、URLエンコードの解釈、webサーバーのデータストリーム処理、SSL接続、プロキシへの接続、ハンドル認証などができる。
GETメソッド
RCurl
パッケージのget**()
で、HTTPリクエストのGETを利用できる。バイナリデータが対象であれば、getBinaryURL()
を使えばいい。
library(RCurl) cat(RCurl::getURL("http://www.r-datacollection.com/materials/http/helloworld.html")) <html> <head><title>Hello World</title></head> <body><h3>Hello World</h3> </body> </html> bin_png <- RCurl::getBinaryURL("http://www.r-datacollection.com/materials/http/sky.png") bin_png %>% head(, 10) [1] 89 50 4e 47 0d 0a writeBin(bin_png, "sky.png")
コンテンツによっては、下記のようにフォームに値を入れて送信して、データを取得する場合がある。
HTMLはこうなっており、<form action="GETexample.php" method="get">
にあるように、GETexample.php
というファイルに送信される。
<!DOCTYPE HTML> <html><head><title>HTTP GET Example</title></head> <body> <h3>HTTP GET Example</h3> <form action="GETexample.php" method="get"> Name: <input type="text" name="name" value="Anny Omous"><br> Age: <input type="number" name="age" value="23"><br><br> <input type="submit" value="Send Form and Evaluate"><br><br> <input type="submit" value="Send Form and Return Request" name="return"> </form> </body></html>
何も値が入っていないと、[http://www.r-datacollection.com/materials/http/GETexample.php]
は下記のように返してくる。
Please specify your name! Please specify your age!
getForm()
を使って、phpにわたす値をname = Tanaka, age = 30
として渡すと下記が返ってくる。
getForm(url, name = "Tanaka", age = 30) [1] "Hello Tanaka!\nYou are 30 years old.\n" attr(,"Content-Type") charset "text/html" "UTF-8"
get**()
では、HTTPメソッドを扱う引数がある。
cat(RCurl::getURL("http://www.r-datacollection.com/materials/http/helloworld.html", .opts = "HEAD", header = TRUE)) HTTP/1.1 200 OK Date: Sun, 15 Mar 2020 03:59:09 GMT Server: Apache Upgrade: h2 Connection: Upgrade Vary: Accept-Encoding,User-Agent Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8 <html> <head><title>Hello World</title></head> <body><h3>Hello World</h3> </body> </html>
AJAX(Asynchronous JavaScript + XML)
HTML/HTTPに欠けている「動的なコンテンツ提供」を行うためにはAJAXを使う。AJAXを使うことで、画像の遷移のない通信である非同期通信を行うことが出来る。そのため、同期処理のように一瞬画面が白くなる画面切替は発生しない。HTML/HTTPには下記が欠けている。
JavaScript
AJAXは、XMLHttpRequest、JavaScript、DOM、XMLの技術要素をまとめた言葉なので、理解するためにはこれらを知っておく必要がある。例えば、JavaScriptをはじめjQueryというDOM操作を用意にするJavaScriptライブラリなどを理解する必要がある。JavaScriptが使われているかどうかはHTMLをみればわかる。例えば、<script>
タグにJavaScriptが記述できたり、<script>
のsrc属性にファイルパスを渡したりすることでJavaScriptが使われているかどうかわかる。いずれの方法もDOMを構築することになる。
DOM(Document Object Model)は、プログラムからHTMLやXMLを操作する仕組みのこと。例えば、ブラウザに表示される文字色などの情報を変更する際に、何もしていない状態のHTMLファイルではJavaScriptからは操作できないため、特定の部分に印を付けてJavaScriptにわかるようにする「取り決め」がDOMの役割。DOMを取り決めることで、ブラウザは動的に振る舞うことが出来る。参考文献のこのページがわかりよい。ソースは下記の通り。
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <html> <script type="text/javascript" src="jquery-1.8.0.min.js"></script> <script type="text/javascript" src="script1.js"></script> <head> <title>Collected R wisdoms</title> </head> <body> <div id="R Inventor" lang="english" date="June/2003"> <h1>Robert Gentleman</h1> <p><i>'What we have is nice, but we need something very different'</i></p> <p><b>Source: </b>Statistical Computing 2003, Reisensburg</p> </div> <div lang="english" date="October/2011"> <h1>Rolf Turner</h1> <p><i>'R is wonderful, but it cannot work magic'</i> <br><emph>answering a request for automatic generation of 'data from a known mean and 95% CI'</emph></p> <p><b>Source: </b><a href="https://stat.ethz.ch/mailman/listinfo/r-help">R-help</a></p> </div> <address><a href="http://www.r-datacollection.com"><i>The book homepage</i></a></address> </body> </html>
script1.js
はこんな感じ。$(document)
はDOM中の要素を選択するためのjQueryのメソッド。ready
はHTML要素が完全に揃うまで待つもので、サイトが巨大になるとDOMの構築が終わらないままjavaScriptが実行されるかもしれない。$("p")
でpノードだけを指定し、hide()
メソッドを実行するように指定。click(function()
ハンドラでクリックのイベントをもとにアクションを引き起こす。$(this).nextAll()
でクリックされた要素に続くすべての要素を選択し、300msの速度でフェードを実行する。
$(document).ready(function() { $("p").hide(); $("h1").click(function(){ $(this).nextAll().slideToggle(300); }); });
XHR
XHRは、XMLHttpRequestの略で、ブラウザとwebサーバー間の連続的な情報交換をする仕組みのこと。XHRによるユーザー・サーバー間の通信は下記のように行われる。
- AJAXリクエストはブラウザでクリック(Javascriptが認識可能イベント)することで開始される。
- AJAXリクエストが開始されると、JavascriptはXHRオブジェクトをインスタンス化する。このインスタンスは、リクエストを作成するものとして使われ、取得したデータをどう扱うかをコールバック関数によって定義する。
- XHRオブジェクトは、指定されたファイルに対するリクエスト(HTTP or HTTPS)をサーバーに送る。
- サーバー側では、リクエストを受信して、処理して、XHRオブジェクトを通じてクライアント、ブラウザに送る。
- ブラウザでレスポンスデータ受信し、そのイベントをイベントハンドラが受け取る。内容によってはコールバックイベントハンドラが処理して、ブラウザに表示する。
このサイトはThe book homepage
しか表示されず、"Quotes.html was fetched."
というアラートが出てくる。これをOKすることで、内容が別のドキュメントから読み込まれる。
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <html> <script type="text/javascript" src="jquery-1.8.0.min.js"></script> <script type="text/javascript" src="script2.js"></script> <head> <title>Collected R wisdoms</title> </head> <body> <address><a href="http://www.r-datacollection.com"><i>The book homepage</i></a></address> </body> </html>
script2.js
はこんな感じ。jQueyのload()
メソッドでquotes/quotes.html
の情報を収集している。load()
メソッドはXHRオブジェクトを生成し、HTMLドキュメントの情報を反映する。
$(document).ready(function() { $("body").load("quotes/quotes.html", function() { alert("Quotes.html was fetched."); }); });
quotes/quotes.html
の内容はこれ。
<div id="R Inventor" lang="english" date="June/2003"> <h1>Robert Gentleman</h1> <p><i>'What we have is nice, but we need something very different'</i></p> <p><b>Source: </b>Statistical Computing 2003, Reisensburg</p> </div> <div lang="english" date="October/2011"> <h1>Rolf Turner</h1> <p><i>'R is wonderful, but it cannot work magic'</i> <br><emph>answering a request for automatic generation of 'data from a known mean and 95% CI'</emph></p> <p><b>Source: </b><a href="https://stat.ethz.ch/mailman/listinfo/r-help">R-help</a></p> </div>
この仕組を見てわかるように、スクレイピングしようとすると、すべての情報が反映されておらず、取得することができないため、何らかのアクションでjQueyを動かして、情報を反映させてからスクレイピングする必要がある。
AJAXを調べる
Chormeの開発者ツールでAJAXを調べることが出来る。Chormeの開発者ツールであれば、AJAXと関わりの深いものはElementsとNetworkの2つ。Networkパネルをみてみる。先程のサイトを通信のやり取りは画像のようになっている。fortunes2.html
、jquery-1.8.0.min.js
、script2.js
、quotes.html
が読み込まれている。
Rに渡すためのURLは、quotes.html
をクリックし、その中のリクエストURLに記載されているhttp://www.r-datacollection.com/materials/ch-6-ajax/fortunes/quotes/quotes.html
である。このサイトにはjQueyで動かした後の情報が記載されている。
Previweでファイルの中身を確認できる。
RのgetURL()
にこのアドレスを渡す必要がある。
cat(RCurl::getURL("http://www.r-datacollection.com/materials/ch-6-ajax/fortunes/quotes/quotes.html")) <div id="R Inventor" lang="english" date="June/2003"> <h1>Robert Gentleman</h1> <p><i>'What we have is nice, but we need something very different'</i></p> <p><b>Source: </b>Statistical Computing 2003, Reisensburg</p> </div> <div lang="english" date="October/2011"> <h1>Rolf Turner</h1> <p><i>'R is wonderful, but it cannot work magic'</i> <br><emph>answering a request for automatic generation of 'data from a known mean and 95% CI'</emph></p> <p><b>Source: </b><a href="https://stat.ethz.ch/mailman/listinfo/r-help">R-help</a></p> </div>
AJAXはWebサービスの利便性を遥かに向上させてくれる一方でスクレイピングを目的とすると、少しややこしくなるが、仕組みを理解しておけばなんとかなる。AJAXにリクエストされる情報は、メインファイルがある同じページのどこかにあるので開発者ツールでなんとかできる。