Skip to content

Commit 952b182

Browse files
committed
fix(scripts): Overpass 406 — User-Agent, form body, mirror fallback
Primary overpass-api.de now rejects bare urllib POSTs. Send Margi User-Agent, application/x-www-form-urlencoded data= query, and retry kumi.systems mirror.
1 parent 6b8e09a commit 952b182

2 files changed

Lines changed: 55 additions & 15 deletions

File tree

‎docs/POI_VERIFICATION_RUNBOOK.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ Human operators phone-verify hospitals along the NH48 Chennai→Chengalpattu cor
99
## Prerequisites
1010

1111
- Python 3.11+ and repo checkout
12-
- OSM ingest completed: `python scripts/ingestCorridors.py --bbox-json data/corridors/nh48_bbox.json --mode demo --min-pois 50 --out data/emergency_seed_raw.db`
12+
- OSM ingest completed (see **Overpass 406** note below): `python scripts/ingestCorridors.py --bbox-json data/corridors/nh48_bbox.json --mode demo --min-pois 50 --out data/emergency_seed_raw.db`
1313
- Spreadsheet or text editor for CSV edits
1414
- Tamil/English phone script (below)
1515

16+
### Overpass HTTP 406
17+
18+
If ingest prints `HTTP Error 406: Not Acceptable`, update to latest `scripts/ingestCorridors.py` (sends `User-Agent` + form-encoded `data=` body, retries mirror). Success looks like: `Overpass OK via …` and `Fetched N hospitals from OSM`.
19+
1620
---
1721

1822
## CSV columns

‎scripts/ingestCorridors.py‎

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@
1414
import json
1515
import sqlite3
1616
import sys
17+
import urllib.error
18+
import urllib.parse
1719
import urllib.request
1820
from pathlib import Path
1921

2022
# Chennai corridor bbox (demo fallback)
2123
DEFAULT_BBOX = (12.85, 79.90, 13.15, 80.35)
22-
OVERPASS = "https://overpass-api.de/api/interpreter"
24+
OVERPASS_ENDPOINTS = (
25+
"https://overpass-api.de/api/interpreter",
26+
"https://overpass.kumi.systems/api/interpreter",
27+
)
28+
USER_AGENT = "Margi-C1-POI-Ingest/1.0 (+https://github.com/Stormynubee/Margi)"
2329

2430

2531
def load_bbox(bbox_json: Path | None) -> tuple[float, float, float, float]:
@@ -29,19 +35,48 @@ def load_bbox(bbox_json: Path | None) -> tuple[float, float, float, float]:
2935
return (data["south"], data["west"], data["north"], data["east"])
3036

3137

32-
def fetch_hospitals(bbox: tuple[float, float, float, float]) -> list[dict]:
38+
def build_hospital_query(bbox: tuple[float, float, float, float]) -> str:
3339
south, west, north, east = bbox
34-
query = f"""
35-
[out:json][timeout:25];
36-
(
37-
node["amenity"="hospital"]({south},{west},{north},{east});
38-
way["amenity"="hospital"]({south},{west},{north},{east});
39-
);
40-
out center 50;
41-
"""
42-
req = urllib.request.Request(OVERPASS, data=query.encode(), method="POST")
43-
with urllib.request.urlopen(req, timeout=60) as resp:
44-
data = json.load(resp)
40+
return f"""[out:json][timeout:60];
41+
(
42+
node["amenity"="hospital"]({south},{west},{north},{east});
43+
way["amenity"="hospital"]({south},{west},{north},{east});
44+
);
45+
out center 50;
46+
"""
47+
48+
49+
def overpass_query(query: str, endpoint: str) -> dict:
50+
"""POST Overpass QL; uses form field `data` and required User-Agent."""
51+
body = urllib.parse.urlencode({"data": query}).encode("utf-8")
52+
req = urllib.request.Request(
53+
endpoint,
54+
data=body,
55+
method="POST",
56+
headers={
57+
"User-Agent": USER_AGENT,
58+
"Accept": "*/*",
59+
"Content-Type": "application/x-www-form-urlencoded",
60+
},
61+
)
62+
with urllib.request.urlopen(req, timeout=90) as resp:
63+
return json.load(resp)
64+
65+
66+
def fetch_hospitals(bbox: tuple[float, float, float, float]) -> list[dict]:
67+
query = build_hospital_query(bbox)
68+
last_error: Exception | None = None
69+
data: dict | None = None
70+
for endpoint in OVERPASS_ENDPOINTS:
71+
try:
72+
data = overpass_query(query, endpoint)
73+
print(f"Overpass OK via {endpoint}")
74+
break
75+
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError, json.JSONDecodeError) as e:
76+
last_error = e
77+
print(f"Overpass failed via {endpoint}: {e}", file=sys.stderr)
78+
if data is None:
79+
raise RuntimeError(f"All Overpass endpoints failed: {last_error}")
4580
nodes = []
4681
for el in data.get("elements", []):
4782
lat = el.get("lat") or (el.get("center") or {}).get("lat")
@@ -169,8 +204,9 @@ def main() -> None:
169204
if not args.skip_fetch:
170205
try:
171206
rows = fetch_hospitals(bbox)
207+
print(f"Fetched {len(rows)} hospitals from OSM")
172208
except Exception as e:
173-
print(f"Overpass failed ({e}); using empty row list.")
209+
print(f"Overpass failed ({e}); using empty row list.", file=sys.stderr)
174210
rows = []
175211

176212
write_db(

0 commit comments

Comments
 (0)