aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/geocode-facilities.py
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-24 12:29:24 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-24 12:29:24 +0900
commita71727538f65ab4f10f5239550be82590f9d47d1 (patch)
tree4608d37faead4f253c3311982a400a8fb88fba9e /scripts/geocode-facilities.py
parentc7efe674b34a2949b76d62bb71a972427965af92 (diff)
parks: 公園一覧と地図、公共施設の情報を更新
- 近隣公園のクリックを市内公園と同じ挙動にし、Googleマップを公園名で開く - 公共施設のトイレを○にし、ルネこだいらを追加 - 未取得だった施設の座標を追加し、再ジオコーディング時の上書きを防止 - 手入力ポリゴン、近隣公園、PWA、ライセンス表示を追加
Diffstat (limited to 'scripts/geocode-facilities.py')
-rw-r--r--scripts/geocode-facilities.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/scripts/geocode-facilities.py b/scripts/geocode-facilities.py
new file mode 100644
index 0000000..12c727c
--- /dev/null
+++ b/scripts/geocode-facilities.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+"""小平市の公共施設JSONに緯度・経度を付与する(Nominatim)。
+
+使い方:
+ py -X utf8 scripts/geocode-facilities.py
+
+- `src/data/kodaira-facilities.json` の各施設に lat / lon / geocode を追加する。
+- 住所で見つからない場合は「小平市 + 施設名」で再試行する。
+- 見つからない場合は lat / lon を null にし、note に理由を追記する。
+- Nominatimの利用ポリシーに従い、1リクエストあたり約1.1秒待つ。
+"""
+import json
+import time
+import urllib.parse
+import urllib.request
+
+PATH = "src/data/kodaira-facilities.json"
+UA = "yasutakeyohei.com facilities geocoder (park list)"
+
+# 住所・名称検索では正しい位置にならない施設。手動の座標を優先する。
+# 値は ((緯度, 経度), geocodeラベル)。
+MANUAL = {
+ "小平市役所(本庁)": ((35.7279025, 139.4774885), "手動補正"),
+ "西部出張所": ((35.735038, 139.461827), "小川西町図書館と同じ建物として補正"),
+ "小川分室": ((35.72604, 139.459319), "小川公民館と同じ建物として補正"),
+ "東部出張所": ((35.7279272, 139.5140803), "東部市民センターと同じ建物として補正"),
+ "喜平図書館": ((35.7173213, 139.4908793), "名称"),
+}
+
+
+def geocode(query):
+ url = (
+ "https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&countrycodes=jp&q="
+ + urllib.parse.quote(query)
+ )
+ req = urllib.request.Request(url, headers={"User-Agent": UA})
+ with urllib.request.urlopen(req, timeout=30) as r:
+ data = json.loads(r.read().decode("utf-8"))
+ if not data:
+ return None
+ return float(data[0]["lat"]), float(data[0]["lon"])
+
+
+def main():
+ data = json.load(open(PATH, encoding="utf-8"))
+ for i, f in enumerate(data, 1):
+ name = f.get("name", "")
+ address = f.get("address", "")
+ if name in MANUAL:
+ (lat, lon), label = MANUAL[name]
+ f["lat"], f["lon"] = lat, lon
+ f["geocode"] = label
+ f["note"] = str(f.get("note", "")).replace("地図の位置は未取得。", "").strip()
+ print(f"{i}/{len(data)} {name}: {lat:.6f},{lon:.6f} ({label})")
+ continue
+ found = None
+ source = ""
+ if address:
+ found = geocode("東京都" + address)
+ source = "住所"
+ if not found and name:
+ time.sleep(1.1)
+ found = geocode("小平市" + name)
+ source = "名称"
+ if found and found[0] is not None:
+ f["lat"], f["lon"] = found
+ f["geocode"] = source
+ f["note"] = str(f.get("note", "")).replace("地図の位置は未取得。", "").strip()
+ print(f"{i}/{len(data)} {name}: {found[0]:.6f},{found[1]:.6f} ({source})")
+ else:
+ f["lat"], f["lon"] = None, None
+ f["geocode"] = ""
+ note = str(f.get("note", "")).strip()
+ if "地図の位置は未取得。" not in note:
+ f["note"] = (note + " " if note else "") + "地図の位置は未取得。"
+ print(f"{i}/{len(data)} {name}: NOT FOUND")
+ time.sleep(1.1)
+ with open(PATH, "w", encoding="utf-8") as fh:
+ json.dump(data, fh, ensure_ascii=False, indent=2)
+ fh.write("\n")
+ ok = sum(1 for f in data if f.get("lat") is not None)
+ print(f"geocoded {ok} / {len(data)} -> {PATH}")
+
+
+if __name__ == "__main__":
+ main()