diff --git a/content/course/manipulation/04a_webscraping_TP/index.qmd b/content/course/manipulation/04a_webscraping_TP/index.qmd
index 03c7aa62b..03b966b2d 100644
--- a/content/course/manipulation/04a_webscraping_TP/index.qmd
+++ b/content/course/manipulation/04a_webscraping_TP/index.qmd
@@ -989,9 +989,6 @@ et enregistrer en local les images.
:::
-
-
-
```{python}
#| include: false
#| echo: false
@@ -1031,7 +1028,6 @@ shutil.copyfile("bulbasaur.jpg", "featured.jpg")
-
# `Selenium` : mimer le comportement d'un utilisateur internet
@@ -1252,23 +1248,177 @@ print('Score final : {} en {} coups'.format(scoreElem.text, count))
browser.quit()
```
+# Exercices supplémentaires
+
+## Récupérer les noms et âges des ministres français
+
+Pour cet exercice, on propose de scraper la liste des ministres français depuis le [site du gouvernement](https://www.gouvernement.fr/composition-du-gouvernement). L'objectif sera, _in fine_ de faire un graphique qui représente la distribution de leurs âges.
+La solution pour cet exercice a été proposée
+par [@tttienthinh](https://github.com/tttienthinh)
+et [Antoine Palazzolo](https://github.com/antoine-palazz).
+
+Pour être en mesure de faire cet exercice, il est
+recommandé d'installer le package `dateparser`
+
+```{python}
+#| output: false
+!pip install dateparser
+#depuis un notebook. En ligne de commande, retirer le !
+```
+
+Pour cet exercice, nous proposons d'utiliser les _packages_
+suivants:
-# Exercice supplémentaire [BONUS]
+```{python}
+import time
+from tqdm import tqdm
+import urllib
+import re, datetime
+from dateutil.parser import parse as parse_dt
+import dateparser
+
+import matplotlib.pyplot as plt
+
+import numpy as np
+import pandas as pd
+import bs4
+```
+
+Nous proposons également d'utiliser la fonction suivante
+pour calculer l'âge à partir de la date de naissance.
+
+```{python}
+def from_birth_to_age(birth):
+ today = datetime.date.today()
+ return today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
+```
::: {.cell .markdown}
```{=html}
-
Exercice : liste des ministres français grâce à Wikipedia
+
Exercice : Les ministres français
+```
+
+
+1. Créer des variables globales `url_gouvernement` et `url_gouvernement` qui représenteront,
+respectivement, la racine de l'URL du site web et le chemin au sein de celui-ci ;
+2. Utiliser `bs4` pour récupérer la composition du gouvernement, qui est contenue dans un `
`
+ayant une classe _ad hoc_. Nommer cet objet `compo`
+3. Utiliser `find_all` pour récupérer la liste des ministres dans `compo`. Nommer
+cet objet `ministres`
+4. Inspecter la structure des champs au sein de `ministres`. Répérer les id `biography`. Comme
+la structure est générique, on va écrire une fonction `from_bio_to_age` sur laquelle on va itérer
+pour chaque élément de la liste `ministres`. Cette fonction effectuera les opérations suivantes:
+ + Remplacer les champs de dates de naissance non numériques (par exemple _"1er"_), en valeur numérique (par exemple 1).
+ + Utiliser la regex `[0-3]?\d \S* \d{4}` avec le _package_ `re` pour extraire les dates
+ de naissance. Nommer l'objet `str_date`.
+ + Appliquer `dateparser.parse` pour convertir sous forme de date
+ + Appliquer `from_birth_to_age` pour transformer cette date de naissance en âge
+5. Pour chaque élément de la liste `ministres`, faire une boucle (en introduisant un
+ `time.sleep(0.25)` entre chaque itération pour ne pas surcharger le site):
+ + Récupérer les noms et prénoms, fonctions pour chaque ministre
+ + Récupérer l'URL de la photo
+ + Créer un URL pour chaque ministre afin d'appliquer la fonction
+ `from_bio_to_age`
+6. Utiliser `matplotlib` ou `seaborn` pour faire un histogramme d'âge
+
+```{=html}
+
+```
+:::
+
+```{python}
+#| echo: false
+# 1/ Créer des variables globales
+url_gouvernement = "https://www.gouvernement.fr"
+suffixe_ministres = "/composition-du-gouvernement"
+```
+
+```{python}
+#| echo: false
+# 2/ Récupérer compo gouvernement
+url = f"{url_gouvernement}/{suffixe_ministres}"
+html = urllib.request.urlopen(url).read()
+page = bs4.BeautifulSoup(html)
+compo = page.find("div", {"class":"composition-du-gouvernement-contenu"}) # Nous n'avons besoin que de la composition
```
-Scraper la liste des ministres français depuis wikipedia. Faire une graphique qui représente la distribution de leur âge.
+```{python}
+#| echo: false
+# 3/ Récupérer les ministres
+ministres = compo.find_all("div", {"class":"ministre"})
+```
-Si vous avez une solution satisfaisante, n'hésitez pas à la soumettre
-sur
-(car je n'ai pas encore testé...)
+A l'issue de la question 4, on devrait
+retrouver les informations suivantes:
-```{=html}
-
+```{python}
+print(f"Nous retrouvons ainsi {len(ministres)} ministres.")
+```
+
+```{python}
+def from_bio_to_age(url):
+ html = urllib.request.urlopen(url).read()
+ page = bs4.BeautifulSoup(html)
+ s = page.find("div", {"id":"biography"}).text.replace("1er", "1") # un peu ad hoc
+ expression = re.compile("[0-3]?\d \S* \d{4}") # renvoie parfois des dates autres que dates de naissance
+ str_date = expression.findall(s)[0]
+ date_de_naissance = dateparser.parse(str_date).date()
+ return from_birth_to_age(date_de_naissance)
```
-:::
\ No newline at end of file
+
+```{python}
+#| include: false
+
+liste = []
+
+for ministre in tqdm(ministres):
+ prenom_nom = ministre.find("a", {"class":"ministre-nom"}).text
+ fonction = ministre.find("p", {"class":"ministre-fonction"}).text
+ photo = ministre.find("img")["src"]
+ href = url_gouvernement + ministre.find("a", {"class":"ministre-nom"})["href"]
+ try:
+ age = from_bio_to_age(href)
+ except:
+ age = np.NaN
+
+ liste.append({
+ 'Nom complet': prenom_nom,
+ 'Fonction': fonction,
+ 'Photo': photo,
+ 'href': href,
+ 'Age': age
+ })
+
+ time.sleep(0.25) # Ne pas surcharger les requêtes
+```
+
+_In fine_, on obtient une liste dont le premier élément
+prend la forme suivante:
+
+```{python}
+liste[0]
+```
+
+Finalement, le `DataFrame` pourra être
+structuré sous la forme suivante. On va éliminer
+les âges égaux à 0 sont qui sont des erreurs
+de scraping:
+lorsque la date de naissance complète n'est pas disponible
+sur la biographie d'un ministre.
+
+```{python}
+df = pd.DataFrame(liste)
+df = df.loc[df['Age'] != 0]
+df.head(3)
+```
+
+Finalement, l'histogramme aura l'aspect suivant:
+
+```{python}
+plt.hist(df.Age, bins=np.arange(25, 80, 4))
+```
+
+
+