Compare commits

..

1 Commits

Author SHA1 Message Date
f1459ca01c ajout de la traduction du tag erroné wall_hoops 2023-08-20 21:48:50 +02:00
13 changed files with 234 additions and 442 deletions

View File

@ -3,11 +3,6 @@
Récupération de Données OSM via Overpass Récupération de Données OSM via Overpass
## Prérequis ## 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 requests`
`pip3 install pyexcel-ods3` `pip3 install pyexcel-ods3`
@ -50,20 +45,10 @@ 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`. Il est possible de ne pas archiver en passant l'argument `-na, --no-archive`.
### 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é.
### 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 ## Umap
[Utilisation avec Umap](docs/umap.md) 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`.
## Requêtes personnalisées 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`.
[Requêtes personnalisées](docs/requetes_perso.md)
## Inspirations / ressources : ## Inspirations / ressources :
### urls ressources ### urls ressources

View File

@ -1,148 +0,0 @@
{
"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

@ -1,96 +0,0 @@
{
"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

@ -1,23 +0,0 @@
{
"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"
}
}

View File

@ -1,13 +0,0 @@
## 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

View File

@ -1,32 +0,0 @@
## 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.

View File

@ -1,11 +0,0 @@
## 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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

166
osm_vc63/requetes.py Normal file
View File

@ -0,0 +1,166 @@
#!/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),
)
)

View File

@ -29,7 +29,7 @@ import csv
from collections import OrderedDict from collections import OrderedDict
import requests import requests
from pyexcel_ods3 import save_data from pyexcel_ods3 import save_data
from rdoopy import errors from osm_vc63 import errors
class Utils: class Utils:
@ -39,23 +39,13 @@ class Utils:
geo_api_url: str geo_api_url: str
dossier_resultats: str dossier_resultats: str
def __init__(self, overpass_url, geo_api_url, dossier_resultats, timeout): def __init__(self, overpass_url, geo_api_url, dossier_resultats):
self.overpass_url = overpass_url self.overpass_url = overpass_url
self.geo_api_url = geo_api_url self.geo_api_url = geo_api_url
self.dossier_resultats = dossier_resultats 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()): 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_sheet = OrderedDict()
ods_data = [] ods_data = []
@ -89,15 +79,13 @@ class Utils:
def save_as_json(self, export_json, nom_req): def save_as_json(self, export_json, nom_req):
"""Enregistrement du JSON""" """Enregistrement du JSON"""
json_file = open( json_file = open(self.dossier_resultats + nom_req + ".json", "w")
self.dossier_resultats + nom_req + ".json", "w", encoding="utf-8"
)
json_file.write(json.dumps(export_json)) json_file.write(json.dumps(export_json))
json_file.close() json_file.close()
logging.info("Sauvegarde résultat format JSON/OSM") logging.info("Sauvegarde résultat format JSON/OSM")
def export_json_pour_umap(self, data, overpass_query_fields, concatenation): def nettoyage_json_pour_umap(self, data, overpass_query_fields):
"""Sélection uniquement des champs export_json == oui""" """Sélection uniquement des champs export_json == oui"""
export_json = { export_json = {
@ -111,7 +99,7 @@ class Utils:
for element in data["elements"]: for element in data["elements"]:
export_json["elements"].append( export_json["elements"].append(
{"type": element["type"], "id": element["id"], "tags": {}} {"type": element["type"], "id": element["id"]}
) )
# positionnement des éléments # positionnement des éléments
@ -120,35 +108,20 @@ class Utils:
export_json["elements"][index_line]["lon"] = element["lon"] export_json["elements"][index_line]["lon"] = element["lon"]
else: # ways et relations else: # ways et relations
export_json["elements"][index_line]["center"] = element["center"] export_json["elements"][index_line]["center"] = element["center"]
export_json["elements"][index_line]["nodes"] = element["nodes"]
# filtrage des tags # filtrage des tags
description = "" description = ""
for tag in overpass_query_fields.keys(): for tag in overpass_query_fields.keys():
if ( if overpass_query_fields[tag]["export_json"] == "Oui":
overpass_query_fields[tag]["export_json"] == "Oui" if tag in element["tags"]:
and tag in element["tags"] if overpass_query_fields[tag]["FR"] != "":
): description = (
if concatenation: description + overpass_query_fields[tag]["FR"] + " : "
ajout = ( )
str(element["tags"][tag])
if overpass_query_fields[tag]["FR"] == "" description = description + str(element["tags"][tag]) + "\n"
else overpass_query_fields[tag]["FR"] export_json["elements"][index_line]["tags"] = {"description": description}
+ " : "
+ 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 index_line = index_line + 1
@ -158,9 +131,15 @@ class Utils:
"""Envoie la requête Overpass et retourne la réponse JSON.""" """Envoie la requête Overpass et retourne la réponse JSON."""
overpass_query = ( overpass_query = (
f"[out:json][timeout: {str(self.timeout)}];({critere});out center;" """[out:json];
(
"""
+ critere
+ """
);
out center;
"""
) )
overpass_query = overpass_query.replace("aire_de_recherche", aire_de_recherche) overpass_query = overpass_query.replace("aire_de_recherche", aire_de_recherche)
response = requests.get(self.overpass_url, params={"data": overpass_query}) response = requests.get(self.overpass_url, params={"data": overpass_query})
@ -179,9 +158,7 @@ class Utils:
url = self.geo_api_url + "/reverse/csv/" url = self.geo_api_url + "/reverse/csv/"
# création du fichier à envoyer à l'API # création du fichier à envoyer à l'API
with open( with open("tmp_geocodage.csv", "w", newline="") as tmp_csv_file:
"tmp_geocodage.csv", "w", newline="", encoding="utf-8"
) as tmp_csv_file:
csv_writer = csv.writer(tmp_csv_file) csv_writer = csv.writer(tmp_csv_file)
csv_writer.writerow(["lat", "lon"]) csv_writer.writerow(["lat", "lon"])
@ -249,7 +226,7 @@ class Utils:
"""Traduit le champ tag des éléments de data avec dict""" """Traduit le champ tag des éléments de data avec dict"""
for element in data["elements"]: for element in data["elements"]:
if tag in element["tags"] and tag in dictionnaire.keys(): if tag in element["tags"]:
element["tags"][tag] = dictionnaire[element["tags"][tag]] element["tags"][tag] = dictionnaire[element["tags"][tag]]
return data return data
@ -277,23 +254,3 @@ class Utils:
for file in os.listdir(self.dossier_resultats) for file in os.listdir(self.dossier_resultats)
if not os.path.isdir(self.dossier_resultats + file) 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)

73
rdoo.py
View File

@ -18,7 +18,7 @@
""" """
Module principal : Module principal : 
- récupération de données par appel à Overpass - récupération de données par appel à Overpass
- géocodage inverse - géocodage inverse
- export des données en JSON pour utilisation avec umap - export des données en JSON pour utilisation avec umap
@ -31,8 +31,9 @@ import os
import argparse import argparse
import logging import logging
import sys import sys
from rdoopy import errors from osm_vc63 import errors
from rdoopy.utils import Utils from osm_vc63 import requetes
from osm_vc63.utils import Utils
OVERPASS_URL = "http://overpass-api.de/api/interpreter" OVERPASS_URL = "http://overpass-api.de/api/interpreter"
GEO_API_URL = "https://api-adresse.data.gouv.fr" GEO_API_URL = "https://api-adresse.data.gouv.fr"
@ -44,6 +45,31 @@ MAX_RETRY = 4
RETRY_DELAY = 120 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: def init_argparse() -> argparse.ArgumentParser:
"""Définition des arguments possibles.""" """Définition des arguments possibles."""
@ -105,19 +131,6 @@ def init_argparse() -> argparse.ArgumentParser:
) )
parser.set_defaults(archivage=True) 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 return parser
@ -130,13 +143,10 @@ def main():
logging.basicConfig( logging.basicConfig(
format="%(asctime)s [%(levelname)s] %(message)s", format="%(asctime)s [%(levelname)s] %(message)s",
level=getattr(logging, args.log_level.upper()), level=getattr(logging, args.log_level.upper()),
handlers=[ handlers=[logging.FileHandler("rdoo.log"), logging.StreamHandler(sys.stdout)],
logging.FileHandler("rdoo.log", encoding="utf-8"),
logging.StreamHandler(sys.stdout),
],
) )
utils = Utils(OVERPASS_URL, GEO_API_URL, args.dossier_resultats, args.timeout) utils = Utils(OVERPASS_URL, GEO_API_URL, args.dossier_resultats)
if args.archivage: if args.archivage:
utils.archivage(args.dossier_archive) utils.archivage(args.dossier_archive)
@ -146,16 +156,14 @@ def main():
# l'id de l'area se calcule en ajoutant 3600000000 au numéro de l'objet OSM # 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) aire_de_recherche = str(3_600_000_000 + args.zone)
for req in utils.json_reqs: for req in requetes.REQS:
for nb_essai in range(MAX_RETRY): # on tente max_retry fois for nb_essai in range(MAX_RETRY): # on tente max_retry fois
try: try:
logging.info(f"# Requête en cours : {req}") logging.info(f"# Requête en cours : {req.nom}")
# appel overpass # appel overpass
data = utils.run_overpass_query( data = utils.run_overpass_query(req.critere, aire_de_recherche)
utils.json_reqs[req]["overpass"], aire_de_recherche
)
nb_resultats = len(data["elements"]) nb_resultats = len(data["elements"])
logging.info(f"{nb_resultats} résultats") logging.info(f"{nb_resultats} résultats")
@ -165,17 +173,16 @@ def main():
data = utils.geocodage_csv(data) data = utils.geocodage_csv(data)
# traduction # traduction
for key in utils.traductions: data = utils.traduction(
data = utils.traduction(key, utils.traductions[key], data) "bicycle_parking", TRAD_BICYCLE_PARKING, data
)
# Sauvegarde # Sauvegarde
os.makedirs(args.dossier_resultats, exist_ok=True) os.makedirs(args.dossier_resultats, exist_ok=True)
export_json = utils.export_json_pour_umap( export_json = utils.nettoyage_json_pour_umap(data, req.champs)
data, utils.json_reqs[req]["champs"], args.concatenation
)
utils.save_as_json(export_json, req) utils.save_as_json(export_json, req.nom)
utils.save_as_ods(utils.json_reqs[req]["champs"], data, req) utils.save_as_ods(req.champs, data, req.nom)
# doucement sur overpass # doucement sur overpass
time.sleep(30) time.sleep(30)