Élections 2015: palmarès du «scraping»
Il est devenu coutume, quand approchent des élections, de comparer les sites web des partis, leur présence sur les réseaux sociaux, etc. J’ai fait un banc d’essai avec une «question de recherche» qui est, je le crois bien, inédite:
quel est le parti dont le site est le mieux fait pour faire du scraping, pour en extraire de l’information?
J’ai donc rédigé cinq scripts pour extraire quelques données des sites web des cinq principaux partis politiques qui participeront à l’élection fédérale du 19 octobre prochain: une simple liste de candidats en format CSV avec leur nom, leur circonscription, leur province, et des infos de contact. J’ai aussi inclus une minuterie dans mes scripts: je prends l’heure quand le script commence et la prends à nouveau quand il arrête, puis je fais la différence entre les deux. Voici les résultats:
NPD : 1,9 secondes
La page des candidats du Nouveau parti démocratique est un charme à scraper. Tout est accessible rapidement et tient en une seule page web. Bref, c’est un site conçu pour faciliter la diffusion de l’information.
Bloc québécois : 3,6 secondes
Si la page des candidats du Bloc prend si peu de temps à extraire, c’est en grande partie en raison du fait qu’elle contient beaucoup moins de candidats que les autres partis. Non seulement le Bloc n’est présent qu’au Québec, mais il est encore loin d’avoir des candidats dans les 78 circonscriptions de la province.
Le site du Bloc comporte néanmoins une difficulté. Tous les candidats n’apparaissent pas dans la page. Pour les avoir tous, il faut soit faire défiler la page vers le bas, soit cliquer sur un bouton intitulé «Dévoiler plus» qui apparaît en bas de page.
C’est un problème, car en scraping, on aime les pages statiques. Ici, la page est dynamique: il faut cliquer ou scroller pour charger tout le contenu.
Heureusement, il appert que le contenu qu’on fait apparaître lorsqu’on clique sur ce bouton est aussi accessible sur d’autres pages disposant chacune d’un URL distinct:
http://www.blocquebecois.org/equipe-2015/candidats/page/2/
,
http://www.blocquebecois.org/equipe-2015/candidats/page/3/
et ainsi de suite.
Il est donc possible de faire une boucle pour aller chercher toutes ces pages, qui sont statiques, et en extraire l’info qui nous intéresse (tout en prenant le soin de s’identifier, car le journalisme se fait à visière levée):
urlBloc = "http://www.blocquebecois.org/equipe-2015/candidats/" # [...] (1..5).each do |page| url = urlBloc + "page/#{page}" pageBloc = Nokogiri::HTML(open(url, "User-Agent" => "Jean-Hugues Roy, UQAM (roy.jean-hugues@uqam.ca)")) # extraction
Parti libéral : 10,5 secondes
Aussi facile de glaner l’info, ici, que dans le cas du NPD. Ces deux partis sont vraiment faits pour aller ensemble!
Chaque candidat est dans une balise li
à l’intérieur de laquelle on identifie facilement les différents éléments.
Je me suis même servi du site du Parti libéral pour construire une variable des codes de circonscription qui a été utile pour scraper le site du parti suivant.
urlLib = "https://www.liberal.ca/fr/candidats/" # [...] pageLib = Nokogiri::HTML(open(urlLib, "User-Agent" => "Jean-Hugues Roy, UQAM (roy.jean-hugues@uqam.ca)")) # variable-tableau codeCirc codeCirc = [] pageLib.css("li.candidate-type-candidate").map do |pouetpouet| codeCirc.push pouetpouet["data-riding-riding_id"] end
Parti vert : 9 minutes et 49,2 secondes
Whoa! Qu’est-ce qui se passe, ici? On passe de quelques secondes à quelques minutes!
C’est simplement parce que la page des candidats du Parti vert ne contient pas toute l’info. On est obligés d’aller sur la page de chacun des candidats pour recueillir toutes les infos sur ces derniers.
Les URL de ces pages sont construits avec les codes de circonscription que j’ai préalablement recueillis sur le site du Parti libéral. Avec le code 24010, par exemple, on peut faire l’URL de la page du candidat dans la circonscription Bellechasse — Les Etchemins — Lévis, André Bélisle.
Parti conservateur : 14 minutes et 4,0 secondes
La palme du code qui donne envie de sacrer son ordinateur par la fenêtre revient cependant au site du Parti conservateur. Sa page de candidats a l’air simple à scraper quand on en inspecte le HTML. Mais c’est rempli de sournoiseries dynamiques qui font que ce qu’on voit dans l’inspecteur de code n’est pas recueilli par notre script, si on s’en tient aux bibliothèques de scraping classiques (Nokogiri, dans le cas du ruby, BeautifulSoup dans le cas du python, node-soupselect dans le cas du node.js).
Il faut donc utiliser un webdriver, qui permet d’extraire de l’info d’un site dynamique. Et pour y parvenir, il a fallu faire une quantité invraisemblable d’essais et d’erreurs pour parvenir à ce code qui fait en sorte qu’on clique virtuellement sur un lien appelé «Candidats» et qu’on attende que la page se charge au complet (on considère qu’elle est toute chargée quand le candidat du Yukon, qui apparaît toujours en dernier, le pauvre, est là):
cons = Watir::Browser.new cons.goto urlCon lien = cons.link :text => "Candidats" lien.click cons.div(:id => "candidates-yt").wait_until_present
On demande ensuite à notre webdriver de mettre une partie du contenu de la page qui vient d’être chargée (un div
ayant pour id
la valeur de candidates
) dans une variable qu’on va appeler liste
:
liste = cons.div(:id => "candidates")
Ensuite, on peut utliser un extracteur plus classique pour analyser (parse) notre variable:
pageCon = Nokogiri::HTML::Document.parse(liste.html)
Comme dans le cas du Parti vert, chaque candidat conservateur a sa propre page. Mais voilà. Pour compliquer la vie du scrapeur, les pages de certains candidats ne fonctionnent pas. Les codeurs conservateurs ne sont pas capables d’écrire correctement les noms de certains de leurs candidats. Un exemple?
Pour scraper les infos d’un candidat, il faut aller sur la page qui apparaît lorsqu’on clique sur le lien «Pour en savoir plus». Dans le cas de Mme O’Neill Gordon, voici le l’URL vers lequel on est envoyé:
http://www.conservateur.ca/equipe/member/?fname=Tilly&lname=O%27Neill%20Gordon&type=candidates
Fin juillet, lorsqu’on clique sur ce lien, on aboutit ici:
Un amusante page d’erreur 404 trafiquée par les conservateurs avec l’image de Justin Trudeau. Le Huff Post en avait déjà parlé. Le problème, c’est que j’ai essayé de corriger cet hyperlien en remplaçant l’apostrophe du O’Neill (codée %27) par d’autres caractères semblables (%60, %92, un espace, rien du tout, alouette). Mais en vain.
Bref, des pépins ridicules comme celui-ci deviennent des obstacles considérables quand on scrape un site dynamique qui peut prendre jusqu’à 15 minutes à chaque essai!
Le site conservateur se démarque pour une autre raison. En consultant l’inspecteur de code, on se rend compte que ses créateurs ont donné le nom de Stephen Harper à plusieurs classes dans leur feuille de style. C’est vraiment étrange! Et ça donne ça quand on consulte le code de la candidate dans Drummond, par exemple:
On est pas loin du cyber-culte de la personnalité.
Bref, j’ai réuni les cinq scripts en un seul, l’ai fait rouler ce matin, et voici les performances de chaque parti:
Mise à jour, 2 août.
Sur Twitter, Jean-François Fortin a posé une bonne question:
@jeanhuguesroy Intéressant, mais que devons-nous conclure de cette démarche?
— Jean-François Fortin (@JeanFrancoisF) 1 Août 2015
À quoi bon faire pareil exercice, donc? Le but original n’était pas de comparer les cinq partis, mais de trouver une façon de constituer dès maintenant, avant que la campagne électorale soit officiellement lancée, une liste de candidats. Ce script peut être exécuté régulièrement (deux, trois ou quatre fois par jour, par exemple) afin d’avoir une liste continuellement à jour.