Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save AldeRoberge/7dcb7d712e6a54b3a59a058d636b4a08 to your computer and use it in GitHub Desktop.

Select an option

Save AldeRoberge/7dcb7d712e6a54b3a59a058d636b4a08 to your computer and use it in GitHub Desktop.
Turn Excel addresses into longitude latitude so you can then import them in Google My Maps to build a itinary.
#!/usr/bin/env python3
"""
Geocode the full contact/address table and write coordinates back out.
SETUP (same as before)
-----------------------
1. Geocoding API must be ENABLED on the project.
2. Billing must be ON.
3. Key restricted by IP (not HTTP referrer), API restriction = Geocoding API.
4. Set the key:
set GOOGLE_MAPS_API_KEY=your_key_here (Windows cmd)
$env:GOOGLE_MAPS_API_KEY="your_key_here" (PowerShell)
...or paste it into API_KEY below.
5. pip install requests
6. python geocode_table.py
-> writes contacts_geocoded.csv (UTF-8 with BOM, opens cleanly in Excel)
"""
import csv
import os
import time
import requests
API_KEY = os.environ.get("GOOGLE_MAPS_API_KEY", "THIS_IS_WHERE_ID_PUT_MY_API_KEY_IF_I_HAD_ONE")
REGION_CONTEXT = "Val-d'Or, QC, Canada"
GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json"
# Column order preserved from the source table. "Coordonees" gets filled in.
FIELDS = [
"Nom",
"Statut de l'adresse",
"Adresse",
"District",
"Quartier",
"MP ou commentaire pour suivi",
"Description",
"Coordonees",
"lat",
"lng",
"geocode_status",
"formatted_address",
]
# (Nom, Statut, Adresse, District, Quartier, MP/commentaire, Description)
ROWS = [
("Marcel Bouchard / Ferronnerie Bouchard", "OK", "2287 Rue des Mineurs", "1", "Parc industriel", "Commentaire", ""),
("Hélène Vaillancourt", "OK", "58, chemin Émile-Nelligan", "1", "Lac blouin et centre-ville", "Messagerie", ""),
("Klaus Werner", "OK", "3419 Boulevard Rivière", "3", "Belvedere", "Messagerie", ""),
("Georgette Marchand (Tante Georgette et Armand)", "OK", "92, rue Papineau", "3", "Belvedere", "Messagerie", "819 271-3092"),
("Vénus clinique medico-esthetique", "OK", "740, 5 ieme avenue", "4", "Sullivan", "Commentaire", "Offre rafraichissement ou verre de vin"),
("Karim Bel", "OK", "5578 chemin sullivan", "4", "Sullivan", "Commentaire", ""),
("Josée Tremblay", "OK", "233 rue Fontaine", "4", "Sullivan", "Courriel info", "joseetremblay5678@gmail.com"),
("Guy Painchaud", "OK", "6890 chemin Deschamps", "5", "Val-Senneville", "Messagerie", "Constater l'etat de la rue")
]
def geocode(address: str) -> dict:
query = f"{address}, {REGION_CONTEXT}"
resp = requests.get(
GEOCODE_URL, params={"address": query, "key": API_KEY}, timeout=15
).json()
status = resp.get("status")
if status == "OK":
r = resp["results"][0]
loc = r["geometry"]["location"]
return {
"status": status,
"lat": loc["lat"],
"lng": loc["lng"],
"formatted_address": r.get("formatted_address", ""),
"error_message": "",
}
return {
"status": status,
"lat": "",
"lng": "",
"formatted_address": "",
"error_message": resp.get("error_message", ""),
}
def main() -> None:
if API_KEY == "PASTE_YOUR_SECURED_KEY_HERE":
print("ERROR: No API key set. Edit API_KEY or set GOOGLE_MAPS_API_KEY.")
return
out = []
for nom, statut, adresse, district, quartier, mp, desc in ROWS:
# Skip addresses with nothing usable to geocode.
if not adresse or adresse.strip() in {"", "?"}:
g = {"status": "SKIPPED_NO_ADDRESS", "lat": "", "lng": "",
"formatted_address": "", "error_message": ""}
else:
g = geocode(adresse)
time.sleep(0.1)
coord = f"{g['lat']}, {g['lng']}" if g["lat"] != "" else ""
detail = f" -- {g['error_message']}" if g["error_message"] else ""
print(f"{nom}\t{g['status']}\t{coord}{detail}")
out.append({
"Nom": nom,
"Statut de l'adresse": statut,
"Adresse": adresse,
"District": district,
"Quartier": quartier,
"MP ou commentaire pour suivi": mp,
"Description": desc,
"Coordonees": coord,
"lat": g["lat"],
"lng": g["lng"],
"geocode_status": g["status"],
"formatted_address": g["formatted_address"],
})
# If the API itself is misconfigured, every row fails the same way.
if g["status"] == "REQUEST_DENIED":
print("\nREQUEST_DENIED -- fix the key/API config and re-run.")
break
# utf-8-sig so accents display correctly when opened in Excel.
with open("contacts_geocoded.csv", "w", newline="", encoding="utf-8-sig") as f:
w = csv.DictWriter(f, fieldnames=FIELDS)
w.writeheader()
w.writerows(out)
print("\nWrote contacts_geocoded.csv")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment