export_geoloc_sncf.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. from __future__ import unicode_literals, print_function #Compatibilité Python3
  4. import json
  5. import os, sys, argparse
  6. import sqlite3
  7. import re, requests
  8. try : #Vérification dépendance Pandas
  9. import pandas as pd
  10. except ImportError:
  11. print('Nécessite le module Pandas\npip install pandas\n')
  12. # CONSTANTES
  13. REPERTOIRE_JSON = 'json/'
  14. GAR_FILE = 'liste-des-gares.json'
  15. REPERTOIRE_DATA = 'data/'
  16. CSV_GEO_FILE = 'open_geo_sncf__.csv'
  17. CSV_GAR_FILE = 'open_gar_sncf__.csv'
  18. DB_FILE = 'geo_sncf.db'
  19. # VARIABLES GLOBALES
  20. dico = {}
  21. dfout = pd.DataFrame()
  22. dfgar = pd.DataFrame()
  23. #API KEYWORD : GEOLOCALISATION
  24. urlall = 'https://ressources.data.sncf.com/api/datasets/1.0/search/?rows=999&facet=keyword&refine.keyword=G%C3%A9olocalisation'
  25. def telechargement(url_req):
  26. """ Recherche par l'API les datasets tagés 'Géolocalisation'
  27. Télécharge les datasets dans le répertoire 'REPERTOIRE_JSON' """
  28. try:
  29. ls_dir_zip = os.listdir(REPERTOIRE_JSON)
  30. except:
  31. print('création du dossier ', REPERTOIRE_JSON)
  32. os.mkdir(REPERTOIRE_JSON)
  33. req = requests.get(url_req)
  34. req = req.json()
  35. req = req['datasets']
  36. print('Il y a %s datasets avec données de géolocalisation à télécharger' % len(req))
  37. for i in range(0,len(req)):
  38. datasetid = req[i]['datasetid']
  39. url = 'https://ressources.data.sncf.com/explore/dataset/{}/download/?format=json'.format(datasetid)
  40. print('Téléchargement du dataset ', datasetid)
  41. r = requests.get(url)
  42. with open(REPERTOIRE_JSON+datasetid+'.json', "wb") as f:
  43. f.write(r.content)
  44. def list_files():
  45. """ Liste les fichiers .json présent dans le répertoire 'REPERTOIRE_JSON' """
  46. liste=[]
  47. for file in os.listdir(REPERTOIRE_JSON):
  48. if file.endswith(".json"):
  49. liste.append(os.path.join(REPERTOIRE_JSON, file))
  50. return liste
  51. def regex_fields(list_fields):
  52. """ Regex sur les dans une liste les noms correspondants aux libellés suivants :
  53. - ligne
  54. - pk
  55. - coordonnées géographiques
  56. Et renvoit une liste contenant les libellés trouvés. """
  57. debfin=False
  58. for fields in list_fields:
  59. if re.match(r"^(?=.*coord)(?=.*geo)(?=.*deb|.*fin)", fields) :
  60. debfin = True
  61. try:
  62. for fields in list_fields:
  63. if fields == 'ligne' or fields == 'code_ligne': ligne = fields
  64. if debfin :
  65. if re.match(r"^(?=.*pk)(?=.*deb)", fields): pk_deb = fields
  66. if re.match(r"^(?=.*pk)(?=.*fin)", fields): pk_fin = fields
  67. if re.match(r"^(?=.*coord)(?=.*geo)(?=.*deb)",fields): cg_deb=fields
  68. if re.match(r"^(?=.*coord)(?=.*geo)(?=.*fin)",fields): cg_fin=fields
  69. else:
  70. if re.match(r"^(?=.*pk)", fields): pk = fields
  71. if re.match(r"^(?=.*coord)(?=.*geo)", fields): cg = fields
  72. if debfin:
  73. list_fields = [[ligne, pk_deb, cg_deb],
  74. [ligne, pk_fin, cg_fin]]
  75. else:
  76. list_fields = [[ligne, pk, cg]]
  77. except:
  78. return False
  79. else:
  80. return list_fields
  81. def geo2df(f):
  82. """ Mise en forme du dataset avec Pandas """
  83. global dfout
  84. try:
  85. df = pd.read_json(f, orient = 'columns')
  86. except:
  87. print('erreur de lecture du fichier ', f)
  88. return False
  89. print('création de la base Géolocalisation')
  90. try:
  91. df = pd.read_json(df['fields'].to_json(),orient = 'index')
  92. except:
  93. pass
  94. list_fields = list(df.columns.values)
  95. list_fields = regex_fields(list_fields) # APPEL FCT regex_fields()
  96. if list_fields:
  97. for i in list_fields:
  98. df_out_tmp = dfout
  99. df_tmp = df[i]
  100. df_tmp = df_tmp.dropna()
  101. df_tmp = df_tmp.reset_index(drop=True)
  102. df_tmp[['lat','lon']] = pd.DataFrame([x for x in df_tmp[i[2]]])
  103. df_tmp[i[1]] = df_tmp[i[1]].str.replace('+','.').str.replace('-','.')
  104. df_tmp[i[1]] = df_tmp[i[1]].astype(float)
  105. df_tmp[i[0]] = df_tmp[i[0]].astype('int64')
  106. df_tmp = df_tmp.drop(i[2], axis=1)
  107. df_tmp = df_tmp.rename(columns = {i[1]:'pk'})
  108. df_tmp = df_tmp.rename(columns = {i[0]:'code_ligne'})
  109. dfout = pd.concat([df_out_tmp,df_tmp], ignore_index=True)
  110. dfout = dfout.drop_duplicates()
  111. else:
  112. print('le fichier %s, ne contient pas de données géolocalisées' % f)
  113. return False
  114. return True
  115. def geo2csv():
  116. """ Export CSV """
  117. dfout.to_csv(REPERTOIRE_DATA+CSV_GEO_FILE, sep=str(';'), encoding='utf-8', index=False)
  118. def geo2db():
  119. """ Export SQLite """
  120. try:
  121. ls_dir_zip = os.listdir(REPERTOIRE_DATA)
  122. except:
  123. print('création du dossier ', REPERTOIRE_DATA)
  124. os.mkdir(REPERTOIRE_DATA)
  125. con = sqlite3.connect(REPERTOIRE_DATA+DB_FILE)
  126. dfout.to_sql("geo", con, if_exists="replace", index=False)
  127. con.commit()
  128. con.close()
  129. def gar2df():
  130. """ Mise en forme du dataset avec Pandas
  131. Spécifique Liste des Gares """
  132. global dfgar
  133. try:
  134. dfgar = pd.read_json(REPERTOIRE_JSON+GAR_FILE, orient = 'columns')
  135. except:
  136. print('erreur de lecture du fichier ', REPERTOIRE_JSON+GAR_FILE)
  137. return False
  138. print('création de la base Gares')
  139. dfgar = pd.read_json(dfgar['fields'].to_json(),orient = 'index')
  140. dfgar = dfgar[['code_ligne','pk','libelle_gare']]
  141. dfgar['pk'] = dfgar['pk'].str.replace('+','.').str.replace('-','.')
  142. dfgar['pk'] = dfgar['pk'].astype(float)
  143. dfgar['code_ligne'] = dfgar['code_ligne'].astype('int64')
  144. dfgar = dfgar.dropna()
  145. dfgar = dfgar.reset_index(drop=True)
  146. dfgar = dfgar.drop_duplicates()
  147. def gar2csv():
  148. """ Export CSV
  149. Spécifique Liste des Gares """
  150. dfgar.to_csv(REPERTOIRE_DATA+CSV_GAR_FILE, sep=str(';'), encoding='utf-8', index=False)
  151. def gar2db():
  152. """ Export SQLite
  153. Spécifique Liste des Gares """
  154. global dfgar
  155. con = sqlite3.connect(REPERTOIRE_DATA+DB_FILE)
  156. dfgar.to_sql("gar", con, if_exists="replace", index=False)
  157. con.commit()
  158. con.close()
  159. def supprimer_fichiers_JSON():
  160. """ Supprime les fichiers .json de 'REPERTOIRE_JSON '"""
  161. #SUPRESSION DES FICHIERS DU REPERTOIRE
  162. for file in os.listdir(REPERTOIRE_JSON):
  163. if file.endswith(".json"):
  164. os.remove(os.path.join(REPERTOIRE_JSON, file))
  165. return True
  166. def parser():
  167. """ Passage des arguments par ligne de commande """
  168. parser = argparse.ArgumentParser(description='Demo')
  169. parser.add_argument('--sql','-s', action='store_true', help='export SQLite' )
  170. parser.add_argument('--csv','-c', action='store_true', help='export CSV' )
  171. parser.add_argument('--delete','-d', action='store_true', help='delete JSON files after export' )
  172. return parser.parse_args()
  173. def geo_clean():
  174. """ Suppression des coordonnées géographiques aberrantesde la base SQLite """
  175. def test(nb_suppr):
  176. suppr=0
  177. cur.execute("""SELECT code_ligne, pk, lat, lon FROM geo WHERE code_ligne = {} ORDER BY pk""".format(sligne))
  178. req=cur.fetchall()
  179. for i in xrange(0,len(req)-1):
  180. if (abs(req[i][2]-req[i+1][2]) > 0.01 or abs(req[i][3]-req[i+1][3]) > 0.015) : # premier test de comparaison (plus rapide que de tester chaque lignes unes à unes...)
  181. #Calcul des lat/lon moyennes +- 0.5km
  182. pkmin = req[i][1]-0.5
  183. pkmax = req[i][1]+0.5
  184. cur.execute("""SELECT AVG(lat), AVG(lon) FROM geo WHERE pk < ? AND pk > ? AND code_ligne=?""",(pkmax,pkmin,sligne))
  185. req2=cur.fetchall()
  186. e_lat = abs(req[i][2]-float(str(req2[0][0])))
  187. e_lon = abs(req[i][3]-float(str(req2[0][1])))
  188. if nb_suppr==999 and (e_lat > 0.5 or e_lon > 0.5): #Premier passage pour supprimer les valeurs les plus aberrantes
  189. suppr+=1
  190. cur.execute("""DELETE FROM geo WHERE code_ligne = ? AND pk = ? AND lat = ? AND lon = ?""",(req[i][0],req[i][1],req[i][2],req[i][3]))
  191. if nb_suppr!=999 and (e_lat > 0.02 or e_lon > 0.03): #Second passage plus fin
  192. suppr+=1
  193. cur.execute("""DELETE FROM geo WHERE code_ligne = ? AND pk = ? AND lat = ? AND lon = ?""",(req[i][0],req[i][1],req[i][2],req[i][3]))
  194. if nb_suppr==999: #Second passage plus fin, permet plus de précision dans les valeurs moyennes après la suppression des valeurs les plus aberrantes
  195. for i in xrange(0,len(req)-1):
  196. if (abs(req[i][2]-req[i+1][2]) > 0.01 or abs(req[i][3]-req[i+1][3]) > 0.015) :
  197. pkmin = req[i][1]-0.5
  198. pkmax = req[i][1]+0.5
  199. cur.execute("""SELECT AVG(lat), AVG(lon) FROM geo WHERE pk < ? AND pk > ? AND code_ligne=?""",(pkmax,pkmin,sligne))
  200. req2=cur.fetchall()
  201. e_lat = abs(req[i][2]-float(str(req2[0][0])))
  202. e_lon = abs(req[i][3]-float(str(req2[0][1])))
  203. if e_lat > 0.02 or e_lon > 0.03:
  204. suppr+=1
  205. cur.execute("""DELETE FROM geo WHERE code_ligne = ? AND pk = ? AND lat = ? AND lon = ?""",(req[i][0],req[i][1],req[i][2],req[i][3]))
  206. return suppr
  207. print('Suppression des coordonnées géographiques aberrantes de la base SQLite.\nCela va prendre quelques minutes...')
  208. con = sqlite3.connect(REPERTOIRE_DATA+DB_FILE)
  209. cur = con.cursor()
  210. cur.execute("""SELECT DISTINCT code_ligne FROM geo ORDER BY code_ligne""") #recuperation des codes_lignes
  211. code_lignes = cur.fetchall()
  212. for ligne in code_lignes:
  213. lig = ligne[0]
  214. sligne = str(lig)
  215. nb_suppr=999
  216. while nb_suppr != 0:
  217. nb_suppr = test(nb_suppr)
  218. con.commit()
  219. con.close()
  220. if __name__ == '__main__':
  221. args = parser()
  222. if not len(sys.argv) > 1: # Si aucun argument : export SQLite
  223. args.sql = True
  224. telechargement(urlall)
  225. list_f=list_files()
  226. for f in list_f:
  227. print(f)
  228. geo2df(f)
  229. if args.sql:
  230. geo2db()
  231. geo_clean()
  232. if args.csv:
  233. geo2csv()
  234. gar2df()
  235. if args.sql:
  236. gar2db()
  237. if args.csv:
  238. gar2csv()
  239. if args.delete:
  240. supprimer_fichiers_JSON()