1. Présentation du web scraping
À l'heure de l'open et du big data, la collecte de données (textes, images, fichiers hébergés) sur Internet devrait dans les années à venir être au centre de toutes les considérations. Référencement, collecte d'informations, provisioning et configuration d'équipements réseau, hacking, bots, le web scraping ou screen scraping est apparu au cours des années 90 dans un certain flou juridique.
1.1 Web scraping, une technique illégale ?
Malheureusement, depuis sa création, la popularité du web scraping s'est effectuée au travers de nombreuses affaires juridiques plutôt que pour ses aspects techniques. En 2008, Ryan Air gagna un procès à la cour de Hambourg contre le tour opérateur Vtours dans le cadre d'extractions de données (horaires des vols et tarifs) jugées illégales. Depuis ce jour, la compagnie ne lésine pas sur le développement de techniques permettant le barrage de toute tentative de scraping. En France, le site d'annonces immobilières « De Particulier à Particulier » a fait condamner quant à lui plusieurs entreprises dans le cadre d'atteinte aux droits de « producteur de sa base de données ».
Le web scraping serait donc une technique de cyber voyous ? Heureusement non ! De nombreuses entreprises et projets open source utilisent cette technique, tels que OpenStreetMap, WP Rocket, le Medialabde Sciences Po Paris, ainsi que plus généralement, des comparateurs de prix et autres réseaux sociaux.
1.2 Aspect légal ?
Quand est-il en France ?
Au titre de l'article L341-1 de la propriété intellectuelle, vous encourez jusqu’à 300 000 euros d'amende et 3 ans d'emprisonnement pour l'utilisation et l'extraction illégale de contenus. Cet article devrait toutefois apparaître dans les conditions générales d'utilisation du site, les fameuses CGU. Plus généralement, d'autres données telles que des données textuelles et images sont également soumises aux droits d'auteur.
1.3 Quel outil pour scraper ?
Que ce soit sous la forme de librairies (WWW::Mechanize en Perl, Ruby et Python, Simple HTML DOM Parser en PHP) ou de frameworks (Scrapy en Python), il existe de nombreuses solutions de scraping. Dans cet article, nous utiliserons la librairie WWW::Mechanize accompagnée du langage Perl et le serveur Selenium Remote Control en langage Java, associé lui-même à la librairie WWW::Selenium, toujours en langage Perl.
2. Le web scraping avec Mechanize et Selenium
2.1 Topologie de page web
Avant de scraper vos premières données, il est préférable d'étudier la topologie et la complexité de la page. Posez-vous les questions suivantes : votre page contient-elle une authentification HTTP ? Du JavaScript ? Des cookies ?
Comme nous allons le voir, il existe une méthode pour chacune de ces réponses.
2.2 WWW::Mechanize, une librairie dédiée au scraping
WWW::Mechanize est une librairie Perl permettant de scraper du contenu web très simplement.
2.2.1 Installation
Deux possibilités s'offrent à vous dans l'installation du package :
- via le CPAN :
cpan install WWW::Mechanize
- via les dépôts de votre distribution Debian ou dérivée :
apt-get install libwww-mechanize-perl
Afin de vérifier que votre module est bien installé, exécutez la commande :
perl -e 'use WWW::mechanize'
Si cette commande ne renvoie aucun retour, c'est qu'il est installé.
2.2.2 Développement du script « scraping.pl »
Notre librairie est maintenant installée ; créons notre premier script, que nous appellerons scraping.pl. Ce script aura pour fonction de récupérer le contenu d'une page cible. Dans notre exemple, la page cible sera la page d'accueil du site www.unixgarden.com.
#!/usr/bin/perl
use strict;
use warnings;
use www::mechanize;
use Data::Dumper;
#Définition de l'URL
my $url = 'http://www.unixgarden.com/';
#Instanciation de l'objet mech
#Définition du user agent « Mozilla Firefox, sous OS Linux »
#Mise en mémoire du cookie
my $mech = WWW::Mechanize->new(
agent => 'Mozilla/4.73 [en] (X11; I; Linux 2.2.16 i686; Nav)',
cookie_jar => {}
);
#Création de la requête HTTP GET
my $result = $mech->get($url);
#Test de la réponse HTTP,
#Si différente de 200, le script s’arrête et affiche 'Erreur de la réponse HTTP GET'
die "Erreur de la reponse HTTP GET" unless $result->is_success;
#Récupération et affichage du code de la page
print Dumper($mech->content());
Dans cette première partie, nous effectuons donc une requête vers une URL, puis nous affichons le code source récupéré.
Sachez qu'il est également possible de récupérer uniquement le texte de la page avec :
$mech->text();
Ou bien son titre :
$mech->title();
Il est également possible d'afficher l'ensemble des liens de la page :
$mech->links();
Le code HTTP de la réponse :
$mech->status;
La liste des formulaires présents :
$mech->forms;
Mechanize permet même de s'authentifier au travers de la méthode credentials :
$mech->credentials($login,$password) ;
Comme nous l'avons vu, il est assez facile d'extraire et de traiter des données.
Associez ce script à l'utilitaire wget et à quelques expressions régulières pour filtrer les données, et vous obtiendrez un robot vous permettant de télécharger en masse des données dans les méandres d'Internet. Cependant, Mechanize a une faiblesse majeure qui est de ne pas supporter JavaScript.
2.3 Aller plus loin dans le web scraping avec Selenium Remote Control
Basé sur une architecture client-serveur, Selenium Remote Control permet un scraping plus proche de l'expérience utilisateur. Survol de souris, clic droit, scrolling et j'en passe, de nombreuses options sont disponibles.
Le principe est simple : le client va envoyer des requêtes au serveur Selenium qui exécutera une instance du navigateur choisi (Firefox, Chrome ou Internet Explorer pour les plateformes Windows) et récupérera le résultat.
Notez également que dans l'exemple suivant, vous verrez votre navigateur s'ouvrir et afficher les pages à l’exécution du script. Sachez qu'il est possible de « bufferiser » les pages en mémoire, grâce à l'utilitaire xvfb (X virtual framebuffer) ; c'est d'ailleurs conseillé dans le cadre d'une mise en production d'un script de scraping sur des serveurs utilisant le runlevel 2 (sans serveur X).
Dans les exemples ci-dessous, le client sera notre script Perl utilisant la librairie WWW::Selenium. Le serveur, quant à lui, sera une archive .jar exécutée en mode standalone.
2.3.1 Installation
Comme pour WWW::Mechanize, vous avez deux possibilités :
- via le CPAN :
cpan install WWW::Selenium
- via les dépôts de votre distribution Debian ou dérivée :
apt-get install libtest-www-selenium-perl
Et comme pour le module Mechanize, vérifions si notre module est bien installé :
perl -e 'use WWW::Selenium'
Installons maintenant notre serveur Selenium Remote Control.
On commence par installer Java :
apt-get install openjdk7-jre
Puis, on télécharge l'archive à l'adresse http://docs.seleniumhq.org/projects/remote-control/.
Pour lancer le serveur, ouvrez un terminal et lancez la commande :
java -jar selenium-server-standalone-x.xx.x.jar &
2.3.2 Développement du client
Ouvrez un second terminal pour écrire le client.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use WWW::Selenium;
my $url = 'http://linuxfr.org';
# Création de l'objet Selenium
my $sel = WWW::Selenium->new( host => "localhost",
port => 4444,
browser => "*firefox",
browser_url => $url,
http_method => "POST"
);
$sel->start;
$sel->open($url);
# Définition de la rapidité d'affichage
$sel->set_speed(500);
# Temps d'attente de chargement de la page
$sel->wait_for_page_to_load(10000);
# Récupération de la source
my $page = $sel->get_html_source;
print Dumper($page);
$sel->stop;
Comme nous l'avons vu, notre client va envoyer ses requêtes sur le port 4444. L'instance de notre navigateur sera ici Firefox, il faut donc bien sûr qu'il soit installé sur votre machine. La méthode HTTP sera ici POST ; il est bien sûr possible d'utiliser une méthode de type GET.
2.3.3 Gestion des formulaires avec Selenium
Dans ce second exemple, nous allons prendre le cas d'une page contenant un formulaire, que nous allons valider après avoir renseigné des champs.
Il existe deux notions de validation dans Selenium : la première, en ciblant le nom du formulaire au travers de la méthode submit('nomduformulaire'). La seconde, en cliquant sur le bouton de validation grâce à la méthode click('valeur_name_du_bouton'). Notez qu'il est également possible de cibler un élément au travers de son arborescence CSS.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use WWW::Selenium;
my $url = 'http://www.unixgarden.com';
# Création de l'objet Selenium
my $sel = WWW::Selenium->new( host => "localhost",
port => 4444,
browser => "*firefox",
browser_url => $url,
http_method => "POST"
);
$sel->start;
$sel->open($url);
# Setting du champ avec la valeur name à 's' du formulaire avec la valeur Linux
$sel->type("s","Linux");
# Clic du bouton, ici pour l'exemple nous ciblons sur le DOM CSS de l’élément
$sel->click("css=input.bouton.padding2");
# On attend le chargement de la page suivante
$sel->wait_for_page_to_load(10000);
my $page = $sel->get_html_source;
$sel->stop;
À l’exécution du script, vous ne devriez pas voir la valeur « Linux » apparaître dans le formulaire. Si vous souhaitez voir la valeur, il faut utiliser la méthode type_keys('s','Linux');.
2.3.4 Options et restrictions avec Selenium Remote Control
Comme Mechanize, Selenium permet de récupérer le texte de la page :
$sel->get_body_text();
Le titre de la page :
$sel->get_title();
La valeur d'un élément texte en particulier ($element ici désignant l’élément cible) :
$sel->get_text($element);
Et permet de vérifier si un élément checkbox est coché :
$sel->is_checked($element);
Concernant les restrictions, Selenium permet de récupérer le contenu des alertes et autres prompts, mais uniquement après l'affichage de l'élément. En effet, Selenium ne supporte pas en direct le JavaScript.
Pour cela, trois méthodes sont disponibles :
Pour les alertes :
$sel->get_alert();
Pour les pop-up :
$sel->get_prompt();
Pour les fenêtres de confirmation :
$sel->get_confirmation();
3. Comment se prémunir contre le web scraping ?
La principale difficulté est de déterminer parmi les visiteurs qui est un robot et qui est un utilisateur « réel ». Cependant, attention à ne pas bloquer l'ensemble des robots (y compris ceux d'indexation), cette action aurait un impact conséquent dans le référencement de votre site !
Les exemples suivants utilisent le serveur web Apache 2 et le package Fail2Ban sur une distribution Debian :
apt-get install apache2-server;
apt-get Fail2ban;
3.1 Honeypot ou la technique dite du « pot de miel »
La première technique, intitulée « pot de miel », consiste en la détection du chargement d'une page spécifique que nous appellerons pot.html.
1. Créez une page pot.html vide.
2. Dans les pages de votre site, ajoutez plusieurs liens non visibles par un visiteur humain pointant vers la page pot.html.
<a href="pot.html" style="display:none;">monlien</a>
3. Interdisez ensuite aux robots d'indexation de visiter la page dans le fichier Robots.txt.
User-Agent: Googlebot, Bingbot
Disallow: pot.html
4. Puis, pour finir, vous allez créer un nouveau filtre afin de permettre à Fail2Ban de détecter notre tentative de scraping :
vi /etc/fail2ban/filter.d/apache-webscrapping.conf
[Definition]
failregex = #Définissez ici votre expression régulière
ignoreregex =
Ajoutez une jail au fichier /etc/fail2ban/jail.conf permettant de bannir les adresses IP détectées :
[apache-webscrapping]
enabled = true
filter = apache-webscrapping
action = hostsdeny
#ban IP address outright
action = iptables-allports
#define which logs to search
logpath = /var/log/apache2/access.log
#end apache-webscrapping section
Redémarrez le service :
service fail2ban reload
Puis, vérifiez que la jail ait bien prise en compte :
fail2ban-client status apache-webscrapping
Ce qui devrait retourner :
Status for the jail: apache-webscrapping
|- filter
| |- File list: /var/log/apache2/access.log
| |- Currently failed: 0
| `- Total failed: 0
`- action
|- Currently banned: 0
| `- IP list:
`- Total banned: 0
Affichez votre page pot.html dans votre navigateur. L'appel apparaîtra dans le fichier de log /var/log/apache2/access.log :
127.0.0.1 - - [02/Apr/2014:21:42:16 +0200] "GET /test/pot.html HTTP/1.1" 200 280 "-" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:22.0) Gecko/20100101 Firefox/22.0"
3.2 Détection du temps de consultation
Une autre pratique consiste en la mise en place d'un seuil de sollicitation de votre site, dans un délai que vous aurez défini ; par exemple : bloquer les adresses IP ayant consulté votre site plus de 150 fois dans un délai de 60 secondes.
Cependant, veillez dans ce cas à ajouter les adresses IP des robots Googlebot et Bingbot dans une « white list » (liste blanche), afin de ne pas bloquer l'indexation de votre site !
Notez au passage que cette pratique est également utilisée dans la détection d'attaques DDOS, ou plus généralement de flooding.
Vous utilisez ici le module Apache 2 mod_evasive :
apt-get install libapache2-mod-evasive
Éditez le fichier de configuration d'Apache /etc/apache2/apache.conf et ajoutez :
# mod_evasive
<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSSiteCount 50
DOSSiteInterval 2
DOSBlockingPeriod 300
DOSEmailNotify "votre@contactemail"
DOSLogDir "/var/log/mod_evasive/"
DOSSystemCommand "/sbin/iptables -I INPUT -s %s -j DROP -m comment –comment 'BAN WEB SCRAPPING'"
DOSWhiteList 127.0.0.1
DOSWhitelist a.b.c.* #Ajouter ici les adresses des bots à ne pas bloquer
</IfModule>
DOSSiteCount définit le nombre de fois où un site peut être demandé par la même adresse IP avant que celle-ci soit bloquée.
DOSSiteInterval détermine un intervalle en secondes qui autorise l’affichage d’un même site avant le blocage.
DOSBlockingPeriod détermine la durée de blocage.
DOSEmailNotify détermine l'e-mail à contacter dans le cas de chaque blocage d’adresse IP.
DOSSystemCommand permet de définir la commande de blocage iptables.
DOSLogDir détermine le chemin où seront stockées les détections.
DOSWhiteListe définit une liste blanche d’adresses IP.
N'oubliez pas de créer votre dossier :
mkdir /var/log/mod_evasive/
Activez le mod_evasive :
a2enmod mod-evasive
Pour finir, au-delà de toute installation, le conseil le plus simple serait bien sûr de ne pas permettre l'indexation de vos dossiers pour ainsi ne pas vous faire aspirer l'ensemble de vos données !
Conclusion
Les possibilités du web scraping, comme nous l'avons vu, sont sans fin. Les entreprises l'ayant vite intégré dans leur process de production et de veille concurrentielle, il apparaît depuis plusieurs mois des annonces intitulées « Responsable Web Scraping » ou encore « Ingénieur Web Scraper » sur les sites d'annonces d'emplois spécialisés. De même, nous pouvons noter une large utilisation de cette technique dans le domaine du « data journalism », journalisme 2.0 où journalistes et développeurs collaborent dans l’agrégation de flux de données dans le but de produire des applications pour les lecteurs. Ce fut notamment le cas lors des différentes échéances politiques des trois dernières années. Et vous, quelle est votre utilisation du web scraping ?