Files
AutoMood/trajet.py
jerem 1cf427a0f2 Ajout suivi prospection : statut, import en masse, message type, trajet+péage
- Statut de prospection (colonne CSV) avec badge coloré et filtre
- Import en masse de liens Facebook (streaming, dédoublonnage)
- Modèle de message de contact configurable + copie en un clic
- Estimation distance/carburant/péage via OpenStreetMap (Nominatim + OSRM)
- Section Paramètres + config.json (non versionné)
2026-06-13 15:28:25 +02:00

109 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Distance routière et coût carburant entre deux adresses (OpenStreetMap : Nominatim + OSRM).
Aucune dépendance ni clé d'API : on utilise les services publics gratuits d'OpenStreetMap
via la bibliothèque standard. Usage personnel et ponctuel (un prospect à la fois).
"""
import json
import re
import urllib.parse
import urllib.request
NOMINATIM = "https://nominatim.openstreetmap.org/search"
OSRM = "https://router.project-osrm.org/route/v1/driving"
# Nominatim impose un User-Agent identifiant l'application
ENTETES = {"User-Agent": "AutoMood/1.0 (outil local de prospection)"}
# Les coordonnées d'une adresse ne changent pas : on évite de re-géocoder (et on
# reste poli envers Nominatim, dont l'usage est limité à ~1 requête/seconde).
_cache_geo = {}
class ErreurTrajet(Exception):
pass
def _http_json(url):
requete = urllib.request.Request(url, headers=ENTETES)
try:
with urllib.request.urlopen(requete, timeout=20) as reponse:
return json.load(reponse)
except Exception as e:
raise ErreurTrajet(f"Service de cartographie injoignable : {e}")
def geocoder(adresse):
"""Adresse texte -> (longitude, latitude). Lève ErreurTrajet si introuvable."""
adresse = (adresse or "").strip()
if not adresse:
raise ErreurTrajet("Adresse vide.")
if adresse in _cache_geo:
return _cache_geo[adresse]
params = urllib.parse.urlencode({
"q": adresse, "format": "json", "limit": 1, "countrycodes": "fr",
})
donnees = _http_json(f"{NOMINATIM}?{params}")
if not donnees:
raise ErreurTrajet(f"Adresse introuvable : « {adresse} ».")
coord = (float(donnees[0]["lon"]), float(donnees[0]["lat"]))
_cache_geo[adresse] = coord
return coord
def _est_autoroute(ref):
"""Vrai si le numéro de route est une autoroute française (« A 11 », « A8;E60 »...).
Heuristique : la plupart des autoroutes « A » sont à péage. Certaines sont
gratuites (rocades, sections urbaines) : l'estimation reste donc approximative.
"""
return any(re.match(r"A\s?\d", t.strip(), re.I) for t in re.split(r"[;,]", ref or ""))
def itineraire(depart, arrivee):
"""(lon, lat) x2 -> (distance_km, duree_min, km_autoroute) du trajet le plus court."""
(lon1, lat1), (lon2, lat2) = depart, arrivee
donnees = _http_json(f"{OSRM}/{lon1},{lat1};{lon2},{lat2}?overview=false&steps=true")
if donnees.get("code") != "Ok" or not donnees.get("routes"):
raise ErreurTrajet("Aucun itinéraire routier trouvé entre ces deux adresses.")
route = donnees["routes"][0]
metres_autoroute = sum(
etape.get("distance", 0)
for jambe in route.get("legs", [])
for etape in jambe.get("steps", [])
if _est_autoroute(etape.get("ref"))
)
return route["distance"] / 1000.0, route["duration"] / 60.0, metres_autoroute / 1000.0
def calculer(adresse_depart, adresse_arrivee, conso_l_100km, prix_carburant, cout_peage_km=0.0):
"""Estime distance, durée, coût carburant et péage (aller simple et aller-retour).
Le péage est estimé : km d'autoroute du trajet × `cout_peage_km` (tarif moyen
paramétrable, en €/km). Mettre 0 pour ne pas compter de péage.
"""
distance_km, duree_min, km_peage = itineraire(
geocoder(adresse_depart), geocoder(adresse_arrivee))
carburant = distance_km / 100.0 * conso_l_100km * prix_carburant
peage = km_peage * cout_peage_km
cout_aller = carburant + peage
return {
"distance_km": round(distance_km, 1),
"distance_aller_retour_km": round(distance_km * 2, 1),
"duree_min": round(duree_min),
"km_peage": round(km_peage, 1),
"carburant_aller": round(carburant, 2),
"carburant_aller_retour": round(carburant * 2, 2),
"peage_aller": round(peage, 2),
"peage_aller_retour": round(peage * 2, 2),
"cout_aller": round(cout_aller, 2),
"cout_aller_retour": round(cout_aller * 2, 2),
}
if __name__ == "__main__":
import sys
if len(sys.argv) != 3:
print("Usage : python trajet.py <adresse-depart> <adresse-arrivee>")
sys.exit(1)
print(json.dumps(calculer(sys.argv[1], sys.argv[2], 6.5, 1.90), ensure_ascii=False, indent=2))