Peut-être vous demandez-vous à quoi peut bien servir concrètement le web-scraping pour un chercheur en sciences humaines/sociales… Alors, soyons plus concret!

Il y a un an, lorsque je débutais ma réflexion sur mon projet de mémoire, je comptais étudier l’Alsace dans son entièreté. Pour ce faire, j’avais besoin d’une petite base de données pour me lancer. Malheureusement, les données dont j’avais besoin, les anciens recensements, ne m’étaient disponibles que sur le site du Projet Cassini de l’EHESS en France. Leur site, quelque peu pénible à consulter, compliquait mon travail, mais même sans cette difficulté, la tâche était gigantesque… En guise de solution, j’avais donc utilisé BeautifulSoup pour récupérer rapidement les données. Je n’ai plus ce code, mais j’ai refait l’exercice sur Selenium pour cette formation. Je me suis cette fois concentré sur le département du Bas-Rhin sur le site du Projet Cassini. En guise de défi, tentez de décortiquer le résultat:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import csv
import time
nb = 0
driver = webdriver.Chrome("D:Mon DrivePythonTestchromedriver.exe")
driver.get("http://cassini.ehess.fr/cassini/fr/html/6d_index_dept.php")
print("Page en chargement")
time.sleep(5)
selection = driver.find_element_by_name("index_d")
driver.switch_to.frame(selection)
print("Accès à la liste des communes")
driver.implicitly_wait(10)
selection = driver.find_element_by_link_text("67")
selection.click()
liste_commune = [driver.find_elements_by_css_selector("#liste_g div"), driver.find_elements_by_css_selector("#liste_d div")]
communes = []
raw = ""
print("Début de l'extraction")
for col in liste_commune:
     for ediv in col:
          raw = ediv.get_attribute("onclick")
          raw = raw.split("'")
          raw = raw[1].replace("fiche.php?select_resultat=", "")
          communes.append(raw)
          nb += 1
          print("Nouvel ID : " + str(raw) + "   |  Total: "+ str(nb))
communes = list(dict.fromkeys(communes))
baseurl = "http://cassini.ehess.fr/cassini/fr/html/fiche.php?select_resultat="
with open('BasRhin.csv', 'w', newline='', encoding='utf-8') as fichier:
     dataAjout = csv.writer(fichier, delimiter=';')
     dataAjout.writerow(["NOM", "ARR", "CANTON", "LONG", "LAT", "POP1872", "POP1876", "POP1881", "POP1886", "POP1891", "POP1896", "POP1901", "POP1906", "POP1911", "POP1921", "POP1926", "POP1931", "POP1936", "POP1946"])
     i = 0
     nomVille = arrondissement = canton = longitude = latitude = pop1872 = pop1876 = pop1881 = pop1886 = pop1891 = pop1896 = pop1901 = pop1906 = pop1911 = pop1921 = pop1926 = pop1931 = pop1936 = pop1946 = ""
     for commune in communes:
          driver.get(baseurl + commune)
          nomVille = driver.find_element_by_css_selector("#bloc h4").text
          arrondissement = driver.find_element_by_xpath("//*[@id='bloc']/table[2]/tbody/tr[3]/td[2]").text
          canton = driver.find_element_by_xpath("//*[@id='bloc']/table[2]/tbody/tr[4]/td[2]").text
          latlong = driver.find_element_by_xpath("//*[@id='bloc']/table[1]/tbody/tr[3]/td[3]").text
          latlong = latlong.replace("longitude : ", "")
          latlong = latlong.replace("latitude : ", "!")
          latlong = latlong.split("!")
          try:
               longitude = latlong[0]
               latitude = latlong[1]
          except:
               longitude = "0"
               latitude = "0"
          pop1872 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[7]/td[2]").text.replace("1872 ","")
          pop1876 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[1]/td[3]").text.replace("1876 ","")
          pop1881 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[2]/td[3]").text.replace("1881 ","")
          pop1886 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[3]/td[3]").text.replace("1886 ","")
          pop1891 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[4]/td[3]").text.replace("1891 ","")
          pop1896 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[5]/td[3]").text.replace("1896 ","")
          pop1901 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[6]/td[3]").text.replace("1901 ","")
          pop1906 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[7]/td[3]").text.replace("1906 ","")
          pop1911 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[1]/td[4]").text.replace("1911 ","")
          pop1921 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[2]/td[4]").text.replace("1921 ","")
          pop1926 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[3]/td[4]").text.replace("1926 ","")
          pop1931 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[4]/td[4]").text.replace("1931 ","")
          pop1936 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[5]/td[4]").text.replace("1936 ","")
          pop1946 = driver.find_element_by_xpath("//*[@id='bloc']/table[6]/tbody/tr[6]/td[4]").text.replace("1946 ","")
          dataAjout.writerow([nomVille, arrondissement, canton, longitude, latitude, pop1872, pop1876, pop1881, pop1886, pop1891, pop1896, pop1901, pop1906, pop1911, pop1921, pop1926, pop1931, pop1936, pop1946])
          i += 1
          print("Ajout de " + nomVille)
print("Opération terminée!n" + str(i) + " communes ajoutées sur " + str(nb) + " communes (incluant doublons)")
driver.quit()

Ce script m’a demandé environ 40 minutes de programmation et peut être réutilisé pour récupérer les données du département de mon choix sur le site du Projet Cassini. Le script récupère d’abord l’ensemble des liens hypertextes permettant d’ouvrir la fiche d’une commune, on traite la chaîne de caractère uniquement pour obtenir le ID unique de la commune sur le site. Puis, le script retire les doublons avant de lancer le «raclage» des données. Pour racler les données, le script ouvre tour à tour les fiches des communes en concaténant une URL de base et le ID unique. Sur la page, il récupère près de 20 champs, en forme une ligne de données, puis l’ajoute à un fichier CSV.

Après seulement 11 minutes de traitement, on obtient un CSV mis en forme contenant 594 lignes contenant chacune 19 champs, soit 11 286 données…Cela fait 51 minutes en incluant la programmation. Combien de temps croyez-vous nécessaire à la réalisation du même fichier CSV sans l’automatisation, donc à la main?

Nous avons essayé avec une commune, pour obtenir un temps minimal de 3 minutes pour récupérer les données et les mettre en forme. Supposons que 3 minutes représentent une durée moyenne, il faudrait 29h42 pour réaliser la même tâche… Et même là, nous serions loin du compte, puisqu’il faut aussi gérer les doublons comme le fait notre script… On se rapproche peut-être plutôt des 35 heures sans pauses… Pour simplifier, disons 30 heures.

On veut maintenant reproduire cette même opération pour l’ensemble des 95 départements de France… (En supposant que les départements contiennent le même nombre de communes uniques):

Pour le web-scraping, on multiplie nos 11 minutes par 95 départements, puis on ajoute nos 40 minutes de programmation (une seule fois). On obtient donc 1085 minutes, donc un peu plus de 18h de travail pour l’ordinateur. À la main, on doit multiplier 30 heures par 95 départements, pour un total de 171000 minutes, donc 2850 heures… Cela représente près 119 jours de travail sans arrêt. Vous avez donc le choix entre laisser votre ordinateur travailler durant 18h, pendant que vous vaquez à vos occupations, ou bien passer 407 jours à consacrer 7 heures par jour à une tâche répétitive, avec le risque de faire des erreurs…

Soyez efficients! Le script pourrait facilement être plus efficient, je n’ai pas pris le temps de l’optimiser, mais il pourrait être nettement plus rapide!

Vous trouverez le déroulement du programme ci-dessous: