#!/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()