Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export par départements dans les fichiers idoines #4

Merged
merged 13 commits into from
Apr 2, 2021
102 changes: 102 additions & 0 deletions data/input/departements-france.csv
@@ -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.
129 changes: 93 additions & 36 deletions prototype.py
@@ -1,22 +1,95 @@
from datetime import datetime
from multiprocessing import Pool
import json
import os
import io
from itertools import islice
Floby marked this conversation as resolved.
Show resolved Hide resolved
import re
import csv
import requests
import pandas as pd
Floby marked this conversation as resolved.
Show resolved Hide resolved

session = requests.session()
Floby marked this conversation as resolved.
Show resolved Hide resolved
if os.getenv('WITH_TOR', 'no') == 'yes':
session.proxies = {'http': 'socks5://127.0.0.1:9050', 'https': 'socks5://127.0.0.1:9050'}
Floby marked this conversation as resolved.
Show resolved Hide resolved

POOL_SIZE = int(os.getenv('POOL_SIZE', 8))
DOCTOLIB_HEADERS = {
'X-Covid-Tracker-Key': os.environ.get('DOCTOLIB_API_KEY', None)
'X-Covid-Tracker-Key': os.environ.get('DOCTOLIB_APIKEY', None)
Floby marked this conversation as resolved.
Show resolved Hide resolved
}

def main():
sauter_n_centres = 0
with Pool(POOL_SIZE) as pool:
centres_cherchés = pool.imap_unordered(
Floby marked this conversation as resolved.
Show resolved Hide resolved
cherche_prochain_rdv_dans_centre,
islice(centre_iterator(), 0, None, 1 + sauter_n_centres),
florimondmanca marked this conversation as resolved.
Show resolved Hide resolved
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):
par_departement = {
code: {
'version': 1,
'last_updated': datetime.now().isoformat(),
Floby marked this conversation as resolved.
Show resolved Hide resolved
'centres_disponibles': [],
'centres_indisponibles': []
}
for code in import_departements()
}
for centre in centres_cherchés:
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:
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))


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 +135,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 +146,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 +157,19 @@ 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'))
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'):
Floby marked this conversation as resolved.
Show resolved Hide resolved
return '971'
if code_insee.startswith('97'):
return code_insee[:3]
return code_insee[:2]
Floby marked this conversation as resolved.
Show resolved Hide resolved

def import_departements():
df = pd.read_csv('data/input/departements-france.csv')
florimondmanca marked this conversation as resolved.
Show resolved Hide resolved
return df.code_departement.astype(str).to_list()
Floby marked this conversation as resolved.
Show resolved Hide resolved


main()
2 changes: 2 additions & 0 deletions requirements.txt
@@ -1 +1,3 @@
requests==2.25.1
requests[socks]
Floby marked this conversation as resolved.
Show resolved Hide resolved
pandas==0.25.3