mirror of
https://forge.chapril.org/tykayn/parking-land
synced 2025-06-20 01:44:42 +02:00
341 lines
No EOL
13 KiB
Python
Executable file
341 lines
No EOL
13 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Script pour trouver l'identifiant OpenStreetMap d'une ville à partir de son nom.
|
|
Utilise l'API Nominatim pour effectuer la recherche.
|
|
"""
|
|
|
|
import sys
|
|
import argparse
|
|
import requests
|
|
import json
|
|
import time
|
|
import os
|
|
import subprocess
|
|
from urllib.parse import quote
|
|
|
|
def search_city(city_name, country=None, limit=5):
|
|
"""
|
|
Recherche une ville par son nom en utilisant l'API Nominatim d'OpenStreetMap.
|
|
|
|
Args:
|
|
city_name (str): Nom de la ville à rechercher
|
|
country (str, optional): Code pays pour filtrer les résultats (ex: 'fr', 'be', 'ch')
|
|
limit (int, optional): Nombre maximum de résultats à retourner
|
|
|
|
Returns:
|
|
list: Liste des correspondances trouvées
|
|
"""
|
|
# Construire l'URL de recherche
|
|
base_url = "https://nominatim.openstreetmap.org/search"
|
|
|
|
# Paramètres de recherche
|
|
params = {
|
|
'q': city_name,
|
|
'format': 'json',
|
|
'addressdetails': 1,
|
|
'limit': limit,
|
|
'polygon_geojson': 0,
|
|
}
|
|
|
|
# Ajouter le filtre de pays si spécifié
|
|
if country:
|
|
params['countrycodes'] = country
|
|
|
|
# Ajouter des paramètres pour filtrer les résultats par type
|
|
params['featuretype'] = 'city'
|
|
|
|
# En-têtes pour respecter les conditions d'utilisation de Nominatim
|
|
headers = {
|
|
'User-Agent': 'CityOSMIDFinder/1.0',
|
|
'Accept-Language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
}
|
|
|
|
try:
|
|
# Effectuer la requête
|
|
response = requests.get(base_url, params=params, headers=headers)
|
|
|
|
# Vérifier si la requête a réussi
|
|
if response.status_code != 200:
|
|
print(f"Erreur lors de la requête: {response.status_code}")
|
|
return []
|
|
|
|
# Analyser les résultats
|
|
results = response.json()
|
|
|
|
# Filtrer pour ne garder que les villes/villages
|
|
filtered_results = []
|
|
for result in results:
|
|
# Vérifier si c'est une ville ou un village
|
|
if 'address' in result:
|
|
place_type = None
|
|
for key in ['city', 'town', 'village', 'municipality', 'hamlet']:
|
|
if key in result['address']:
|
|
place_type = key
|
|
break
|
|
|
|
if place_type:
|
|
# Ajouter des informations supplémentaires
|
|
result['place_type'] = place_type
|
|
|
|
# Rechercher l'ID de relation
|
|
osm_id = result.get('osm_id')
|
|
osm_type = result.get('osm_type')
|
|
|
|
if osm_id and osm_type:
|
|
# Convertir le type en majuscule pour la première lettre
|
|
osm_type = osm_type.capitalize()
|
|
|
|
# Ajouter à la liste filtrée
|
|
filtered_results.append(result)
|
|
|
|
return filtered_results
|
|
|
|
except Exception as e:
|
|
print(f"Erreur lors de la recherche: {str(e)}")
|
|
return []
|
|
|
|
def get_relation_id(osm_type, osm_id):
|
|
"""
|
|
Récupère l'ID de relation pour un élément OSM.
|
|
Si l'élément est déjà une relation, retourne simplement son ID.
|
|
Sinon, essaie de trouver une relation associée.
|
|
|
|
Args:
|
|
osm_type (str): Type d'élément OSM ('Node', 'Way', 'Relation')
|
|
osm_id (int): ID de l'élément OSM
|
|
|
|
Returns:
|
|
int: ID de la relation ou None si aucune relation n'est trouvée
|
|
"""
|
|
if osm_type == 'Relation':
|
|
return osm_id
|
|
|
|
# Pour les nodes et ways, on doit chercher la relation associée
|
|
# Construire la requête Overpass
|
|
if osm_type == 'Node':
|
|
query = f"""
|
|
[out:json];
|
|
node({osm_id});
|
|
is_in->.a;
|
|
relation.a["admin_level"="8"];
|
|
out ids;
|
|
"""
|
|
elif osm_type == 'Way':
|
|
query = f"""
|
|
[out:json];
|
|
way({osm_id});
|
|
is_in->.a;
|
|
relation.a["admin_level"="8"];
|
|
out ids;
|
|
"""
|
|
else:
|
|
return None
|
|
|
|
# Envoyer la requête à l'API Overpass
|
|
try:
|
|
overpass_url = "https://overpass-api.de/api/interpreter"
|
|
response = requests.post(overpass_url, data={"data": query})
|
|
|
|
if response.status_code != 200:
|
|
print(f"Erreur lors de la requête Overpass: {response.status_code}")
|
|
return None
|
|
|
|
data = response.json()
|
|
|
|
# Extraire l'ID de relation
|
|
if 'elements' in data and data['elements']:
|
|
for element in data['elements']:
|
|
if element.get('type') == 'relation':
|
|
return element.get('id')
|
|
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"Erreur lors de la récupération de l'ID de relation: {str(e)}")
|
|
return None
|
|
|
|
def display_results(results):
|
|
"""
|
|
Affiche les résultats de recherche de manière formatée.
|
|
|
|
Args:
|
|
results (list): Liste des résultats de recherche
|
|
"""
|
|
if not results:
|
|
print("Aucun résultat trouvé.")
|
|
return
|
|
|
|
print(f"\n{len(results)} résultat(s) trouvé(s):\n")
|
|
|
|
for i, result in enumerate(results, 1):
|
|
# Extraire les informations
|
|
name = result.get('display_name', 'Nom inconnu')
|
|
osm_type = result.get('osm_type', '').capitalize()
|
|
osm_id = result.get('osm_id', 'ID inconnu')
|
|
place_type = result.get('place_type', 'Type inconnu')
|
|
|
|
# Extraire les informations d'adresse
|
|
address = result.get('address', {})
|
|
city = address.get('city', address.get('town', address.get('village', address.get('municipality', address.get('hamlet', '')))))
|
|
county = address.get('county', '')
|
|
state = address.get('state', '')
|
|
country = address.get('country', '')
|
|
|
|
# Afficher les informations
|
|
print(f"{i}. {city} ({place_type})")
|
|
print(f" Localisation: {county}, {state}, {country}")
|
|
print(f" OSM ID: {osm_id} (Type: {osm_type})")
|
|
print(f" URL: https://www.openstreetmap.org/{osm_type.lower()}/{osm_id}")
|
|
|
|
# Rechercher l'ID de relation si ce n'est pas déjà une relation
|
|
if osm_type != 'Relation':
|
|
print(" Recherche de l'ID de relation associé...")
|
|
relation_id = get_relation_id(osm_type, osm_id)
|
|
if relation_id:
|
|
print(f" ID de relation: {relation_id}")
|
|
print(f" URL de relation: https://www.openstreetmap.org/relation/{relation_id}")
|
|
else:
|
|
print(" Aucune relation trouvée.")
|
|
|
|
print()
|
|
|
|
def generate_map(osm_id, output_path=None, use_folium=True, verbose=False):
|
|
"""
|
|
Génère une carte pour la ville avec l'ID OpenStreetMap spécifié.
|
|
|
|
Args:
|
|
osm_id (int): ID OpenStreetMap de la ville
|
|
output_path (str, optional): Chemin où sauvegarder la carte
|
|
use_folium (bool, optional): Utiliser Folium au lieu d'OSMnx
|
|
verbose (bool, optional): Afficher les messages de débogage
|
|
|
|
Returns:
|
|
str: Chemin vers la carte générée ou None en cas d'erreur
|
|
"""
|
|
try:
|
|
# Vérifier si le script generate_city_map.py existe
|
|
if not os.path.exists("generate_city_map.py"):
|
|
print("Erreur: Le script generate_city_map.py n'a pas été trouvé.")
|
|
return None
|
|
|
|
# Construire la commande
|
|
cmd = ["python", "generate_city_map.py", str(osm_id)]
|
|
|
|
# Ajouter les options
|
|
if output_path:
|
|
cmd.extend(["-o", output_path])
|
|
if use_folium:
|
|
cmd.append("--folium")
|
|
if verbose:
|
|
cmd.append("-v")
|
|
|
|
# Exécuter la commande
|
|
print(f"Génération de la carte pour l'ID OSM {osm_id}...")
|
|
print(f"Commande: {' '.join(cmd)}")
|
|
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
|
|
# Vérifier si la commande a réussi
|
|
if result.returncode == 0:
|
|
output_file = output_path if output_path else "city_map.html" if use_folium else "city_map.jpg"
|
|
print(f"Carte générée avec succès: {output_file}")
|
|
|
|
# Afficher les messages de sortie si verbose
|
|
if verbose:
|
|
print("\nSortie de la commande:")
|
|
print(result.stdout)
|
|
|
|
return output_file
|
|
else:
|
|
print(f"Erreur lors de la génération de la carte (code {result.returncode}):")
|
|
print(result.stderr)
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"Erreur lors de la génération de la carte: {str(e)}")
|
|
return None
|
|
|
|
def main():
|
|
"""
|
|
Fonction principale qui traite les arguments de ligne de commande
|
|
et effectue la recherche.
|
|
"""
|
|
parser = argparse.ArgumentParser(description='Recherche l\'identifiant OpenStreetMap d\'une ville à partir de son nom.')
|
|
parser.add_argument('city_name', type=str, help='Nom de la ville à rechercher')
|
|
parser.add_argument('-c', '--country', type=str, help='Code pays pour filtrer les résultats (ex: fr, be, ch)', default='fr')
|
|
parser.add_argument('-l', '--limit', type=int, default=5, help='Nombre maximum de résultats à afficher (défaut: 5)')
|
|
parser.add_argument('-j', '--json', action='store_true', help='Afficher les résultats au format JSON', default=False)
|
|
parser.add_argument('-r', '--relation-only', action='store_true', help='Afficher uniquement les IDs de relation', default=False)
|
|
|
|
# Nouvelles options pour la génération de carte
|
|
parser.add_argument('-g', '--generate-map', action='store_true', default=True,
|
|
help='Générer automatiquement une carte pour le premier résultat (actif par défaut)')
|
|
parser.add_argument('-ng', '--no-generate-map', action='store_false', dest='generate_map',
|
|
help='Ne pas générer automatiquement de carte')
|
|
parser.add_argument('-o', '--output', type=str, default='carte_ville.html',
|
|
help='Chemin où sauvegarder la carte générée (défaut: carte_ville.html)')
|
|
parser.add_argument('--no-folium', action='store_false', dest='use_folium',
|
|
help='Utiliser OSMnx au lieu de Folium pour la génération de carte', default=True)
|
|
parser.add_argument('-v', '--verbose', action='store_true',
|
|
help='Afficher les messages de débogage')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Effectuer la recherche
|
|
print(f"Recherche de la ville: {args.city_name}")
|
|
if args.country:
|
|
print(f"Filtrage par pays: {args.country}")
|
|
|
|
results = search_city(args.city_name, args.country, args.limit)
|
|
|
|
# Afficher les résultats
|
|
if args.json:
|
|
print(json.dumps(results, indent=2))
|
|
elif args.relation_only:
|
|
for result in results:
|
|
osm_type = result.get('osm_type', '').capitalize()
|
|
osm_id = result.get('osm_id', '')
|
|
|
|
if osm_type == 'Relation':
|
|
print(f"{osm_id}")
|
|
else:
|
|
relation_id = get_relation_id(osm_type, osm_id)
|
|
if relation_id:
|
|
print(f"{relation_id}")
|
|
else:
|
|
display_results(results)
|
|
|
|
# Générer une carte si demandé et si des résultats ont été trouvés
|
|
if args.generate_map and results:
|
|
# Prendre le premier résultat
|
|
first_result = results[0]
|
|
osm_type = first_result.get('osm_type', '').capitalize()
|
|
osm_id = first_result.get('osm_id', '')
|
|
|
|
# Obtenir l'ID de relation si nécessaire
|
|
if osm_type != 'Relation':
|
|
relation_id = get_relation_id(osm_type, osm_id)
|
|
if relation_id:
|
|
osm_id = relation_id
|
|
else:
|
|
print("Aucune relation trouvée pour ce résultat. Utilisation de l'ID original.")
|
|
|
|
# Générer la carte
|
|
if osm_id:
|
|
print("\n--- Génération automatique de la carte ---")
|
|
map_path = generate_map(osm_id, args.output, args.use_folium, args.verbose)
|
|
|
|
if map_path:
|
|
print(f"\nCarte générée avec succès: {map_path}")
|
|
|
|
# Si c'est un fichier HTML, suggérer de le convertir en JPG
|
|
if map_path.endswith('.html'):
|
|
print("\nPour convertir cette carte HTML en image JPG, utilisez la commande:")
|
|
print(f"python html2jpg.py {map_path} -o {os.path.splitext(map_path)[0]}.jpg")
|
|
else:
|
|
print("\nÉchec de la génération de la carte.")
|
|
|
|
if __name__ == "__main__":
|
|
main() |