2015/12/15
Web APIを利用する
この記事はPowerShell Advent Calendar 2015の15日目の記事です。
はじめに
前々回と前回は、PowerShellによるWebスクレイピングの具体的手法についてまとめました。ただ、スクレイピングはあくまで最後の手段であり、Webから何らかの文字列情報を取得するには、Web APIを用いるのが本道かと思います。
今回はPowerShellでWeb APIを用いるお話です。
Web APIとは
Web APIというのは、その名の通り、プログラムからWeb上のデータを取得したり、何らかのサービスの機能を実行したりするための、呼び出し方式を定めた規約です。
Web APIでは、HTTPリクエストに呼び出したい機能の内容を指定し、結果をHTTPレスポンスとして受け取るというのが一連の流れになります。
Web APIの主な実装方式としてはSOAPとRESTがありますが、このうち、XMLでリクエストを組み立てるSOAPは最近は廃れてきた感じです。
(PowerShellではSOAP APIはNew-WebServiceProxyコマンドレットで対応しています。が、今回は略。参考:PowerShell: ◆空港の場所と天気を調べる(New-WebServiceProxy))
最近はWeb APIといえばREST(REpresentational State Transfer) APIを指すことが殆どです。REST APIでは操作の対象となるリソース=URI(エンドポイントという)、呼び出し方式=HTTPメソッド(GET:データの取得, POST:データの作成, PUT:データの更新, DELETE:データの削除)、操作に対するパラメータ=クエリストリング(GETの場合)もしくはリクエストボディ(POSTの場合)、結果の返却=HTTPレスポンス(JSON、XML等)となるのが基本です。
また、RESTの呼び出しは基本的にステートレスなものとなります。要はセッション情報を持たない≒cookieを使わない、ってことです。
PowerShellではREST APIを簡便に利用するためにInvoke-RestMethodコマンドレットが用意されています。(ただしPowerShell 3.0から)
Invoke-RestMethodコマンドレットのパラメータ指定
Invoke-RestMethodコマンドレットのパラメータについては、実は前々回に取り上げたInvoke-WebRequestコマンドレットと同じです(IEのパーサーを使うことはないので、-UseBasicParsingも無いですが)。ただしREST APIの形式は前述の通りなので、利用するパラメータは限られてきます。具体的には
データ取得の場合
$response = Invoke-RestMethod -Uri エンドポイント(パラメータを含む) -Method GET
データ作成、更新の場合
$response = Invoke-RestMethod -Uri エンドポイント -Method POST -Body パラメータ(連想配列あるいはJSONやXML等)
となるかと思います。
その他にOAuth等の認証情報を指定する場合は、-Headers @{Authorization="認証情報"}のような指定も必要になることがあります。
Invoke-RestMethodコマンドレットのレスポンス
Invoke-RestMethodコマンドレットがInvoke-WebRequestコマンドレットと異なる最大のポイントは、レスポンス文字列の種類によって、自動的に出力オブジェクトの型が切り替わるところです。
私の調べた限りでは以下のような対応になっているようです。
レスポンス文字列の種類 | 出力型 |
XML | XmlDocument |
RSS/ATOM | XmlElement |
JSON | PSCustomObject |
プレーンテキスト | string |
利用の具体例
AED検索
Microsoft MVPのはつねさんが公開されている、AED検索はREST APIでAEDの所在地情報を検索し、JSONで結果を得ることができます。
例えば兵庫県芦屋市のAED一覧を取得するには、
$response = Invoke-RestMethod https://aed.azure-mobile.net/api/aedinfo/兵庫県/芦屋市/ $response | Format-Table Latitude, Longitude, LocationName, @{L = "Address"; E = { "$($_.Perfecture) $($_.City) $($_.AddressArea)" }} -AutoSize
のようにします。
ここで$responseには、JSON形式のデータをパースしてPSCustomObject化したデータが格納されるので、あとはFormat-Tableコマンドレットで見やすい形で出力してあげれば良いでしょう。
結果はこんな感じです。
AED検索APIと、去年のアドベントカレンダーで紹介した、Windows 位置情報プラットフォームを用いて現在位置を取得するGet-GeoCoordinate関数を併用して、「現在位置の最寄りにあるAEDをGoogle MAP上で表示する」なんてこともできます。
$location = Get-GeoCoordinate $response = Invoke-RestMethod "https://aed.azure-mobile.net/api/NearAED?lat=$($location.Latitude)&lng=$($location.Longitude)" Start-Process "http://maps.google.com/maps?q=$($response.Latitude),$($response.Longitude)"
ここではREST APIにQueryStringでパラメータ(経度、緯度)情報を渡しているところと、レスポンスから生成されたオブジェクトのプロパティ値をマップ表示の際のパラメータとして利用しているところに注目してください。
RSS取得
RSSやATOMもREST APIの一種と考えて良いと思います。
ここではこのブログのRSSを取得する例を示します。
$response = Invoke-RestMethod ./rss2/ $response | select @{L = "Title"; E = "title"}, @{L = "Url"; E = "link"}, @{L = "PublishDate"; E = {[DateTime]::Parse($_.pubDate)}}, @{L = "Description"; E = { ($_.description -replace "<.+?>"). PadRight(50).Substring(0,50).TrimEnd() + "..." }}| Format-List
Descriptionの加工がやや適当(HTMLタグっぽいところを削除して50文字に切り詰めてるだけ)ですが、少し見やすくしています。結果は以下のように表示されます。
RSSの結果は、1エントリがXMLElement型のオブジェクトとして出力されるので、データの取扱いが比較的楽だと思います。
レスポンスがXMLなREST APIの良い例がなかったので省略してますが、基本的には前回取り上げた、XHTMLをXMLとしてパースする方法と同じやり方です。ただInvoke-RestMethodの場合は[xml]型アクセラレータによる変換は不要で、いきなりXmlDocumentオブジェクトが得られます。
現状の問題点
レスポンスがコールバック関数つきのJSONP形式であるとかで、JSON、XML、RSS/ATOMのいずれの形式にも適合しない場合はプレーンテキストとして出力されてしまいます。
その場合は、出力文字列を適宜加工した後に、[xml]型アクセラレータや、ConvertFrom-Jsonコマンドレット等により手動でオブジェクト化するようにしてください。もっとも、その場合は敢えてInvoke-RestMethodを使わずInvoke-WebRequestで充分ですが。
あとWeb APIというのは大抵(特にPOSTの場合)、認証を要するのですが、最近よくあるのはTwitter等でもおなじみのOAuth認証です。ところがOAuth認証は結構めんどくさい処理で、何らかのライブラリを使わないとしんどいです。残念ながらPowerShellの標準コマンドレットには存在しないので、自前で頑張って書くか、既存のライブラリやコマンドを利用することになるかと思います。
今回そこまで説明できませんでしたが、また機会があれば。
プライバシーポリシー