Module 8 - Exercices

STT-1100 Introduction à la science des données

ImportantDossier de travail du module

Télécharger le dossier prêt à ouvrir (.zip)

Décompressez le fichier, puis ouvrez le projet .Rproj. Les chemins utilisés dans les exercices fonctionneront sans déplacer les données.

Exercices de consolidation

Ces exercices sont indépendants de l’aventure et du défi. Ils servent à consolider les gestes techniques du module 8: lire une page HTML, cibler des éléments avec des sélecteurs CSS, transformer une extraction en fonction, automatiser une extraction répétée et documenter les limites d’une collecte.

Les pages HTML utilisées ici sont des instantanés locaux de données québécoises réelles. Les deux catalogues proviennent de l’API officielle de Données Québec; la page d’événements est tirée du jeu Événements - Système d’information touristique Québec du ministère du Tourisme. Les instantanés conservent les valeurs publiées, mais leur structure HTML est simplifiée pour rendre l’exercice stable et reproductible. Les métadonnées et les événements sont diffusés sous licence CC BY 4.0.

library(tidyverse)
library(rvest)
library(purrr)

Bloc A - Lire une page HTML locale

Exercice 1 - Importer une page HTML

Lisez catalogue_donnees_quebec.html avec read_html(). Repérez les six cartes de jeux de données avec le sélecteur .dataset-card. Elles couvrent Québec, Gatineau, Sherbrooke, Trois-Rivières, Saguenay et Montréal.

page_catalogue <- read_html("data/catalogue_donnees_quebec.html")

cartes <- page_catalogue |>
  html_elements(".dataset-card")

length(cartes)
[1] 6
cartes[[1]]
{html_node}
<article class="dataset-card" data-source-url="https://www.donneesquebec.ca/recherche/dataset/vque_31">
[1] <h2 class="dataset-title">Arbres non-répertoriés</h2>
[2] <p class="dataset-producer">Ville de Québec</p>
[3] <p class="dataset-category">Environnement, ressources naturelles et énerg ...
[4] <p class="dataset-updated">2026-07-10</p>

Exercice 2 - Extraire un premier vecteur

Extrayez les titres des jeux de données avec le sélecteur .dataset-title.

titres <- cartes |>
  html_element(".dataset-title") |>
  html_text2()

titres
[1] "Arbres non-répertoriés"
[2] "Pistes cyclables"
[3] "Milieux humides RCI"
[4] "Avis de grands travaux"
[5] "Chantiers - 511"
[6] "RSQA - indice de la qualité de l'air temps réel (quotidien)"

Exercice 3 - Construire un tableau

Extrayez les producteurs, les catégories et les dates de mise à jour. Combinez le tout dans un tibble.

catalogue <- tibble(
  titre = html_element(cartes, ".dataset-title") |> html_text2(),
  producteur = html_element(cartes, ".dataset-producer") |> html_text2(),
  categorie = html_element(cartes, ".dataset-category") |> html_text2(),
  date_mise_a_jour = html_element(cartes, ".dataset-updated") |>
    html_text2() |>
    as.Date()
)

catalogue
# A tibble: 6 × 4
  titre                                    producteur categorie date_mise_a_jour
  <chr>                                    <chr>      <chr>     <date>
1 Arbres non-répertoriés                   Ville de … Environn… 2026-07-10
2 Pistes cyclables                         Ville de … Infrastr… 2025-11-25
3 Milieux humides RCI                      Ville de … Environn… 2026-06-02
4 Avis de grands travaux                   Ville de … Infrastr… 2026-07-11
5 Chantiers - 511                          Ville de … Transport 2026-07-11
6 RSQA - indice de la qualité de l'air te… Ville de … Environn… 2026-07-11      

Bloc B - Transformer l’extraction en fonction

Exercice 4 - Créer une fonction auxiliaire

Créez une fonction extraire_texte() qui reçoit un noeud HTML et un sélecteur CSS, puis retourne le texte correspondant. Si l’élément manque, la fonction doit retourner NA_character_.

extraire_texte <- function(noeud, selecteur) {
  element <- html_element(noeud, selecteur)
  texte <- html_text2(element)

  if (length(texte) == 0 || is.na(texte) || !nzchar(texte)) {
    return(NA_character_)
  }

  texte
}

extraire_texte(cartes[[1]], ".dataset-title")
[1] "Arbres non-répertoriés"
extraire_texte(cartes[[1]], ".champ-inexistant")
[1] NA

Exercice 5 - Créer une fonction d’extraction

Écrivez une fonction extraire_catalogue(fichier) qui lit une page HTML locale et retourne un tibble avec les colonnes titre, producteur, categorie, date_mise_a_jour.

extraire_catalogue <- function(fichier) {
  page <- read_html(fichier)
  cartes <- html_elements(page, ".dataset-card")

  tibble(
    titre = map_chr(cartes, extraire_texte, ".dataset-title"),
    producteur = map_chr(cartes, extraire_texte, ".dataset-producer"),
    categorie = map_chr(cartes, extraire_texte, ".dataset-category"),
    date_mise_a_jour = map_chr(cartes, extraire_texte, ".dataset-updated") |>
      as.Date()
  )
}

extraire_catalogue("data/catalogue_donnees_quebec.html")
# A tibble: 6 × 4
  titre                                    producteur categorie date_mise_a_jour
  <chr>                                    <chr>      <chr>     <date>
1 Arbres non-répertoriés                   Ville de … Environn… 2026-07-10
2 Pistes cyclables                         Ville de … Infrastr… 2025-11-25
3 Milieux humides RCI                      Ville de … Environn… 2026-06-02
4 Avis de grands travaux                   Ville de … Infrastr… 2026-07-11
5 Chantiers - 511                          Ville de … Transport 2026-07-11
6 RSQA - indice de la qualité de l'air te… Ville de … Environn… 2026-07-11      

Exercice 6 - Tester une page irrégulière

Utilisez la même fonction sur catalogue_donnees_quebec_irregulier.html. Certaines fiches officielles ne sont associées à aucune catégorie dans le portail. Quelles valeurs manquent?

catalogue_irregulier <- extraire_catalogue("data/catalogue_donnees_quebec_irregulier.html")

catalogue_irregulier
# A tibble: 4 × 4
  titre                                    producteur categorie date_mise_a_jour
  <chr>                                    <chr>      <chr>     <date>
1 Débits de circulation                    Ville de … <NA>      2025-11-20
2 Sondage de satisfaction auprès des cito… Ville de … <NA>      2026-04-07
3 Zones inondables                         Ville de … Environn… 2026-06-01
4 Sentiers pédestres                       Ville de … Tourisme… 2026-07-06      
catalogue_irregulier |>
  summarise(
    producteurs_manquants = sum(is.na(producteur)),
    categories_manquantes = sum(is.na(categorie))
  )
# A tibble: 1 × 2
  producteurs_manquants categories_manquantes
                  <int>                 <int>
1                     0                     2

La fonction ne s’arrête pas lorsqu’un champ manque. Elle retourne NA, ce qui permet de diagnostiquer le problème dans un tableau.

Exercice 7 - Automatiser sur plusieurs pages

Utilisez purrr::imap_dfr() pour appliquer extraire_catalogue() aux deux pages de catalogue et ajouter une colonne source.

fichiers_catalogue <- c(
  regulier = "data/catalogue_donnees_quebec.html",
  irregulier = "data/catalogue_donnees_quebec_irregulier.html"
)

catalogues_combines <- imap_dfr(
  fichiers_catalogue,
  function(fichier, source) {
    extraire_catalogue(fichier) |>
      mutate(source = source, .before = 1)
  }
)

catalogues_combines
# A tibble: 10 × 5
   source     titre                        producteur categorie date_mise_a_jour
   <chr>      <chr>                        <chr>      <chr>     <date>
 1 regulier   Arbres non-répertoriés       Ville de … Environn… 2026-07-10
 2 regulier   Pistes cyclables             Ville de … Infrastr… 2025-11-25
 3 regulier   Milieux humides RCI          Ville de … Environn… 2026-06-02
 4 regulier   Avis de grands travaux       Ville de … Infrastr… 2026-07-11
 5 regulier   Chantiers - 511              Ville de … Transport 2026-07-11
 6 regulier   RSQA - indice de la qualité… Ville de … Environn… 2026-07-11
 7 irregulier Débits de circulation        Ville de … <NA>      2025-11-20
 8 irregulier Sondage de satisfaction aup… Ville de … <NA>      2026-04-07
 9 irregulier Zones inondables             Ville de … Environn… 2026-06-01
10 irregulier Sentiers pédestres           Ville de … Tourisme… 2026-07-06      

Bloc C - Sobriété et éthique de collecte

Exercice 8 - Interpréter un robots.txt

Voici un exemple fictif de fichier robots.txt.

robots_exemple <- c(
  "User-agent: *",
  "Disallow: /admin/",
  "Disallow: /api/privee/",
  "Crawl-delay: 1"
)

writeLines(robots_exemple)
User-agent: *
Disallow: /admin/
Disallow: /api/privee/
Crawl-delay: 1

Identifiez les chemins à éviter et expliquez pourquoi ce fichier ne constitue pas une autorisation complète de collecte.

chemins_interdits <- robots_exemple |>
  str_subset("^Disallow:") |>
  str_remove("^Disallow:\\s*")

chemins_interdits
[1] "/admin/"      "/api/privee/"

robots.txt donne des consignes techniques aux robots. Il ne remplace pas les conditions d’utilisation, le jugement éthique, la prudence sur la charge serveur ou une autorisation écrite lorsque la collecte et la redistribution sont sensibles.

Étude de cas 1 - Catalogue municipal québécois

Vous devez produire un court résumé de métadonnées publiées par plusieurs municipalités québécoises dans Données Québec.

Exercice 9 - Résumer les catégories

À partir des deux pages de catalogue combinées, calculez le nombre de jeux de données par catégorie.

resume_categories <- catalogues_combines |>
  mutate(categorie = replace_na(categorie, "Non indiquee")) |>
  count(categorie, sort = TRUE)

resume_categories
# A tibble: 7 × 2
  categorie                                                                    n
  <chr>                                                                    <int>
1 Environnement, ressources naturelles et énergie                              3
2 Non indiquee                                                                 2
3 Environnement, ressources naturelles et énergie; Loi, justice et sécuri…     1
4 Infrastructures                                                              1
5 Infrastructures; Transport                                                   1
6 Tourisme, sports et loisirs                                                  1
7 Transport                                                                    1

Exercice 10 - Produire une note de collecte

Écrivez trois phrases qui expliquent ce que votre code collecte, comment il limite les risques et ce qu’il faudrait vérifier avant de l’appliquer à un vrai site.

Le code lit seulement des pages HTML locales préparées pour l’exercice et extrait des champs publics agrégés. Dans un vrai contexte, il faudrait limiter le nombre de pages, ajouter des pauses entre les requêtes et éviter toute collecte massive ou contourner des protections. Il faudrait aussi vérifier robots.txt, les conditions d’utilisation, la licence des données et les règles de redistribution avant de publier une table dérivée.

Étude de cas 2 - Page d’événements publics

Le ministère du Tourisme publie des événements du SIT Québec. L’instantané retient six événements annoncés à Gatineau, Montréal, Québec, Saguenay, Sherbrooke et Trois-Rivières. Vous voulez extraire les titres, les dates, les lieux et les types pour produire un calendrier.

Exercice 11 - Extraire les événements

Créez une fonction extraire_evenements(fichier) qui retourne un tibble avec les colonnes titre, date, lieu, theme.

extraire_evenements <- function(fichier) {
  page <- read_html(fichier)
  evenements <- html_elements(page, ".event-card")

  tibble(
    titre = map_chr(evenements, extraire_texte, ".event-title"),
    date = html_element(evenements, ".event-date") |>
      html_attr("datetime") |>
      as.Date(),
    lieu = map_chr(evenements, extraire_texte, ".event-location"),
    theme = map_chr(evenements, extraire_texte, ".event-theme")
  )
}

evenements <- extraire_evenements("data/evenements_sit_quebec.html")

evenements
# A tibble: 6 × 4
  titre                                                   date       lieu  theme
  <chr>                                                   <date>     <chr> <chr>
1 Festival Parasol                                        2026-07-15 Gati… Fest…
2 Rendez-vous familial des pompiers et pompières de Mont… 2026-07-11 Mont… Fête…
3 L'Horizon de Khéops à Québec                            2026-07-15 Québ… Expé…
4 Festival International des Rythmes du Monde             2026-07-16 Sagu… Fest…
5 La Fête du Lac des Nations Promutuel Assurance          2026-07-14 Sher… Fest…
6 Rendez-vous des coureurs des bois de Trois-Rivières     2026-07-17 Troi… Fest…

Exercice 12 - Vérifier le résultat

Produisez un résumé du nombre d’événements par thème et formulez une vérification simple qui pourrait servir de test.

evenements |>
  count(theme, sort = TRUE)
# A tibble: 3 × 2
  theme                                 n
  <chr>                             <int>
1 Festival                              4
2 Expérience multimédia / immersive     1
3 Fête populaire                        1
stopifnot(
  nrow(evenements) == 6,
  identical(names(evenements), c("titre", "date", "lieu", "theme")),
  all(!is.na(evenements$titre))
)

Ces tests sont simples, mais ils détectent déjà des erreurs fréquentes: mauvais nombre de lignes, colonnes mal nommées ou titres non extraits.

GPT STT-1100