はじめに
駅すぱあとWebサービスは経路検索・運賃計算・時刻表のAPIを提供しているオンラインサービスです
今回はこれの フリープラン をCommonLispで使ってみます
事前準備
手始めに 「駅すぱあとWebサービス フリープラン」利用お申し込み のページから申し込みする
しばらくするとアクセスキーが書かれたメールが来る
アクセスキーが手に入ったらスペシャル変数として定義しておく
(defparameter *api-key* "Your API Key")
ベースURLとして以下を定義する
(defparameter *base-url* "http://api.ekispert.jp/v1")
取得するデータのフォーマットは xml
と json
のどちらかを選べるので、今回は json
を選択
(defparameter *format* "/json")
今回は駅情報を取得したいので station
を指定
他の情報を取得したい場合は API一覧 から
(defparameter *station-info* "/station")
以上を全部つなげると http://api.ekispert.jp/v1/json/station
となる
(defparameter *base-station-url* (concatenate 'string *base-url* *format* *station-info*))
これを使って駅情報を取得する
HTTPクライアントとして dexador を使用するのでロードしておく
(ql:quickload :dexador)
駅名で取得
とりあえず 東京
を指定してみる
駅名で取得する場合のクエリパラメータは以下のように指定する
name={station name}
以下のようにすることで旧駅名も指定できる
oldName={station name}
指定できるパラメータは 駅情報 parameters に記載されている
駅名には日本語を指定するためURLエンコードする必要がある
そのためURIライブラリの quri をロードする
(ql:quickload :quri)
以下のように指定する駅名に quri:url-encode
を使用する
(defparameter *name* (quri:url-encode "東京"))
これで準備完了、早速取得してみる
(dex:get (format nil "~A?key=~A&name=~A" *base-station-url* *api-key* *name*))
"{\"ResultSet\":{\"apiVersion\":\"1.27.0.0\",\"max\":\"9\",\"offset\":\"1\",\"engineVersion\":\"202012_02a\",\"Point\":[{\"Station\":{\"code\":\"22828\",\"Name\":\"東京\",\"Type\":\"train\",\"Yomi\":\"とうきょう\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.46.13.59\",\"lati\":\"35.40.41.9\",\"longi_d\":\"139.770444\",\"lati_d\":\"35.678083\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29110\",\"Name\":\"成田空港(東京)\",\"Type\":\"plane\",\"Yomi\":\"なりたくうこう\"},\"Prefecture\":{\"code\":\"12\",\"Name\":\"千葉県\"},\"GeoPoint\":{\"longi\":\"140.23.26.0\",\"lati\":\"35.45.55.0\",\"longi_d\":\"140.390556\",\"lati_d\":\"35.765278\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"22827\",\"Name\":\"羽田空港(東京)\",\"Type\":\"plane\",\"Yomi\":\"はねだくうこう\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.47.19.0\",\"lati\":\"35.32.52.0\",\"longi_d\":\"139.788611\",\"lati_d\":\"35.547778\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"22859\",\"Name\":\"とうきょうスカイツリー\",\"Type\":\"train\",\"Yomi\":\"とうきょうすかいつりー\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.48.44.19\",\"lati\":\"35.42.25.59\",\"longi_d\":\"139.812278\",\"lati_d\":\"35.70711\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29073\",\"Name\":\"東京テレポート\",\"Type\":\"train\",\"Yomi\":\"とうきょうてれぽーと\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.46.52.79\",\"lati\":\"35.37.27.9\",\"longi_d\":\"139.781332\",\"lati_d\":\"35.624194\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29372\",\"Name\":\"東京ディズニーシー・ステーション\",\"Type\":\"train\",\"Yomi\":\"とうきょうでぃずにーしーすてーしょん\"},\"Prefecture\":{\"code\":\"12\",\"Name\":\"千葉県\"},\"GeoPoint\":{\"longi\":\"139.53.34.0\",\"lati\":\"35.37.27.0\",\"longi_d\":\"139.892778\",\"lati_d\":\"35.624167\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29370\",\"Name\":\"東京ディズニーランド・ステーション\",\"Type\":\"train\",\"Yomi\":\"とうきょうでぃずにーらんどすてーしょん\"},\"Prefecture\":{\"code\":\"12\",\"Name\":\"千葉県\"},\"GeoPoint\":{\"longi\":\"139.52.55.0\",\"lati\":\"35.37.58.0\",\"longi_d\":\"139.881944\",\"lati_d\":\"35.632778\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29059\",\"Name\":\"東京ビッグサイト\",\"Type\":\"train\",\"Yomi\":\"とうきょうびっぐさいと\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.47.41.0\",\"lati\":\"35.37.37.0\",\"longi_d\":\"139.794722\",\"lati_d\":\"35.626944\",\"gcs\":\"tokyo\"}},{\"Station\":{\"code\":\"29056\",\"Name\":\"東京国際クルーズターミナル\",\"Type\":\"train\",\"Yomi\":\"とうきょうこくさいくるーずたーみなる\"},\"Prefecture\":{\"code\":\"13\",\"Name\":\"東京都\"},\"GeoPoint\":{\"longi\":\"139.46.35.9\",\"lati\":\"35.37.5.9\",\"longi_d\":\"139.776416\",\"lati_d\":\"35.618083\",\"gcs\":\"tokyo\"}}]}}"
200
#<HASH-TABLE :TEST EQUAL :COUNT 7 {1002B77193}>
#<QURI.URI.HTTP:URI-HTTP http://api.ekispert.jp/v1/json/station?key=LE_uR3LCxKb4csTX&name=%E6%9D%B1%E4%BA%AC>
#<SB-SYS:FD-STREAM for "socket 192.168.11.9:35642, peer: 52.197.98.85:80" {1002B75973}>
色々ごちゃっと取れたけど、とりあえず使うのは最初のJSONデータだけ
JSONデータの内容の詳細は 駅情報 response に記載されている
JSONのままだとCommonLispでは使いづらいので、連想リストに変換する
そのために jonathan をロードする
(ql:quickload :jonathan)
もう一回取得
(jojo:parse
(dex:get (format nil "~A?key=~A&name=~A" *base-station-url* *api-key* *name*))
:as :alist)
(("ResultSet"
("Point"
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.678083")
("longi_d" . "139.770444") ("lati" . "35.40.41.9")
("longi" . "139.46.13.59"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "とうきょう") ("Type" . "train") ("Name" . "東京")
("code" . "22828")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.765278")
("longi_d" . "140.390556") ("lati" . "35.45.55.0")
("longi" . "140.23.26.0"))
("Prefecture" ("Name" . "千葉県") ("code" . "12"))
("Station" ("Yomi" . "なりたくうこう") ("Type" . "plane") ("Name" . "成田空港(東京)")
("code" . "29110")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.547778")
("longi_d" . "139.788611") ("lati" . "35.32.52.0")
("longi" . "139.47.19.0"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "はねだくうこう") ("Type" . "plane") ("Name" . "羽田空港(東京)")
("code" . "22827")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.70711")
("longi_d" . "139.812278") ("lati" . "35.42.25.59")
("longi" . "139.48.44.19"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "とうきょうすかいつりー") ("Type" . "train")
("Name" . "とうきょうスカイツリー") ("code" . "22859")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.624194")
("longi_d" . "139.781332") ("lati" . "35.37.27.9")
("longi" . "139.46.52.79"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "とうきょうてれぽーと") ("Type" . "train") ("Name" . "東京テレポート")
("code" . "29073")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.624167")
("longi_d" . "139.892778") ("lati" . "35.37.27.0")
("longi" . "139.53.34.0"))
("Prefecture" ("Name" . "千葉県") ("code" . "12"))
("Station" ("Yomi" . "とうきょうでぃずにーしーすてーしょん") ("Type" . "train")
("Name" . "東京ディズニーシー・ステーション") ("code" . "29372")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.632778")
("longi_d" . "139.881944") ("lati" . "35.37.58.0")
("longi" . "139.52.55.0"))
("Prefecture" ("Name" . "千葉県") ("code" . "12"))
("Station" ("Yomi" . "とうきょうでぃずにーらんどすてーしょん") ("Type" . "train")
("Name" . "東京ディズニーランド・ステーション") ("code" . "29370")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.626944")
("longi_d" . "139.794722") ("lati" . "35.37.37.0")
("longi" . "139.47.41.0"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "とうきょうびっぐさいと") ("Type" . "train")
("Name" . "東京ビッグサイト") ("code" . "29059")))
(("GeoPoint" ("gcs" . "tokyo") ("lati_d" . "35.618083")
("longi_d" . "139.776416") ("lati" . "35.37.5.9")
("longi" . "139.46.35.9"))
("Prefecture" ("Name" . "東京都") ("code" . "13"))
("Station" ("Yomi" . "とうきょうこくさいくるーずたーみなる") ("Type" . "train")
("Name" . "東京国際クルーズターミナル") ("code" . "29056"))))
("engineVersion" . "202012_02a") ("offset" . "1") ("max" . "9")
("apiVersion" . "1.27.0.0")))
駅名に「東京」が入っている駅の情報が取得できた
さらに、連想リストを操作するのに便利なユーティリティ assoc-utils があるのでこれもロードする
(ql:quickload :assoc-utils)
取得した現在の駅情報をスペシャル変数として定義しておく
(defparameter *station-info*
(jojo:parse
(dex:get (format nil "~A?key=~A&name=~A" *base-station-url* *api-key* *name*))
:as :alist))
以下のように駅名と駅コードを取り出してリスト表示できる
(let ((points (assoc-utils:aget
(assoc-utils:aget *station-info* "ResultSet")
"Point")))
(mapcar
(lambda (point)
(let ((station (assoc-utils:aget point "Station")))
(format t "Code: ~A, Name: ~A~%"
(assoc-utils:aget station "code")
(assoc-utils:aget station "Name"))
station))
points))
Code: 22828, Name: 東京
Code: 29110, Name: 成田空港(東京)
Code: 22827, Name: 羽田空港(東京)
Code: 22859, Name: とうきょうスカイツリー
Code: 29073, Name: 東京テレポート
Code: 29372, Name: 東京ディズニーシー・ステーション
Code: 29370, Name: 東京ディズニーランド・ステーション
Code: 29059, Name: 東京ビッグサイト
Code: 29056, Name: 東京国際クルーズターミナル
名前に「東京」が入っている駅、以外と多い
成田空港と羽田空港の「(東京)」も駅名の一部なのか・・・
さいごに
駅すぱあとWebサービスをCommonLispから使って駅情報を取得してみました
導入も簡単でとても良いと思いました