Script “Exercices Supplémentaires”

## Stratégies Numériques en Sciences Sociales - 2021
## Julien Boelaert, Etienne Ollion
## Exercices supplémentaires

## Ce script est encodé en UTF-8 ; si les accents ne s'affichent pas bien, 
## utilisez dans Rstudio le menu Fichier -> Réouvrir avec encodage... 
## et choisissez UTF-8.


#############
## Préliminaires : environnement, bibliothèques
#############

rm(list = ls())
## Conseil : redémarrez la session R, Ctr+Shift+F10

setwd("~/cours/20-21 SICSS Scraping/playground/") # à adapter

## Installation des bibliothèques
# install.packages(c("httr", "XML", "scraEP"))

library(httr) # Pour la fonction GET
library(XML) # Pour les fonctions htmlParse, et xpathSApply
library(scraEP) # Pour la fonction xscrape



#############
## Exercice : lemonde
## URL : https://css.cnrs.fr/scrape/lemonde
## Consigne : 
## 1 - Télécharger et parser la page
## 2 - Extraire, en une data.frame, les titres et les liens des 21 articles à la
## "une"
## 3 - Compter, parmi l'ensemble des liens de cette page, combien redirigent en
## dehors du domaine lemonde.fr
#############

## Téléchargement et parsing
lemonde.brut <- GET("https://css.cnrs.fr/scrape/lemonde")
writeLines(as.character(lemonde.brut), "lemonde.html")
lemonde.parse <- htmlParse("lemonde.html")

## Extraction des titres et liens des 21 articles à la une
## Méthode 1 : en deux vecteurs indépendants
lem.titres <- xpathSApply(
  lemonde.parse, 
  "//section[contains(@class, 'zone--homepage')]//div[contains(@class, 'article')]//a", 
  xmlValue)
lem.liens <- xpathSApply(
  lemonde.parse, 
  "//section[contains(@class, 'zone--homepage')]//div[contains(@class, 'article')]//a/@href")
lem.table1 <- data.frame(titre = lem.titres, lien = lem.liens)


## Extraction des titres et liens des 21 articles à la une
## Méthode 2 : avec une boucle sur les noeuds intermédiaires
lem.articles <- xpathSApply(
  lemonde.parse, 
  "//section[contains(@class, 'zone--homepage')]//div[contains(@class, 'article')]//a")
lem.titres <- NULL
lem.liens <- NULL
for (i in 1:length(lem.articles)) {
  tmp.titre <- xpathSApply(lem.articles[[i]], ".", xmlValue)
  tmp.lien <- xpathSApply(lem.articles[[i]], "./@href")
  lem.titres <- c(lem.titres, tmp.titre)
  lem.liens <- c(lem.liens, tmp.lien)
}
lem.table2 <- data.frame(titre = lem.titres, lien = lem.liens)


## Extraction des titres et liens des 21 articles à la une
## Méthode 3 : avec xscrape 
## Remarque : xscrape garantit de ne pas avoir de surprises (mauvais alignement
## des lignes) dans le résultat, contrairement aux deux méthodes précédentes.
lem.table3 <- xscrape(
  lemonde.parse, 
  row.xpath = "//section[contains(@class, 'zone--homepage')]//div[contains(@class, 'article')]//a", 
  col.xpath = c(titre = ".", lien = "./@href"))


## Décompte des liens internes et externes
lemonde.liens <- xpathSApply(lemonde.parse, "//a/@href")
lemonde.lien.interne <- 
  grepl("^https?://[^/]+?lemonde[.]fr\\b", lemonde.liens) |
  grepl("^#$", lemonde.liens)
table(lemonde.lien.interne)



#############
## Exercice : europresse
## URL : https://css.cnrs.fr/scrape/europresse
## Consigne : 
## 1 - Télécharger et parser la page
## 2 - Extraire, en une data.frame comprenant un article par ligne, les champs 
## suivants en colonnes : journal, auteur, date, titre, sous-titre, et texte
#############

## Téléchargement et parsing
epress.brut <- GET("https://css.cnrs.fr/scrape/europresse")
epress.char <- as.character(epress.brut)
writeLines(epress.char, "europresse.html")
epress.parse <- htmlParse("europresse.html")

## Méthode 1 : 
## Extraction avec xscrape
## Note : la version xml2 permet de nettoyer le texte
epress.table <- xscrape(
  epress.parse, engine = "xml2",
  row.xpath = "//article", 
  col.xpath = c(journal = './/span[@class="DocPublicationName"]', 
                auteur = './/div[@class="docAuthors"]', 
                date = './/span[@class="DocHeader"]', 
                titre = './/p[contains(@class, "titreArticleVisu")]', 
                soustitre = './/p[@class="rdp__subtitle"]', 
                texte = './/section'))


## Méthode 2 : 
## Extraction en passant par les noeuds intermédiaires (ici les articles) et des
## boucles
epress.articles <- xpathSApply(epress.parse, "//article")
## Créons une fonction pour nous assurer qu'un résultat soit toujours de
## longueur 1 : s'il est vide on lui donne NA, s'il est multiple on concatène
## les chaînes de caractères
postprod <- function(x) {
  if (length(x) == 0) return(NA)
  if (length(x) > 1) return(paste(x, collapse = " | "))
  x
}
## Et procédons à la boucle (ici uniquement pour journal, date, titre et texte)
epress.journal <- epress.date <- epress.titre <- epress.texte <- NULL
for (iart in seq_along(epress.articles)) {
  ## Journal
  tmp.journal <- xpathSApply(epress.articles[[iart]], 
                             './/span[@class="DocPublicationName"]', xmlValue)
  epress.journal <- c(epress.journal, postprod(tmp.journal))
  
  ## Date
  tmp.date <- xpathSApply(epress.articles[[iart]], 
                             './/span[@class="DocHeader"]', xmlValue)
  epress.date <- c(epress.date, postprod(tmp.date))
  
  ## Titre
  tmp.titre <- xpathSApply(epress.articles[[iart]], 
                          './/p[contains(@class, "titreArticleVisu")]', xmlValue)
  epress.titre <- c(epress.titre, postprod(tmp.titre))
  
  ## Texte
  tmp.texte <- xpathSApply(epress.articles[[iart]], 
                          './/section', xmlValue)
  epress.texte <- c(epress.texte, postprod(tmp.texte))
}

epress.table2 <- data.frame(journal = epress.journal, 
                            date = epress.date, 
                            titre = epress.titre, 
                            texte = epress.texte)


#############
## Exercice : leboncoin
## URL : https://css.cnrs.fr/scrape/boncoin-page1 , 
## https://css.cnrs.fr/scrape/boncoin-page2, 
## https://css.cnrs.fr/scrape/boncoin-page3
## Consigne : 
## 1 - Télécharger et parser les trois pages en une liste
## 2 - Extrayez de la première page les informations suivantes en une data.frame
## avec une ligne par article et les colonnes : description et prix
## 3 - Transformer ces trois pages en une seule data.frame, avec une ligne par 
## objet en vente, et en colonne : la description de l'objet, le prix, 
## le code postal et l'heure de dépôt de l'annonce
#############

## Téléchargement 
urls <- paste0("https://css.cnrs.fr/scrape/boncoin-page", 1:3)
fichiers <- gsub("^.*/(.*)$", "\\1.html", urls)
for (i in 1:3) {
  cat(urls[i], "\n")
  bc.brut <- GET(urls[i])
  writeLines(as.character(bc.brut), fichiers[i])
  Sys.sleep(1)
}

## Parsing en une liste de trois pages parsées
bc.parse <- lapply(fichiers, htmlParse)

## Extraction depuis la première page : description et prix
bc.page1 <- xscrape(
  bc.parse[[1]], 
  row.xpath = '//div[contains(@class, "styles_adCard__2YFTi")]', 
  col.xpath = c(description = './/p[contains(@class, "AdCardTitle")]', 
                prix = './/span[@data-qa-id="aditem_price"]'))

## Extraction depuis les trois pages : description, prix, code postal, heure
bc.articles <- xscrape(
  bc.parse, 
  row.xpath = '//div[contains(@class, "styles_adCard__2YFTi")]', 
  col.xpath = c(description = './/p[contains(@class, "AdCardTitle")]', 
                prix = './/span[@data-qa-id="aditem_price"]', 
                datelieu = './/span[@class="_2k43C Dqdzf cJtdT _3j0OU"]//span'))
## Nettoyage code postal :
bc.articles$postal <- gsub("^.*(\\d{5}).*$", "\\1", bc.articles$datelieu)
bc.articles$postal <- as.numeric(bc.articles$postal)
## Nettoyage heure : 
bc.articles$heure <- gsub("^.*(\\d{2}:\\d{2}).*$", "\\1", bc.articles$datelieu)
bc.articles$heure[!grepl(":", bc.articles$heure)] <- NA