これは「imtakalab Advent Calendar 2025」の 2 日目の記事です。
はじめに
こんにちは! 最近忙しいのか忙しく見せてるのかわからない iitz-i13 です!
もうクリスマスシーズンですね🎅
実はディズニーがとても好きで、期間限定のものに目がないんです👀
そして今まさに、東京ディズニーリゾートでは現在 クリスマス限定フード が多数登場しています🎄
しかし、実際に公式サイトでフードを探そうとすると……
- 画面遷移が多い
- レストランごとにページを開き直す必要がある
- パーク・エリア・店舗・フード種別でサクッと絞り込みたいのに、結構大変
と感じる場面が多いと思います。
「今いるエリアで食べられるクリスマス限定メニュー(限定メニューに関わらず)を、パッと一覧で見たい…!」
こう思ったことがある人も多いのではないでしょうか。
そこで本当は
パークの地図上に、検索したクリスマスフードをマッピング表示する Web ツール を作りたかったのですが、今回は時間が足りず……
まずは CLI 版としてシンプルに検索できるツール を Go (Golang) で作りました。
なぜ Go 言語を使用して作るの?
理由はほんとにシンプルで、
- Go を一回触ってみたかった
- コンパイラ言語であるため処理が速い
- シンプルで書きやすいらしい
という3つだけです。
「とりあえず軽めのツールで Go を試してみよう!」
というノリで作り始めました。
今回作るもの
今回実装した CLI ツールを使うと、次のように 検索条件を指定してクリスマス限定フードを一発で一覧表示 できます。
例えば、TDS の「メディテレーニアンハーバー」にあるクリスマスメニューだけを見たい 場合は下記のコマンドを入力します。
go run ./cmd/xmas_cli --park tds --area ハーバー
そうすると以下のような出力が得られます。
一致するフードが 14 件見つかりました
1/14 | スペシャルセット (5800円) [meal]
パーク : TDS
エリア : メディテレーニアンハーバー
店舗名 : リストランテ・ディ・カナレット
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/408/
詳細URL : https://www.tokyodisneyresort.jp/food/4222/
2/14 | チョコレートチュロス (600円) [food]
パーク : TDS
エリア : メディテレーニアンハーバー
店舗名 : ザンビーニ・ブラザーズ・リストランテ
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/403/
詳細URL : https://www.tokyodisneyresort.jp/food/1549/
.
.
.
他にもレストラン名やジャンル(food, drink, meal)を分けてのフィルターもできます。
go run ./cmd/xmas_cli --restaurant ベイサイド --kind drink
実際に上記のコマンドを入力すると下記のような出力を得ることができます。
一致するフードが 1 件見つかりました
1/1 | ホットアップルジンジャードリンク (700円) [drink]
パーク : TDS
エリア : ポートディスカバリー
店舗名 : ベイサイド・テイクアウト
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/453/
詳細URL : https://www.tokyodisneyresort.jp/food/2847/
前提
開発のディレクトリ環境は以下のようになっています
disney_xmas_foods
├── xmas_cli
│ └── main.go
├── data
│ └── foods_xmas.json
└── internal
├── data
│ └── loader.go
└── domain
├── food.go
└── search.go
-
data/foods_xmas.json
→ クリスマスフードのデータ -
internal/domain
→ ドメイン構造体 & 検索ロジック -
internal/data
→ JSON 読み込み -
xmas_cli/main.go
→ CLI 実行ファイル
また、今回は、クリスマスフードの情報が以下のような JSON にまとまっている前提で進めます。
[
{
"id": 1,
"name": "スペシャルセット",
"park": "TDS",
"area": "メディテレーニアンハーバー",
"restaurant": "リストランテ・ディ・カナレット",
"price": 5800,
"kind": "meal",
"url_detail": "https://www.tokyodisneyresort.jp/food/4222/",
"url_restaurant": "https://www.tokyodisneyresort.jp/tds/restaurant/detail/408/"
},
{
"id": 2,
"name": "チョコレートチュロス",
"park": "TDS",
"area": "メディテレーニアンハーバー",
"restaurant": "ザンビーニ・ブラザーズ・リストランテ",
"price": 600,
"kind": "food",
"url_detail": "https://www.tokyodisneyresort.jp/food/1549/",
"url_restaurant": "https://www.tokyodisneyresort.jp/tds/restaurant/detail/403/"
},
.
.
.
{
"id": 36,
"name": "ロゼ・スパークリングワイン(グラス)",
"park": "TDS",
"area": "メディテレーニアンハーバー",
"restaurant": "カフェ・ポルトフィーノ",
"price": 1000,
"kind": "drink",
"url_detail": "https://www.tokyodisneyresort.jp/food/2255/",
"url_restaurant": "https://www.tokyodisneyresort.jp/tds/restaurant/detail/400/"
}
]
スクレイピングをしようとしたけど、ちょっとグレーかなって思ったので、テストデータを作成して実装しました〜
実装
フード情報のデータ構造(internal/domain/food.go)
ここでは、クリスマスフード 1 件分のデータを表す Food 構造体と、検索に使用する条件をまとめた SearchCondition を定義しています。
Food 構造体には、パーク名・エリア名・店舗名・価格・メニューの種類など、検索に必要なすべての情報が含まれています。
また、公式サイトへのリンク(詳細ページ・店舗ページ)も保持しているため、検索結果からそのままアクセスできます。
検索条件をまとめる SearchCondition は、CLI からの入力を受け取り、
「どのパークを検索するか」「どの店舗名で絞るか」などの指定を扱うためのものです。
// internal/domain/food.go
package domain
type Food struct {
ID int `json:"id"`
Name string `json:"name"`
Park string `json:"park"`
Area string `json:"area"`
Restaurant string `json:"restaurant"`
Price int `json:"price"`
Kind string `json:"kind"`
URLDetail string `json:"url_detail"`
URLRestaurant string `json:"url_restaurant"`
}
type SearchCondition struct {
Park string
Area string
Restaurant string
Kind string
}
検索ロジック(internal/domain/search.go)
フード情報を実際に検索するロジックがこちらです。
// internal/domain/search.go
package domain
import "strings"
func SearchFoods(foods []Food, cond SearchCondition) []Food {
var result []Food
for _, food := range foods {
if !matchFood(food, cond) {
continue
}
result = append(result, food)
}
return result
}
func matchFood(food Food, cond SearchCondition) bool {
// 空文字は無視
if cond.Park != "" && !strings.EqualFold(food.Park, cond.Park) {
return false
}
if cond.Area != "" {
// 部分一致 & 大文字小文字を無視
condArea := strings.ToLower(cond.Area)
foodArea := strings.ToLower(food.Area)
if !strings.Contains(foodArea, condArea) {
return false
}
}
if cond.Kind != "" && food.Kind != cond.Kind {
return false
}
if cond.Restaurant != "" {
restLower := strings.ToLower(food.Restaurant)
condLower := strings.ToLower(cond.Restaurant)
if !strings.Contains(restLower, condLower) {
return false
}
}
return true
}
SearchFoods は、全フードデータを走査し、検索条件に一致したものだけを返すシンプルな関数です。
条件のチェック部分は matchFood に切り出されており、
「条件が空の場合は無視」 という仕様になっているため、
ユーザーは指定したい条件だけを CLI で入力すれば OK です。
特にエリア名や店舗名は、完全一致だとミスの影響を受けやすいため、
「部分一致」+「大文字小文字を無視する」 形で柔軟に検索できるようにしています。
ここで実装しているフィルタリングに加えて、
価格帯(例:--max-price や --min-price)を追加したい場合は、
SearchCondition に項目を足して、matchFood に条件分岐を数行追加するだけで実装できます。
JSON ローダー(internal/data/loader.go)
フード情報は JSON 形式で保存されており、それを読み込むのが LoadFoods です。
-
os.ReadFileで JSON ファイルを読み込み -
json.Unmarshalで[]Food型にパース
// internal/data/loader.go
package data
import (
"encoding/json"
"os"
"disney_xmas_foods/internal/domain"
)
func LoadFoods(path string) ([]domain.Food, error) {
file, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var foods []domain.Food
if err := json.Unmarshal(file, &foods); err != nil {
return nil, err
}
return foods, nil
}
実行
CLI から実行するときは、以下のようにフラグを指定して検索できます。
-
--park:TDLorTDS(tdlortds) -
--area: エリア名(部分一致 OK) -
--restaurant: 店舗名(部分一致 OK) -
--kind: food / drink / meal
例えば:
go run main.go --park TDS --area リストランテ
のように入力すれば、条件にマッチしたクリスマス限定フードだけが一覧表示されます!
一致するフードが 8 件見つかりました
1/8 | スペシャルセット (5800円) [meal]
パーク : TDS
エリア : メディテレーニアンハーバー
店舗名 : リストランテ・ディ・カナレット
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/408/
詳細URL : https://www.tokyodisneyresort.jp/food/4222/
2/8 | チョコレートチュロス (600円) [food]
パーク : TDS
エリア : メディテレーニアンハーバー
店舗名 : ザンビーニ・ブラザーズ・リストランテ
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/403/
詳細URL : https://www.tokyodisneyresort.jp/food/1549/
3/8 | スペシャルパスタセット (3800円) [meal]
パーク : TDS
エリア : メディテレーニアンハーバー
店舗名 : リストランテ・ディ・カナレット
店舗URL : https://www.tokyodisneyresort.jp/tds/restaurant/detail/408/
詳細URL : https://www.tokyodisneyresort.jp/food/4223/
.
.
.
まとめ
いかがでしたでしょうか、前日書いたにしてはいい感じに発展性もりもりの初期段階の開発ができたと思います。なかなか上手くいかなくてたのしかったです🙃
今回の Go CLI ツールでは、
- JSON データを読み込んで
- パーク・エリア・店舗名・ジャンルで検索し
- 目的のクリスマス限定メニューを一瞬で取得できる
という機能を実装しました。
本当は、
地図上にアイコンとしてフードをマッピングする Web アプリ
まで実装したかったのですが、まずは検索機能だけを CLI で先に実装しました。
この仕組みを使えば、今後は
- Web API 化してアプリから使えるようにしたり
- 地図上にフードを表示したり
- iPhoneのショートカットと連携したり
といった形で、簡単に機能を広げていくこともできます。
本当は APEX Legends ユーザーのステータス可視化とかやってみたかったんですけど、それはまた今度気が向いたらやってみたいなぁなんておもてます。
最後までご覧いただき、ありがとうございました❕
参考文献

