aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/geocode-facilities.py
blob: 12c727c26c071bdae5f62c8f884882dd6f56fdb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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()