LoginSignup
2

More than 5 years have passed since last update.

ヴァル研究所 Advent Calendar 2016、4日目はいよいよ経路探索の話しをしてみようと思います。

経路探索はドキュメントにもあるように、指定された駅もしくは地点間の公共交通機関を利用した経路を探索する機能です。
(「駅すぱあと」の主たる機能のひとつですね!)

経路探索の例

例として、新宿から高円寺までの経路を探索してみます。昨日の駅コードの話しにもある通り、最初に駅名を駅コードに変換しましょう。
新宿の駅コードは22741、高円寺の駅コードは22671であることが分かります。
(この場合は「新宿」が含まれる駅名が複数あるので注意ですね)

$ curl -s -XGET 'http://api.ekispert.jp/v1/json/station?key=<アクセスキー>&name=新宿&type=train' \
      | jq '.ResultSet.Point[].Station' \
      | egrep '(code|Name)' \
      | paste - - 
  "code": "22741",        "Name": "新宿",
  "code": "29342",        "Name": "新宿(東京メトロ)",
  "code": "22768",        "Name": "西武新宿",
  "code": "22742",        "Name": "新宿御苑前",
  "code": "22743",        "Name": "新宿三丁目",
  "code": "29330",        "Name": "新宿西口",
$ curl -s -XGET 'http://api.ekispert.jp/v1/json/station?key=<アクセスキー>&name=高円寺&type=train' \
      | jq '.ResultSet.Point.Station' \
      | egrep '(code|Name)' \
      | paste - - 
  "code": "22671",        "Name": "高円寺",

続いて取得した駅コードを用いて経路探索を呼び出します。
必須パラメータはアクセスキー(key)とviaListになります。viaListパラメータに出発駅と到着駅をコロン(":")で区切って指定します。
また、デフォルトでは現在の日付、日時での探索となります。日時を指定する場合は、datetimeパラメータを指定してください。

curl -s -XGET 'http://api.ekispert.jp/v1/json/search/course/extreme?key=<アクセスキー>&viaList=22741:22671'

探索結果は以下のようになります。ResultSet/Course要素に探索結果が含まれる形のレスポンスになっています。

{
  "ResultSet": {
    "apiVersion": "1.27.0.0",
    "engineVersion": "201612_02a",
    "Course": [
      {
        "searchType": "departure",
        "dataType": "onTimetable",
        "SerializeData": "VkV4QaEByALDAqYBM6KyA6YBM6KyBJHCAUMAAAACpgEzorIDyQEBAgEDAQQBBwEIAQoCD0L_fxCl__cFlMECpVjVwQKlWI_BAqVZysECpVdZBpHDAQECAQPHAaUkJQIeAyIFpHkGRTIwNTdCBwMIAgeRxQGmATOitAOlBRoEpQUjBQAIAAiRxQQBBQEGAQekbggBCZHBAwEPkcUBkgABApHDAQACAAMAA5HDAQACAAMABJEABZEA--T3221233232319:F3321122120:A23121141:--1cfb45bf0658b316a41dcc9dfc2ef46a824db796--0--0--0--183",
        "Price": [
          {
            "kind": "FareSummary",
            "Oneway": "160",
            "Round": "320"
          },
          {
            "fareRevisionStatus": "none",
            "toLineIndex": "1",
            "fromLineIndex": "1",
            "kind": "Fare",
            "index": "1",
            "selected": "true",
            "Type": "Fare",
            "Oneway": "160",
            "Round": "320"
          },
          {
            "kind": "Teiki1Summary",
            "Oneway": "4850"
          },
          {
            "fareRevisionStatus": "none",
            "toLineIndex": "1",
            "fromLineIndex": "1",
            "kind": "Teiki1",
            "index": "1",
            "selected": "true",
            "Type": "Teiki1",
            "Oneway": "4850"
          },
          {
            "kind": "Teiki3Summary",
            "Oneway": "13820"
          },
          {
            "fareRevisionStatus": "none",
            "toLineIndex": "1",
            "fromLineIndex": "1",
            "kind": "Teiki3",
            "index": "1",
            "selected": "true",
            "Type": "Teiki3",
            "Oneway": "13820"
          },
          {
            "kind": "Teiki6Summary",
            "Oneway": "23260"
          },
          {
            "fareRevisionStatus": "none",
            "toLineIndex": "1",
            "fromLineIndex": "1",
            "kind": "Teiki6",
            "index": "1",
            "selected": "true",
            "Type": "Teiki6",
            "Oneway": "23260"
          }
        ],
        "Route": {
          "timeOther": "0",
          "timeOnBoard": "9",
          "exhaustCO2": "127",
          "exhaustCO2atPassengerCar": "974",
          "distance": "58",
          "timeWalk": "0",
          "transferCount": "0",
          "Line": {
            "stopStationCount": "3",
            "teiki3Index": "1",
            "teiki6Index": "1",
            "timeOnBoard": "9",
            "track": "railway",
            "exhaustCO2": "127",
            "fareIndex": "1",
            "exhaustCO2atPassengerCar": "974",
            "distance": "58",
            "teiki1Index": "1",
            "Name": "JR総武線・三鷹行",
            "Type": "train",
            "ArrivalState": {
              "no": "1",
              "Type": "normal",
              "Datetime": {
                "text": "2016-12-04T21:55:00+09:00",
                "operation": "today"
              }
            },
            "Destination": "三鷹",
            "TimeReliability": "onTimetable",
            "DepartureState": {
              "no": "16",
              "Type": "normal",
              "Datetime": {
                "text": "2016-12-04T21:46:00+09:00",
                "operation": "today"
              }
            },
            "Color": "255222000"
          },
          "Point": [
            {
              "Station": {
                "code": "22741",
                "Name": "新宿",
                "Type": "train",
                "Yomi": "しんじゅく"
              },
              "Prefecture": {
                "code": "13",
                "Name": "東京都"
              },
              "GeoPoint": {
                "longi": "139.42.11.0",
                "lati": "35.41.15.0",
                "longi_d": "139.703056",
                "gcs": "tokyo",
                "lati_d": "35.6875"
              }
            },
            {
              "Station": {
                "code": "22671",
                "Name": "高円寺",
                "Type": "train",
                "Yomi": "こうえんじ"
              },
              "Prefecture": {
                "code": "13",
                "Name": "東京都"
              },
              "GeoPoint": {
                "longi": "139.39.10.89",
                "lati": "35.42.7.59",
                "longi_d": "139.653027",
                "gcs": "tokyo",
                "lati_d": "35.70211"
              }
            }
          ]
        }
      },
      ...

このレスポンスから欲しい要素を取得してみます。例として、出発・到着駅、路線名と金額を表示してみます。

JavaScriptを使って上記のレスポンス(JSON)をパースしてそれっぽい結果表示を得てみます。
(説明を簡単にするため、乗り換えのない経路のみを表示する処理になっています)

#!/usr/bin/env node

var fs = require('fs');
var json_file = process.argv[2] == undefined ? 'result.json' : process.argv[2];

fs.readFile(json_file, 'utf8', function (err, json_str) {
    var json = JSON.parse(json_str);    
    var course = json.ResultSet.Course; // ResultSet/Course要素を取得

    for (var i in course) {
        var price = course[i].Price[0].Oneway;  // 片道料金
        var line  = course[i].Route.Line;

        // 説明を簡略化するため、乗り換えのない経路のみ表示
        if (Array.isArray(line) == false) {

            var lineName = line.Name;           // 路線の名称
            var point = course[i].Route.Point;
            var from  = point[0].Station.Name;  // 出発駅
            var to    = point[1].Station.Name;  // 到着駅

            console.log('候補: ' + (parseInt(i) + 1));
            console.log('' + from);
            console.log('' + lineName);
            console.log('' + price + '');
            console.log('' + to);
            console.log('');
        }
    }
});

上記JavaScriptをsample.js等の名前で保存し、以下のように実行してみます。

$ curl -s -XGET 'http://api.ekispert.jp/v1/json/search/course/extreme?key=<アクセスキー>&viaList=22741:22671' > result.json
$ ./sample.js result.json

実行結果は以下になります。経路探索のレスポンス(JSON)から探索結果の一覧を表示できています。

候補: 1
□ 新宿
│ JR総武線・三鷹行
│ 160円
□ 高円寺

候補: 2
□ 新宿
│ JR総武線・武蔵小金井行
│ 160円
□ 高円寺

候補: 3
□ 新宿
│ JR総武線・三鷹行
│ 160円
□ 高円寺

候補: 4
□ 新宿
│ JR総武線・武蔵小金井行
│ 160円
□ 高円寺

まとめ

今日は経路探索の話と、レスポンスのJSONを用いてJavaScriptで探索結果を表示する例を示しました。
これでWebAPIの使い方とレスポンスから欲しい要素を取り出すという一連の手順が説明できましたので、以降はより実用的な例を解説できればと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2