189 lines
6.0 KiB
Python
189 lines
6.0 KiB
Python
|
|
"""
|
||
|
|
URA GLS Map API — Full Sample
|
||
|
|
==============================
|
||
|
|
Shows exactly what the API returns with all headers and data.
|
||
|
|
Run from any IP (ArcGIS endpoints are publicly accessible).
|
||
|
|
"""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import requests
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Config (from Env.js)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
ESERVICE = "https://eservice.ura.gov.sg"
|
||
|
|
MAP_HOST = "https://maps.ura.gov.sg"
|
||
|
|
ONEMAP = "https://www.onemap.gov.sg"
|
||
|
|
|
||
|
|
session = requests.Session()
|
||
|
|
session.headers.update({
|
||
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||
|
|
"Referer": f"{ESERVICE}/maps/",
|
||
|
|
"Origin": ESERVICE,
|
||
|
|
})
|
||
|
|
|
||
|
|
|
||
|
|
def show(label, resp):
|
||
|
|
"""Print full request/response details."""
|
||
|
|
print(f"\n{'='*70}")
|
||
|
|
print(f" {label}")
|
||
|
|
print(f"{'='*70}")
|
||
|
|
print(f" URL: {resp.url}")
|
||
|
|
print(f" Status: {resp.status_code}")
|
||
|
|
print(f"\n --- Request Headers ---")
|
||
|
|
for k, v in resp.request.headers.items():
|
||
|
|
print(f" {k}: {v}")
|
||
|
|
print(f"\n --- Response Headers ---")
|
||
|
|
for k, v in resp.headers.items():
|
||
|
|
print(f" {k}: {v}")
|
||
|
|
print(f"\n --- Response Body ---")
|
||
|
|
try:
|
||
|
|
data = resp.json()
|
||
|
|
print(json.dumps(data, indent=2, ensure_ascii=False)[:5000])
|
||
|
|
return data
|
||
|
|
except Exception:
|
||
|
|
print(resp.text[:3000])
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 1. Get OneMap auth token (JSONP)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
print(f"\n{'#'*70}")
|
||
|
|
print(f" STEP 1: Get OneMap Auth Token")
|
||
|
|
print(f"{'#'*70}")
|
||
|
|
|
||
|
|
token_resp = session.get(f"{ESERVICE}/sharedServicesWeb/onemapService/getOnemapToken", timeout=15)
|
||
|
|
print(f"\n URL: {token_resp.url}")
|
||
|
|
print(f" Status: {token_resp.status_code}")
|
||
|
|
print(f" Raw response (JSONP): {token_resp.text[:200]}")
|
||
|
|
|
||
|
|
# Parse JSONP
|
||
|
|
text = token_resp.text.strip()
|
||
|
|
if "(" in text:
|
||
|
|
start = text.index("(") + 1
|
||
|
|
end = text.rindex(")")
|
||
|
|
text = text[start:end]
|
||
|
|
token_data = json.loads(text)
|
||
|
|
onemap_token = token_data["token"]["token"]
|
||
|
|
print(f"\n Parsed token: {onemap_token[:60]}...")
|
||
|
|
print(f" Expiry: {token_data['token']['expiry']}")
|
||
|
|
|
||
|
|
session.headers["Authorization"] = onemap_token
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 2. URA GLS — Layer Metadata
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 2: URA GLS Layer Metadata (what fields exist)",
|
||
|
|
session.get(f"{MAP_HOST}/ArcGis/rest/services/lsag/ura_sale_sites/MapServer/0", params={"f": "json"}, timeout=15),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 3. URA GLS — Query actual parcel data
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 3: URA GLS Parcels (first 3, all fields)",
|
||
|
|
session.get(
|
||
|
|
f"{MAP_HOST}/ArcGis/rest/services/lsag/ura_sale_sites/MapServer/0/query",
|
||
|
|
params={
|
||
|
|
"where": "1=1",
|
||
|
|
"outFields": "*",
|
||
|
|
"f": "json",
|
||
|
|
"resultRecordCount": "3",
|
||
|
|
},
|
||
|
|
timeout=15,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 4. URA GLS — Query with filter (upcoming sites only)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 4: URA GLS — Filtered (SITE_STATUS = 'Launched')",
|
||
|
|
session.get(
|
||
|
|
f"{MAP_HOST}/ArcGis/rest/services/lsag/ura_sale_sites/MapServer/0/query",
|
||
|
|
params={
|
||
|
|
"where": "SITE_STATUS='Launched for Sale'",
|
||
|
|
"outFields": "NAME_GLS,LOCATION,DEVT_ALLOW,GPR,GFA,SA_SQM,LEASE_YR,DATE_LNCH,DATE_CLOSG,SITE_STATUS",
|
||
|
|
"f": "json",
|
||
|
|
"resultRecordCount": "10",
|
||
|
|
},
|
||
|
|
timeout=15,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 5. HDB Sale Sites
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 5: HDB Sale Sites (first 3)",
|
||
|
|
session.get(
|
||
|
|
f"{MAP_HOST}/ArcGis/rest/services/lsag/hdb_sale_sites2/MapServer/0/query",
|
||
|
|
params={
|
||
|
|
"where": "1=1",
|
||
|
|
"outFields": "*",
|
||
|
|
"f": "json",
|
||
|
|
"resultRecordCount": "3",
|
||
|
|
},
|
||
|
|
timeout=15,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 6. JTC Sale Sites
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 6: JTC Sale Sites (first 3)",
|
||
|
|
session.get(
|
||
|
|
f"{MAP_HOST}/arcgis/rest/services/lsag/jtc_sale_sites/MapServer/0/query",
|
||
|
|
params={
|
||
|
|
"where": "1=1",
|
||
|
|
"outFields": "*",
|
||
|
|
"f": "json",
|
||
|
|
"resultRecordCount": "3",
|
||
|
|
},
|
||
|
|
timeout=15,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 7. OneMap Reverse Geocode (with auth header)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
show(
|
||
|
|
"STEP 7: OneMap Reverse Geocode (Orchard Road)",
|
||
|
|
session.get(
|
||
|
|
f"{ONEMAP}/api/public/revgeocode",
|
||
|
|
params={"location": "1.3004,103.8460", "addressType": "all", "otherFeatures": "Y"},
|
||
|
|
timeout=15,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# 8. Map Export URL (server-rendered map image)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
print(f"\n{'#'*70}")
|
||
|
|
print(f" STEP 8: Map Export URLs (open in browser)")
|
||
|
|
print(f"{'#'*70}")
|
||
|
|
|
||
|
|
# Bounding box for Singapore (SVY21 coordinates)
|
||
|
|
# xmin,ymin,xmax,ymax
|
||
|
|
bboxes = {
|
||
|
|
"Central Singapore": "28000,30000,32000,34000",
|
||
|
|
"Full Singapore": "5000,25000,50000,50000",
|
||
|
|
}
|
||
|
|
|
||
|
|
for name, bbox in bboxes.items():
|
||
|
|
url = f"{MAP_HOST}/ArcGis/rest/services/lsag/ura_sale_sites/MapServer/export?f=image&bbox={bbox}&size=800,600&format=png&transparent=false"
|
||
|
|
print(f"\n {name}:")
|
||
|
|
print(f" {url}")
|
||
|
|
|
||
|
|
print(f"\n Open any of these URLs in your browser to see the GLS parcels map!")
|