Skip to content

Commit

Permalink
Merge pull request #4 from Floby/export-par-departement
Browse files Browse the repository at this point in the history
Export par départements dans les fichiers idoines
  • Loading branch information
Floby committed Apr 2, 2021
2 parents af7650b + 8c14373 commit 8a90ea6
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 36 deletions.
102 changes: 102 additions & 0 deletions data/input/departements-france.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
code_departement,nom_departement,code_region,nom_region
01,Ain,84,Auvergne-Rhône-Alpes
02,Aisne,32,Hauts-de-France
03,Allier,84,Auvergne-Rhône-Alpes
04,Alpes-de-Haute-Provence,93,Provence-Alpes-Côte d'Azur
05,Hautes-Alpes,93,Provence-Alpes-Côte d'Azur
06,Alpes-Maritimes,93,Provence-Alpes-Côte d'Azur
07,Ardèche,84,Auvergne-Rhône-Alpes
08,Ardennes,44,Grand Est
09,Ariège,76,Occitanie
10,Aube,44,Grand Est
11,Aude,76,Occitanie
12,Aveyron,76,Occitanie
13,Bouches-du-Rhône,93,Provence-Alpes-Côte d'Azur
14,Calvados,28,Normandie
15,Cantal,84,Auvergne-Rhône-Alpes
16,Charente,75,Nouvelle-Aquitaine
17,Charente-Maritime,75,Nouvelle-Aquitaine
18,Cher,24,Centre-Val de Loire
19,Corrèze,75,Nouvelle-Aquitaine
21,Côte-d'Or,27,Bourgogne-Franche-Comté
22,Côtes-d'Armor,53,Bretagne
23,Creuse,75,Nouvelle-Aquitaine
24,Dordogne,75,Nouvelle-Aquitaine
25,Doubs,27,Bourgogne-Franche-Comté
26,Drôme,84,Auvergne-Rhône-Alpes
27,Eure,28,Normandie
28,Eure-et-Loir,24,Centre-Val de Loire
29,Finistère,53,Bretagne
2A,Corse-du-Sud,94,Corse
2B,Haute-Corse,94,Corse
30,Gard,76,Occitanie
31,Haute-Garonne,76,Occitanie
32,Gers,76,Occitanie
33,Gironde,75,Nouvelle-Aquitaine
34,Hérault,76,Occitanie
35,Ille-et-Vilaine,53,Bretagne
36,Indre,24,Centre-Val de Loire
37,Indre-et-Loire,24,Centre-Val de Loire
38,Isère,84,Auvergne-Rhône-Alpes
39,Jura,27,Bourgogne-Franche-Comté
40,Landes,75,Nouvelle-Aquitaine
41,Loir-et-Cher,24,Centre-Val de Loire
42,Loire,84,Auvergne-Rhône-Alpes
43,Haute-Loire,84,Auvergne-Rhône-Alpes
44,Loire-Atlantique,52,Pays de la Loire
45,Loiret,24,Centre-Val de Loire
46,Lot,76,Occitanie
47,Lot-et-Garonne,75,Nouvelle-Aquitaine
48,Lozère,76,Occitanie
49,Maine-et-Loire,52,Pays de la Loire
50,Manche,28,Normandie
51,Marne,44,Grand Est
52,Haute-Marne,44,Grand Est
53,Mayenne,52,Pays de la Loire
54,Meurthe-et-Moselle,44,Grand Est
55,Meuse,44,Grand Est
56,Morbihan,53,Bretagne
57,Moselle,44,Grand Est
58,Nièvre,27,Bourgogne-Franche-Comté
59,Nord,32,Hauts-de-France
60,Oise,32,Hauts-de-France
61,Orne,28,Normandie
62,Pas-de-Calais,32,Hauts-de-France
63,Puy-de-Dôme,84,Auvergne-Rhône-Alpes
64,Pyrénées-Atlantiques,75,Nouvelle-Aquitaine
65,Hautes-Pyrénées,76,Occitanie
66,Pyrénées-Orientales,76,Occitanie
67,Bas-Rhin,44,Grand Est
68,Haut-Rhin,44,Grand Est
69,Rhône,84,Auvergne-Rhône-Alpes
70,Haute-Saône,27,Bourgogne-Franche-Comté
71,Saône-et-Loire,27,Bourgogne-Franche-Comté
72,Sarthe,52,Pays de la Loire
73,Savoie,84,Auvergne-Rhône-Alpes
74,Haute-Savoie,84,Auvergne-Rhône-Alpes
75,Paris,11,Île-de-France
76,Seine-Maritime,28,Normandie
77,Seine-et-Marne,11,Île-de-France
78,Yvelines,11,Île-de-France
79,Deux-Sèvres,75,Nouvelle-Aquitaine
80,Somme,32,Hauts-de-France
81,Tarn,76,Occitanie
82,Tarn-et-Garonne,76,Occitanie
83,Var,93,Provence-Alpes-Côte d'Azur
84,Vaucluse,93,Provence-Alpes-Côte d'Azur
85,Vendée,52,Pays de la Loire
86,Vienne,75,Nouvelle-Aquitaine
87,Haute-Vienne,75,Nouvelle-Aquitaine
88,Vosges,44,Grand Est
89,Yonne,27,Bourgogne-Franche-Comté
90,Territoire de Belfort,27,Bourgogne-Franche-Comté
91,Essonne,11,Île-de-France
92,Hauts-de-Seine,11,Île-de-France
93,Seine-Saint-Denis,11,Île-de-France
94,Val-de-Marne,11,Île-de-France
95,Val-d'Oise,11,Île-de-France
971,Guadeloupe,01,Guadeloupe
972,Martinique,02,Martinique
973,Guyane,03,Guyane
974,La Réunion,04,La Réunion
976,Mayotte,06,Mayotte
Empty file added data/output/.gitkeep
Empty file.
139 changes: 104 additions & 35 deletions prototype.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,98 @@
from datetime import datetime
from multiprocessing import Pool
import json
import os
import io
import re
import csv
import requests

session = requests.Session()
if os.getenv('WITH_TOR', 'no') == 'yes':
session.proxies = {'http': 'socks5://127.0.0.1:9050', 'https': 'socks5://127.0.0.1:9050'}

POOL_SIZE = int(os.getenv('POOL_SIZE', 20))
DOCTOLIB_HEADERS = {
'X-Covid-Tracker-Key': os.environ.get('DOCTOLIB_API_KEY', None)
}

def main():
with Pool(POOL_SIZE) as pool:
centres_cherchés = pool.imap_unordered(
cherche_prochain_rdv_dans_centre,
centre_iterator(),
1
)
export_data(centres_cherchés)

def cherche_prochain_rdv_dans_centre(centre):
start_date = datetime.now().isoformat()[:10]
try:
plateforme, next_slot = fetch_centre_slots(centre['rdv_site_web'], start_date)
except Exception as e:
print(f"erreur lors du traitement de la ligne avec le gid {centre['gid']}")
print(e)
next_slot = None
plateforme = None

print(plateforme, next_slot, numero_departement(centre))
return {
'departement': numero_departement(centre),
'nom': centre['nom'],
'url': centre['rdv_site_web'],
'plateforme': plateforme,
'prochain_rdv': next_slot
}

def export_data(centres_cherchés):
compte_centres = 0
compte_centres_avec_dispo = 0
par_departement = {
code: {
'version': 1,
'last_updated': datetime.now().isoformat(),
'centres_disponibles': [],
'centres_indisponibles': []
}
for code in import_departements()
}
for centre in centres_cherchés:
compte_centres += 1
code_departement = centre['departement']
if code_departement in par_departement:
if centre['prochain_rdv'] is None:
par_departement[code_departement]['centres_indisponibles'].append(centre)
else:
compte_centres_avec_dispo += 1
par_departement[code_departement]['centres_disponibles'].append(centre)
else:
print(f"WARNING: le centre {centre['nom']} ({code_departement}) n'a pas pu être rattaché à un département connu")

for code_departement, disponibilités in par_departement.items():
print(f'writing result to {code_departement}.json file')
with open(f'data/output/{code_departement}.json', "w") as outfile:
outfile.write(json.dumps(disponibilités, indent=2))

print (f"{compte_centres_avec_dispo} centres de vaccination avaient des disponibilités sur {compte_centres} scannés")


def fetch_centre_slots(rdv_site_web, start_date):
if rdv_site_web.startswith('https://partners.doctolib.fr'):
return 'Doctolib', fetch_doctolib_slots(rdv_site_web, start_date)
if rdv_site_web.startswith('https://vaccination-covid.keldoc.com'):
return 'Keldoc', None
if rdv_site_web.startswith('https://www.maiia.com'):
return 'Maiia', None
return 'Autre', None


def fetch_doctolib_slots(rdv_site_web, start_date):
centre = re.search(r'\/([^`\/]*)\?', rdv_site_web)
if not centre:
return None

centre_api_url = f'https://partners.doctolib.fr/booking/{centre.group(1)}.json'
response = requests.get(centre_api_url, headers=DOCTOLIB_HEADERS)
response = session.get(centre_api_url, headers=DOCTOLIB_HEADERS)
response.raise_for_status()
data = response.json()

Expand Down Expand Up @@ -62,7 +138,7 @@ def fetch_doctolib_slots(rdv_site_web, start_date):

slots_api_url = f'https://partners.doctolib.fr/availabilities.json?start_date={start_date}&visit_motive_ids={visit_motive_id}&agenda_ids={agenda_ids}&insurance_sector=public&practice_ids={practice_ids}&destroy_temporary=true&limit=7'

response = requests.get(slots_api_url, headers=DOCTOLIB_HEADERS)
response = session.get(slots_api_url, headers=DOCTOLIB_HEADERS)
response.raise_for_status()

slots = response.json()
Expand All @@ -73,19 +149,9 @@ def fetch_doctolib_slots(rdv_site_web, start_date):
return None


def fetch_centre_slots(rdv_site_web, start_date):
if rdv_site_web.startswith('https://partners.doctolib.fr'):
return 'Doctolib', fetch_doctolib_slots(rdv_site_web, start_date)
if rdv_site_web.startswith('https://vaccination-covid.keldoc.com'):
return 'Keldoc', None
if rdv_site_web.startswith('https://www.maiia.com'):
return 'Maiia', None
return 'Autre', None


def centre_iterator():
url = "https://www.data.gouv.fr/fr/datasets/r/5cb21a85-b0b0-4a65-a249-806a040ec372"
response = requests.get(url)
response = session.get(url)
response.raise_for_status()

reader = io.StringIO(response.content.decode('utf8'))
Expand All @@ -94,25 +160,28 @@ def centre_iterator():
yield row


def fetch_all_slots(start_date):
output = []
for row in centre_iterator():
try:
plateforme, slots = fetch_centre_slots(row['rdv_site_web'], start_date)
except requests.exceptions.RequestException as e:
print(row['rdv_site_web'], e)
slots = None
plateforme = None

print(plateforme, slots, row['rdv_site_web'])

output.append({
'nom': row['nom'],
'url': row['rdv_site_web'],
'plateforme': plateforme,
'prochain_rdv': slots
})
return output


print(fetch_all_slots('2021-04-15'))
# NOTE:
# les codes INSEE de communes sont _normalement_ sur 5 chiffres
# - SAUF, si on a mis le type de la colonne à "nombre" dans excel et qu'il vire le 0 au début de 02401
# Le code INSEE commence par le code du département sur ses 2 premiers caractères
# - SAUF pour l'outre-mer (>96) où c'est concrètement le bordel
#
def numero_departement(centre):
code_insee = centre['com_insee']
if len(code_insee) == 4:
code_insee = '0' + code_insee
if code_insee.startswith('977') or code_insee.startswith('978'):
return '971'
if code_insee.startswith('97'):
return code_insee[:3]
return code_insee[:2]

def import_departements():
import csv
with open('data/input/departements-france.csv', newline='\n') as csvfile:
reader = csv.DictReader(csvfile)
return [str(row["code_departement"]) for row in reader]


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
requests==2.25.1
requests[socks]==2.25.1

0 comments on commit 8a90ea6

Please sign in to comment.