はじめに
「日経ソフトウエア 2022年 11月号」の「バスのリアルタイム運行情報をGoogleマップに表示しよう」という特集を参考に Google Maps Platform と 公共交通オープンデータセンターの利用方法を探っています。
これまで、Google Maps Platformの利用開始手続きと公共交通オープンデータセンターの利用開始手続きを行い、それぞれ呼び出すのに必要なAPIキーとアクセストークンを入手しました。
これで、公共交通オープンデータセンターのリアルタイムデータを読み込んで、リアルタイムにGoogle Map に表示できる環境がとのいました。
「日経ソフトウエア 2022年 11月号」の特集のコードを紐解いて、何をやっているか探っていこうと思います。
特集記事を解析
まず動かしてみた
ソースコードは日経のサイトからダウンロードできましたので、とりあえず動かしてみました。
データのアクセストークンとMapのAPIキーをセットしただでけすんなり動きました。
実行環境は Node.js のローカルサーバーです。
Visual Studio Code のターミナルで起動。

ブラウザでローカルサーバーの index.html を呼び出すと、初期画面が表示されました。

地図が表示され、左上に「バス停検索」テキストボックス、その横に「選択されたバス停」リストボックス、次の行に「交通状況を表示」チェックボックスがあります。

「バス停検索」テキストボックスにバス停名の一部を入力すると、該当するバス停が検索されて「選択されたバス停」リストボックスにセットされ選択できるようになります。

リストボックスからバス停を選択すると、このバス停を通る路線のチェックボックスが表示されます。

路線にチェックを入れると路線が赤色の線で、バス停が▽マークと吹き出しで表示されます。

バスが何処に居るのかスクロールしてみたところ、中原と西長岡の間にいました。
バスは緑の◎で表示されます。

その他の機能として「交通状況を表示」チェックボックスがあります。
チェックを入れると、道路の渋滞状況が赤・オレンジで表示されます。

プログラム構成
プログラムを構成するファイルは以下です。

WebサーバーのNode.js のファイルが混じっていて色々ありますが、アプリの本体は index.htmlとserver.js です。
server.js は、サーバー側で動作するプログラムで、主にサーバーの起動とデータの取得をしています。
公共交通センターAPIにリクエストを送りデータを取得しています。
index.html はブラウザで動作するプログラムで、ユーザーのオペレーションの処理とMapの表示をしています。
server.jsのコマンドを呼び出しデータを取得し、結果を Maps JavaScript APIを利用して表示しています。
サーバーの処理 server.js
起動時
起動時には以下の処理をしています。
- Webサーバーを起動
- バス運行系統情報の取得
- バス停票柱情報の取得
- フロントエンドから受けるエンドポイントの設定
1.Webサーバーを起動
ポート8080でWebサーバーを起動しています。
2.バス運行系統情報の取得
バス路線のデータを取得しています。
バス路線は改定されるまで同じデータなので、ファイルに保存して利用しています。
起動時にファイルが存在していればファイルからメモリにデータを読み込み、ファイルが無ければ公共交通オープンデータセンターからAPIを使ってデータをメモリに読み込み、ファイルに保存しています。
取得方法はHTTPリクエストを送信します。
const response = sqait axios.request({
url: 'https://api.odpt.org/api/v4/odpt:BusroutePattern.json',
method: 'get',
prams: {
'acl:consumerKey': [アクセストークン],
}
});JSONデータが返ってきます。
取得したデータを.filter()で都営バスデータでかつバス路線の経度・緯度を持っているデータのみを抽出し、/data/busroutePatterns.json ファイルに保存しています。
保存データの構造は以下のようになっています。
// 路線一つ分のデータ構造
{"sameAs":"odpt.BusroutePattern:Toei.T05-1.72414.1", // バス系統ID
"title":"都05-1 東京駅丸の内南口行", // バス路線名称
"coordinates":[{"lng":139.774971,"lat":35.64798}, // バス路線の緯度・経度配列
・
・
・
{"lng":139.765532,"lat":35.680137}],
"busstopPoles":["odpt.BusstopPole:Toei.HarumiFuto.1249.4", // 経由するバス停ID配列
・
・
・
"odpt.BusstopPole:Toei.TokyoStationMarunouchiMinamiguchi.966.4"]
},3.バス停票柱情報の取得
バス停のデータを取得しています。
バス停もバス路線と同様、ファイルに保存して利用しています。
取得方法はHTTPリクエストを送信します。
const response = sqait axios.request({
url: 'https://api.odpt.org/api/v4/odpt:BusstopPole.json',
method: 'get',
prams: {
'acl:consumerKey': [アクセストークン],
}
});JSONデータが返ってきます。
取得したデータを.filter()で都営バスデータのみを抽出し、/data/busstopPoles.json ファイルに保存しています。
保存データの構造は以下のようになっています。
// バス停一つ分のデータ構造
{"sameAs":"odpt.BusstopPole:Toei.Tenjincho.957.1", // バス停ID
"title":"天神町", // バス停名
"kana":"てんじんちょう", // バス停名ひらがな
"lat":35.730858, // バス停の緯度
"lng":139.494166, // バス停の緯度
"busroutePattern":["odpt.BusroutePattern:Toei.Ume70.28008.1", // 経由バス系統ID
"odpt.BusroutePattern:Toei.Ume70.28009.1",
"odpt.BusroutePattern:Toei.Ume70.28012.1"]
},4.フロントエンドから受けるエンドポイントの設定
クライアントが特定のデータや機能にアクセスするための窓口となるエンドポイントを設定します。
app.get(‘/busstopPoles’, [処理])
クライアントからリクエストがあれば、キーワードを受け取ってバス停名または読み仮名に部分一致するバス停情報の配列をJSONで返します。
app.get(‘/bussroutePatterns’, [処理])
クライアントからリクエストがあれば、バス停IDを受け取って、指定したバス停を経由するバス運行系統情報オブジェクトの配列をJSONで返します。
app.get(‘/buses’, [処理])
クライアントからリクエストがあれば、バス系統IDを受け取って、バス車両のリアルタイム位置情報配列をJSONで返します。
待ち受け
サーバーが起動時に「4.フロントエンドから受けるエンドポイントの設定」が行われ、クライアントからのリクエスト待ち受け状態になります。
クライアントからリクエストがあれば、それぞれのエンドポイントの処理が実行され、該当するデータが返されます。
GET /busstopPoles
クライアントの「バス停検索」でキーワードが入力された時に呼び出されます。
const fetchBusstopPoles = async (keyword) => {
const response = await fetch(`/busstopPoles?keyword=${keyword}`);
return await response.json()
};サーバーの[処理]
起動時に読み込んだ「バス停票柱情報」から「keyword」とバス停名または読み仮名が部分一致するデータを抽出してJSONデータを返します。
クライアントではこのデータをもとに「選択されたバス停」リストボックスを作成しています。
GET /busroutePatterns
クライアントの「選択されたバス停」リストボックスが選択された時に呼び出されます。
const fetchBusstopPoles = async (keyword) => {
const response = await fetch(`/busstopPoles?keyword=${keyword}`);
return await response.json()
};サーバーの[処理]
起動時に読み込んだ「バス運行系統情報」から「keyword」とバス停IDが一致するデータを抽出し、「バス標柱情報」とマッピングしたオブジェクト配列をJSONデータにして返します。
クライアントではこのデータをもとに「路線チェックボックス」を作成しています。
JSONデータは下記のフォーマットです。
// バス運行系統情報オブジェクト一つ分のデータ構造
{"sameAs": "odpt.BusroutePattern:Toei.T05-1.72414.1", // バス系統ID
"title":"都05-1 東京駅丸の内南口行", // バス路線名称
"coordinates":[{"lng":139.774971,"lat":35.64798}, // バス路線の緯度・経度配列
・
・
・
{"lng":139.765532,"lat":35.680137}],
"busstopPoles": [ // 経由するバス停情報配列
{"sameAs":"odpt.BusstopPole:Toei.Tenjincho.957.1", // バス停ID
"title":"天神町", // バス停名
"kana":"てんじんちょう", // バス停名ひらがな
"lat":35.730858, // バス停の緯度
"lng":139.494166, // バス停の緯度
"busroutePattern":["odpt.BusroutePattern:Toei.Ume70.28008.1", // 経由バス系統ID
"odpt.BusroutePattern:Toei.Ume70.28009.1",
"odpt.BusroutePattern:Toei.Ume70.28012.1"]
}]
},GET /buses
クライアントの「路線チェックボックス」にチェックが入った時に呼び出されます。
const fetchBuses = async (busroutePatternSameAs) => {
const response = await fetch(`/buses?busroutePatternSameAs=${busroutePatternSameAs}`);
return await response.json();
};サーバーの[処理]
バス系統IDが「busroutePatternSameAs」のバス車両のリアルタイム位置情報を取得します。
取得方法はHTTPリクエストを送信します。
const response = await axios.request({
url: 'https://api.odpt.org/api/v4/odpt:Bus',
method: 'get',
params: {
// 公共交通オープンデータセンターのAPI アクセストークンを送る
'acl:consumerKey': config.PUBLIC_TRANSPORTATION_OPEN_DATA_API_CONSUMER_KEY,
'odpt:busroutePattern': busroutePatternSameAs, // バス系統ID
}
});JSONデータが返ってきます。
サーバーではこのデータを加工して、バスが通過しているバス停間の路線の座標値を取得してクライアントに返します。
クライアントではこのデータをもとにバス車両の通過している区間をバス路線上に表示します。
HTTPリクエストで返ってくるJSONデータは下記のフォーマットです。
{
// データに付与された固有識別子
"@id":"urn:ucode:_00001C0000000000000100000363EDA8",
// バス運行情報クラス名(odpt:Busが入る)
"@type":"odpt:Bus",
// データ生成時刻
"dc:date":"2025-10-29T18:26:33+09:00",
// JSON-LD仕様に基づく @context のURL
"@context":"http://vocab.odpt.org/context_odpt_Bus.jsonld",
// データ保証期限
"dct:valid":"2025-10-29T18:27:03+09:00",
// 注記
"odpt:note":"都05-1 晴海埠頭→東京駅丸の内南口 晴海埠頭",
// バス運行情報の固有識別子
"owl:sameAs":"odpt.Bus:Toei.T05-1.72414.1.F653",
// バス路線ID
"odpt:busroute":"odpt.Busroute:Toei.T05-1",
// 運行会社のID
"odpt:operator":"odpt.Operator:Toei",
// バス車両番号
"odpt:busNumber":"F653",
// 更新頻度(秒)
"odpt:frequency":30,
// 運行中の便の時刻表のID
"odpt:busTimetable":"odpt.BusTimetable:Toei.T05-1.72414-1-81-179-1826",
// 次に到着するバス停のID
"odpt:toBusstopPole":"odpt.BusstopPole:Toei.HarumiFutoKoenMinami.2629.1",
// 運行中の系統のID
"odpt:busroutePattern":"odpt.BusroutePattern:Toei.T05-1.72414.1",
// 直近に通過した、あるいは停車中のバス停のID
"odpt:fromBusstopPole":"odpt.BusstopPole:Toei.HarumiFuto.1249.4",
// 直近に通過したバス停を発車した時刻
"odpt:fromBusstopPoleTime":"2025-10-29T18:26:19+09:00",
// 運行中系統の始発バス停を表すID
"odpt:startingBusstopPole":"odpt.BusstopPole:Toei.HarumiFuto.1249.4",
// 運行中系統の終着バス停を表すID
"odpt:terminalBusstopPole":"odpt.BusstopPole:Toei.TokyoStationMarunouchiMinamiguchi.966.4"
},クライアントでバス車両の描画は、出発バス停と到着バス停の間のルートを◎が移動する形で表示します。
ただし、出発バス停・到着バス停のいずれかがnullの場合、バスはnullで無い方のバス停に泊まっているので、バスが止まっているバス停が出発・到着バス停になります。
上記JSONデータの「直近に通過したバス停ID」と「次に到着するバス停のID」からバス停票柱情報が持っているバス停の緯度・経度を取得し、このバス停間の路線座標データをバス運行系統情報から取得しJSONデータでクライアントに返します。
次回
以上でサーバー側の動きをだいたい追うことができました。
公共交通オープンデータセンターのバス路線・バス停・リアルタイム情報に必要なデータとその取得のやりかたが見えてきました。
次回は、クライアント側の処理を追って行きたいと思います。
クライアントでは、サーバーにリクエストを出してバスデータを取得し、このデータをMaps JavaScript APIを利用してGoogle Mapに表示していますので、このへんが理解できたらなと思っています。
さらに次は・・・
日経ソフトウエアの記事では、サーバーにNode.jsを利用しています。
ローカルのテストでは便利ですが、実際レンタルサーバーで動かそうと思うと無理があります。
そこで、サーバー側の処理をPythonで作ってレンタルサーバーで動かせるようにしようと思います。


コメント