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} +```{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)) +``` + + +