Compare commits

..

14 Commits

13 changed files with 443 additions and 235 deletions

View File

@ -3,6 +3,11 @@
Récupération de Données OSM via Overpass
## Prérequis
### Installation de Python
- [Windows](docs/python_windows.md).
- Linux : cest installé sur les distributions.
### Installation des dépendances
`pip3 install requests`
`pip3 install pyexcel-ods3`
@ -45,10 +50,20 @@ Ces chemins sont relatifs à `rdoo.py`, il est possible de passer des chemins ab
Il est possible de ne pas archiver en passant l'argument `-na, --no-archive`.
## Umap
Les fichiers json générés peuvent être directements utilisés dans [umap](https://umap.openstreetmap.fr/fr/) en les [important](https://wiki.openstreetmap.org/wiki/FR:UMap/Guide/Importer_un_fichier_de_donn%C3%A9es) et choisissant le format de données `osm`.
### Concaténation des tags dans l'export json
`-nc, --no-concatenation`, pour ne pas concaténer les tags dans le champ description du json exporté.
Si vous disposez d'un serveur pour héberger le script ou ses résultats, le lien du fichier peut être utilisé directement dans umap comme `données distantes` d'un calque, en cochant `dynamique` et `avec proxy`.
### Timeout
`-t, --timeout`, pour définir le timeout en secondes de la requêt Overpass (défaut 25s).
## Traductions
Les tags peuvent être traduits grâce au fichier `traductions.json` contenant la configuration sous la forme `"clef" : "tableau_de_valeurs"` où la clef est la valeur du tag OSM à traduire et le tableau de valeurs est de la forme `"valeur" : "traduction"`. Le fichier par défaut contient l'exemple de la traduction du tag `"bicycle_parking"`.
## Umap
[Utilisation avec Umap](docs/umap.md)
## Requêtes personnalisées
[Requêtes personnalisées](docs/requetes_perso.md)
## Inspirations / ressources :
### urls ressources

View File

@ -0,0 +1,148 @@
{
"CHAMPS_STATIONNEMENT": {
"amenity": {
"export_json": "Non",
"FR": "aménagement"
},
"capacity": {
"export_json": "Oui",
"FR": "nombre d'emplacements"
},
"access": {
"export_json": "Oui",
"FR": "accès"
},
"bicycle_parking": {
"export_json": "Oui",
"FR": "type"
},
"covered": {
"export_json": "Oui",
"FR": "couvert"
},
"operator": {
"export_json": "Oui",
"FR": "opérateur"
},
"operator:type": {
"export_json": "Oui",
"FR": "type d'opérateur"
},
"fee": {
"export_json": "Oui",
"FR": "frais"
},
"check_date:capacity": {
"export_json": "Non",
"FR": "date_vérification"
},
"source": {
"export_json": "Non",
"FR": "source"
}
},
"CHAMPS_POI": {
"name": {
"export_json": "Oui",
"FR": ""
},
"description": {
"export_json": "Oui",
"FR": ""
},
"website": {
"export_json": "Oui",
"FR": ""
},
"addr:housenumber": {
"export_json": "Oui",
"FR": ""
},
"addr:street": {
"export_json": "Oui",
"FR": ""
},
"addr:postcode": {
"export_json": "Oui",
"FR": ""
},
"addr:city": {
"export_json": "Oui",
"FR": ""
},
"contact:email": {
"export_json": "Oui",
"FR": "email"
},
"contact:twitter": {
"export_json": "Oui",
"FR": "Twitter"
},
"contact:facebook": {
"export_json": "Oui",
"FR": "Facebook"
},
"contact:phone": {
"export_json": "Oui",
"FR": "Téléphone"
},
"network": {
"export_json": "Oui",
"FR": "Réseau"
},
"office": {
"export_json": "Oui",
"FR": "Bureau"
},
"opening_hours": {
"export_json": "Oui",
"FR": "Horaires"
}
},
"CHAMPS_ADRESSE": {
"api_adresse:geometry:coordinates:lon": {
"export_json": "Non",
"FR": "lon_adresse_etalab"
},
"api_adresse:geometry:coordinates:lat": {
"export_json": "Non",
"FR": "lat_adresse_etalab"
},
"api_adresse:properties:label": {
"export_json": "Non",
"FR": "adresse_etalab"
},
"api_adresse:properties:score": {
"export_json": "Non",
"FR": "score_etalab"
},
"api_adresse:properties:housenumber": {
"export_json": "Non",
"FR": "numero_etalab"
},
"api_adresse:properties:type": {
"export_json": "Non",
"FR": "type_etalab"
},
"api_adresse:properties:name": {
"export_json": "Non",
"FR": "numero_et_voie_etalab"
},
"api_adresse:properties:postcode": {
"export_json": "Non",
"FR": "code_postal_etalab"
},
"api_adresse:properties:citycode": {
"export_json": "Non",
"FR": "code_INSEE_etalab"
},
"api_adresse:properties:city": {
"export_json": "Non",
"FR": "ville_etalab"
},
"api_adresse:properties:street": {
"export_json": "Non",
"FR": "rue_etalab"
}
}
}

View File

@ -0,0 +1,96 @@
{
"stationnements_velos_non_publics": {
"overpass": "nwr[\"amenity\"=\"bicycle_parking\"][\"access\"~\"(no|permit|private|customers|permissive)\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_STATIONNEMENT",
"CHAMPS_ADRESSE"
],
"champ_local": ""
},
"stationnements_velos_publics": {
"overpass": "nwr[\"amenity\"=\"bicycle_parking\"](area:aire_de_recherche); - nwr[\"amenity\"=\"bicycle_parking\"][\"access\"~\"(no|permit|private|customers|permissive)\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_STATIONNEMENT",
"CHAMPS_ADRESSE"
],
"champ_local": ""
},
"ateliers_autoreparation": {
"overpass": "nwr[\"service:bicycle:diy\"=\"yes\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"service:bicycle:diy": {
"export_json": "Non",
"FR": ""
}
}
},
"associations_velo": {
"overpass": "nwr[\"association\"=\"bicycle\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"association": {
"export_json": "Non",
"FR": ""
}
}
},
"fabriquants_velo": {
"overpass": "nwr[\"craft\"=\"bicycle\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"craft": {
"export_json": "Non",
"FR": ""
}
}
},
"vendeurs_velo": {
"overpass": "nwr[\"shop\"=\"bicycle\"](area:aire_de_recherche); nwr[\"service:bicycle:retail\"=\"yes\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"shop": {
"export_json": "Non",
"FR": ""
}
}
},
"velos_libre_service": {
"overpass": "nwr[\"amenity\"=\"bicycle_rental\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"amenity": {
"export_json": "Non",
"FR": ""
}
}
},
"location_velo": {
"overpass": "nwr[\"service:bicycle:rental\"=\"yes\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": {
"service:bicycle:rental": {
"export_json": "Non",
"FR": ""
}
}
}
}

View File

@ -0,0 +1,23 @@
{
"bicycle_parking": {
"stands": "Arceaux",
"wall_loops": "Pince roues",
"rack": "Râteliers",
"anchors": "Ancrage",
"shed": "Abri collectif",
"bollard": "Potelet",
"lockers": "Abris individuels",
"wide_stands": "Arceaux espacés",
"ground_slots": "Fente dans le sol",
"building": "Bâtiment",
"informal": "Informel",
"wave": "Râteliers",
"streetpod": "Arceaux",
"tree": "Arbre à bicyclettes",
"crossbar": "Barre",
"rope": "Câble",
"two-tier": "Deux étages",
"floor": "Sol",
"handlebar_holder": "Accroche-guidons"
}
}

13
docs/python‍_windows.md Normal file
View File

@ -0,0 +1,13 @@
## Installer python
- Télécharger la dernière version de [Python](https://www.python.org/downloads/)
- Lancer l'installeur
- Cocher "Add python.exe to path"
- Se placer dans le dossier de travail
- Ouvrir une console windows (raccourci en écrivant "cmd" dans la barre de l'explorateur)
- Installer les pré-requis
- Télécharger l'[archive](https://forge.chapril.org/SebF/RDOO/archive/master.zip) de RDOO
- Décompresser l'archive
- Ouvrir rdoo.py avec IDLE
- Modifier éventuellement les requêtes (nécessite de connaître la syntaxe Overpass)
- Lancer le script Run - Run module (F5)
- Lancer le script Run - Run... customized (shift+F5) pour ajouter les options

32
docs/requetes_perso.md Normal file
View File

@ -0,0 +1,32 @@
## Requêtes personnalisées
Les requêtes sont stockées dans le fichier [requetes.json](../configuration/requetes.json) qui contient un tableau de requêtes.
### Requêtes
```json
"fontaines": {
"commentaire": "champ de texte libre",
"overpass": "nwr[\"amenity\"=\"fountain\"](area:aire_de_recherche);",
"champs_generiques": [
"CHAMPS_POI",
"CHAMPS_ADRESSE"
],
"champ_local": ""
}
```
Un bloc de requête commence par son nom et nécessite obligatoirement :
- la chaîne de recherche `overpass` (penser à échapper les `"` avec `\`) ([overpass turbo](https://overpass-turbo.eu/), [wiki Overpass_QL](https://wiki.openstreetmap.org/wiki/FR:Overpass_API/Overpass_QL))
- les `champs_generiques` utilisés, qui contiennent les informations de tags osm ou géocodage
- le `champ_local` utilisé.
Il peut aussi contenir un `commentaire` qui ne serait pas interprété par rdoo.
### Champs
Les champs génériques sont stockées dans le fichier [champs_generiques.json](../configuration/champs_generiques.json) et sont divisés en 3 blocs :
- `CHAMPS_STATIONNEMENT` pour les tags liés au stationnement vélo
- `CHAMPS_POI` pour les tags liés aux informations classiques (nom, description, moyens de contact, addresse)
- `CHAMPS_ADRESSE` pour les tags correspondant au géocodage inversé via Etalab.
### Traduction
Les traductions sont stockées dans le fichier [traductions.json](../configuration/traductions.json), le tag à traduire est suivi d'un tableau de correspondance des valeurs à traduire.

11
docs/umap.md Normal file
View File

@ -0,0 +1,11 @@
## Utilisation avec Umap
### Import
Les fichiers json générés peuvent être directements utilisés dans [umap](https://umap.openstreetmap.fr/fr/) en les [important](https://wiki.openstreetmap.org/wiki/FR:UMap/Guide/Importer_un_fichier_de_donn%C3%A9es) et choisissant le format de données `osm`.
![configuration import](umap_import.png)
### Distant
Si vous disposez d'un serveur pour héberger le script ou ses résultats, le lien du fichier peut être utilisé directement dans umap comme `données distantes` d'un calque, en cochant `dynamique` et `avec proxy`, au format de données `osm`.
![configuration distante](umap_distant.png)

BIN
docs/umap_distant.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
docs/umap_import.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -1,166 +0,0 @@
#!/usr/bin/env python3
# Copyright 2021 Olav63, SebF
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Module des requêtes"""
class Requete:
"""Objet requête"""
nom: str
critere: str
champs: dict
def __init__(self, nom, critere, champs):
self.nom = nom
self.critere = critere
self.champs = champs
REQS = []
CHAMPS_STATIONNEMENT = {
"amenity": {"export_json": "Non", "FR": "aménagement"},
"capacity": {"export_json": "Oui", "FR": "nombre d'emplacements"},
"access": {"export_json": "Oui", "FR": "accès"},
"bicycle_parking": {"export_json": "Oui", "FR": "type"},
"covered": {"export_json": "Oui", "FR": "couvert"},
"operator": {"export_json": "Oui", "FR": "opérateur"},
"operator:type": {"export_json": "Oui", "FR": "type d'opérateur"},
"fee": {"export_json": "Oui", "FR": "frais"},
"check_date:capacity": {"export_json": "Non", "FR": "date_vérification"},
"source": {"export_json": "Non", "FR": "source"},
}
CHAMPS_POI = {
"name": {"export_json": "Oui", "FR": ""},
"description": {"export_json": "Oui", "FR": ""},
"website": {"export_json": "Oui", "FR": ""},
"addr:housenumber": {"export_json": "Oui", "FR": ""},
"addr:street": {"export_json": "Oui", "FR": ""},
"addr:postcode": {"export_json": "Oui", "FR": ""},
"addr:city": {"export_json": "Oui", "FR": ""},
"contact:email": {"export_json": "Oui", "FR": "email"},
"contact:twitter": {"export_json": "Oui", "FR": "Twitter"},
"contact:facebook": {"export_json": "Oui", "FR": "Facebook"},
"contact:phone": {"export_json": "Oui", "FR": "Téléphone"},
"network": {"export_json": "Oui", "FR": "Réseau"},
"office": {"export_json": "Oui", "FR": "Bureau"},
"opening_hours": {"export_json": "Oui", "FR": "Horaires"},
}
CHAMPS_ADRESSE = {
"api_adresse:geometry:coordinates:lon": {
"export_json": "Non",
"FR": "lon_adresse_etalab",
},
"api_adresse:geometry:coordinates:lat": {
"export_json": "Non",
"FR": "lat_adresse_etalab",
},
"api_adresse:properties:label": {"export_json": "Non", "FR": "adresse_etalab"},
"api_adresse:properties:score": {"export_json": "Non", "FR": "score_etalab"},
"api_adresse:properties:housenumber": {"export_json": "Non", "FR": "numero_etalab"},
"api_adresse:properties:type": {"export_json": "Non", "FR": "type_etalab"},
"api_adresse:properties:name": {
"export_json": "Non",
"FR": "numero_et_voie_etalab",
},
"api_adresse:properties:postcode": {
"export_json": "Non",
"FR": "code_postal_etalab",
},
"api_adresse:properties:citycode": {
"export_json": "Non",
"FR": "code_INSEE_etalab",
},
"api_adresse:properties:city": {"export_json": "Non", "FR": "ville_etalab"},
"api_adresse:properties:street": {"export_json": "Non", "FR": "rue_etalab"},
}
# pylint: disable=C0301
STATIONNEMENT_NON_PUBLIC_REQ = r'nwr["amenity"="bicycle_parking"]["access"~"(no|permit|private|customers|permissive)"](area:aire_de_recherche);'
REQS.append(
Requete(
"stationnements_velos_non_publics",
STATIONNEMENT_NON_PUBLIC_REQ,
dict(CHAMPS_STATIONNEMENT, **CHAMPS_ADRESSE),
)
)
REQS.append(
Requete(
"stationnements_velos_publics",
# pylint: disable=C0301
rf'nwr["amenity"="bicycle_parking"](area:aire_de_recherche); - {STATIONNEMENT_NON_PUBLIC_REQ}',
dict(CHAMPS_STATIONNEMENT, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"service:bicycle:diy": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"ateliers_autoreparation",
r'nwr["service:bicycle:diy"="yes"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"association": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"associations_velo",
r'nwr["association"="bicycle"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"craft": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"fabriquants_velo",
r'nwr["craft"="bicycle"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"shop": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"vendeurs_velo",
# pylint: disable=C0301
r'nwr["shop"="bicycle"](area:aire_de_recherche); nwr["service:bicycle:retail"="yes"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"amenity": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"velos_libre_service",
r'nwr["amenity"="bicycle_rental"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)
CHAMP_LOCAL = {"service:bicycle:rental": {"export_json": "Non", "FR": ""}}
REQS.append(
Requete(
"location_velo",
r'nwr["service:bicycle:rental"="yes"](area:aire_de_recherche);',
dict(CHAMP_LOCAL, **CHAMPS_POI, **CHAMPS_ADRESSE),
)
)

73
rdoo.py
View File

@ -18,7 +18,7 @@
"""
Module principal : 
Module principal :
- récupération de données par appel à Overpass
- géocodage inverse
- export des données en JSON pour utilisation avec umap
@ -31,9 +31,8 @@ import os
import argparse
import logging
import sys
from osm_vc63 import errors
from osm_vc63 import requetes
from osm_vc63.utils import Utils
from rdoopy import errors
from rdoopy.utils import Utils
OVERPASS_URL = "http://overpass-api.de/api/interpreter"
GEO_API_URL = "https://api-adresse.data.gouv.fr"
@ -45,31 +44,6 @@ MAX_RETRY = 4
RETRY_DELAY = 120
# traductions des tags bicycle_parking
TRAD_BICYCLE_PARKING = {
"stands": "Arceaux",
"wall_loops": "Pince roues",
"wall_hoops": "Pince roues",
"rack": "Râteliers",
"anchors": "Ancrage",
"shed": "Abri collectif",
"bollard": "Potelet",
"lockers": "Abris individuels",
"wide_stands": "Arceaux espacés",
"ground_slots": "Fente dans le sol",
"building": "Bâtiment",
"informal": "Informel",
"wave": "Râteliers",
"streetpod": "Arceaux",
"tree": "Arbre à bicyclettes",
"crossbar": "Barre",
"rope": "Câble",
"two-tier": "Deux étages",
"floor": "Sol",
"handlebar_holder": "Accroche-guidons",
}
def init_argparse() -> argparse.ArgumentParser:
"""Définition des arguments possibles."""
@ -131,6 +105,19 @@ def init_argparse() -> argparse.ArgumentParser:
)
parser.set_defaults(archivage=True)
parser.add_argument(
"-nc",
"--no-concatenation",
dest="concatenation",
action="store_false",
help="Désactiver la concaténation des tags dans l'export json",
)
parser.set_defaults(concatenation=True)
parser.add_argument(
"-t", "--timeout", type=int, help="Définir le temps de timeout.", default=25
)
return parser
@ -143,10 +130,13 @@ def main():
logging.basicConfig(
format="%(asctime)s [%(levelname)s] %(message)s",
level=getattr(logging, args.log_level.upper()),
handlers=[logging.FileHandler("rdoo.log"), logging.StreamHandler(sys.stdout)],
handlers=[
logging.FileHandler("rdoo.log", encoding="utf-8"),
logging.StreamHandler(sys.stdout),
],
)
utils = Utils(OVERPASS_URL, GEO_API_URL, args.dossier_resultats)
utils = Utils(OVERPASS_URL, GEO_API_URL, args.dossier_resultats, args.timeout)
if args.archivage:
utils.archivage(args.dossier_archive)
@ -156,14 +146,16 @@ def main():
# l'id de l'area se calcule en ajoutant 3600000000 au numéro de l'objet OSM
aire_de_recherche = str(3_600_000_000 + args.zone)
for req in requetes.REQS:
for req in utils.json_reqs:
for nb_essai in range(MAX_RETRY): # on tente max_retry fois
try:
logging.info(f"# Requête en cours : {req.nom}")
logging.info(f"# Requête en cours : {req}")
# appel overpass
data = utils.run_overpass_query(req.critere, aire_de_recherche)
data = utils.run_overpass_query(
utils.json_reqs[req]["overpass"], aire_de_recherche
)
nb_resultats = len(data["elements"])
logging.info(f"{nb_resultats} résultats")
@ -173,16 +165,17 @@ def main():
data = utils.geocodage_csv(data)
# traduction
data = utils.traduction(
"bicycle_parking", TRAD_BICYCLE_PARKING, data
)
for key in utils.traductions:
data = utils.traduction(key, utils.traductions[key], data)
# Sauvegarde
os.makedirs(args.dossier_resultats, exist_ok=True)
export_json = utils.nettoyage_json_pour_umap(data, req.champs)
export_json = utils.export_json_pour_umap(
data, utils.json_reqs[req]["champs"], args.concatenation
)
utils.save_as_json(export_json, req.nom)
utils.save_as_ods(req.champs, data, req.nom)
utils.save_as_json(export_json, req)
utils.save_as_ods(utils.json_reqs[req]["champs"], data, req)
# doucement sur overpass
time.sleep(30)

View File

@ -29,7 +29,7 @@ import csv
from collections import OrderedDict
import requests
from pyexcel_ods3 import save_data
from osm_vc63 import errors
from rdoopy import errors
class Utils:
@ -39,13 +39,23 @@ class Utils:
geo_api_url: str
dossier_resultats: str
def __init__(self, overpass_url, geo_api_url, dossier_resultats):
def __init__(self, overpass_url, geo_api_url, dossier_resultats, timeout):
self.overpass_url = overpass_url
self.geo_api_url = geo_api_url
self.dossier_resultats = dossier_resultats
self.timeout = timeout
with open("configuration/traductions.json", encoding="utf-8") as trads:
self.traductions = json.load(trads)
self.lecture_requetes()
def save_as_ods(self, fields, data, nom_req, ods_data_sheet=OrderedDict()):
"""Sauvegarde de data dans un classeur ods"""
"""Sauvegarde de data dans un classeur ods.
Le paramètre ods_data_sheet est évalué une seule fois à la définition de la fonction,
ce qui enregistre les data de chaque appel dans une nouvelle feuille.
"""
# ods_data_sheet = OrderedDict()
ods_data = []
@ -79,13 +89,15 @@ class Utils:
def save_as_json(self, export_json, nom_req):
"""Enregistrement du JSON"""
json_file = open(self.dossier_resultats + nom_req + ".json", "w")
json_file = open(
self.dossier_resultats + nom_req + ".json", "w", encoding="utf-8"
)
json_file.write(json.dumps(export_json))
json_file.close()
logging.info("Sauvegarde résultat format JSON/OSM")
def nettoyage_json_pour_umap(self, data, overpass_query_fields):
def export_json_pour_umap(self, data, overpass_query_fields, concatenation):
"""Sélection uniquement des champs export_json == oui"""
export_json = {
@ -99,7 +111,7 @@ class Utils:
for element in data["elements"]:
export_json["elements"].append(
{"type": element["type"], "id": element["id"]}
{"type": element["type"], "id": element["id"], "tags": {}}
)
# positionnement des éléments
@ -108,20 +120,35 @@ class Utils:
export_json["elements"][index_line]["lon"] = element["lon"]
else: # ways et relations
export_json["elements"][index_line]["center"] = element["center"]
export_json["elements"][index_line]["nodes"] = element["nodes"]
# filtrage des tags
description = ""
for tag in overpass_query_fields.keys():
if overpass_query_fields[tag]["export_json"] == "Oui":
if tag in element["tags"]:
if overpass_query_fields[tag]["FR"] != "":
description = (
description + overpass_query_fields[tag]["FR"] + " : "
)
description = description + str(element["tags"][tag]) + "\n"
export_json["elements"][index_line]["tags"] = {"description": description}
if (
overpass_query_fields[tag]["export_json"] == "Oui"
and tag in element["tags"]
):
if concatenation:
ajout = (
str(element["tags"][tag])
if overpass_query_fields[tag]["FR"] == ""
else overpass_query_fields[tag]["FR"]
+ " : "
+ str(element["tags"][tag])
)
description = description + ajout + "\n"
export_json["elements"][index_line]["tags"] = {
"description": description[:-1]
}
else:
tagname = (
tag
if overpass_query_fields[tag]["FR"] == ""
else overpass_query_fields[tag]["FR"]
)
export_json["elements"][index_line]["tags"].update(
{tagname: element["tags"][tag]}
)
index_line = index_line + 1
@ -131,15 +158,9 @@ class Utils:
"""Envoie la requête Overpass et retourne la réponse JSON."""
overpass_query = (
"""[out:json];
(
"""
+ critere
+ """
);
out center;
"""
f"[out:json][timeout: {str(self.timeout)}];({critere});out center;"
)
overpass_query = overpass_query.replace("aire_de_recherche", aire_de_recherche)
response = requests.get(self.overpass_url, params={"data": overpass_query})
@ -158,7 +179,9 @@ class Utils:
url = self.geo_api_url + "/reverse/csv/"
# création du fichier à envoyer à l'API
with open("tmp_geocodage.csv", "w", newline="") as tmp_csv_file:
with open(
"tmp_geocodage.csv", "w", newline="", encoding="utf-8"
) as tmp_csv_file:
csv_writer = csv.writer(tmp_csv_file)
csv_writer.writerow(["lat", "lon"])
@ -226,7 +249,7 @@ class Utils:
"""Traduit le champ tag des éléments de data avec dict"""
for element in data["elements"]:
if tag in element["tags"]:
if tag in element["tags"] and tag in dictionnaire.keys():
element["tags"][tag] = dictionnaire[element["tags"][tag]]
return data
@ -254,3 +277,23 @@ class Utils:
for file in os.listdir(self.dossier_resultats)
if not os.path.isdir(self.dossier_resultats + file)
]
def lecture_requetes(self):
"""Lecture des requêtes dans les fichiers de configuration"""
with open("configuration/requetes.json", encoding="utf-8") as reqs:
self.json_reqs = json.load(reqs)
with open(
"configuration/champs_generiques.json", encoding="utf-8"
) as champs_generiques:
self.json_champs_generiques = json.load(champs_generiques)
for req in self.json_reqs:
self.json_reqs[req]["champs"] = dict(self.json_reqs[req]["champ_local"])
for champ in self.json_reqs[req]["champs_generiques"]:
self.json_reqs[req]["champs"].update(self.json_champs_generiques[champ])
# nettoyage
self.json_reqs[req].pop("champ_local", None)
self.json_reqs[req].pop("champs_generiques", None)