Artisan Numérique

/développement/perl/lwp/ Perl, accéder facilement au WEB avec LWP

Perl est très pratique quant il s'agit de manipuler les pages HTML. Il m'a rendu de fiers services dans de nombreux domaine touchant à l'automatisation de connexion à des sites. L'objectif de ce petit tutorial est de montrer pas à pas comment se connecter sur la toile avec Perl et comment en extraire un contenu.

La gestion du protocole HTTP est pris en charge par le module LWP, tout commence donc par :

use LWP;

Fabrication d'un navigateur

On va tout d'abord fabriquer un navigateur. LWP appelle cet objet un UserAgent.

my $browser = new LWP::UserAgent;

Fabrication d'une requête

La fabrication d'une requête de type GET (l'équivalent d'un click sur un lien) procède comme suit :

my $request = new HTTP::Request( GET => "www.monsite.com/chemin/page.html" );

Cette requête peut être affinée pour permettre une meilleur simulation d'un "vrai" navigateur. Pour cela on modifie l'en-tête de la requête et ce qui est plus lié au protocole HTTP qu'à perl.

my $headers = $request->headers();

# Simulation d'un navigateur Konqueror. J'aurais pu mettre 
#  'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
# Pour simuler un IE... 
$headers->header( 'User-Agent','Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko)');

# Ajoute une liste de contenu supporté (types mime)
$headers->header( 'Accept', 'text/html, image/jpeg, image/png, text/*, image/*, */*');

# Authorize le serveur à renvoyer des contenus compressés. Attention, vous devrez les décompresser vous même. A prendre avec précaution.
$headers->header( 'Accept-Encoding','x-gzip, x-deflate, gzip, deflate');

# Type d'encodage caractères accepté
$headers->header( 'Accept-Charset', 'iso-8859-15, utf-8;q=0.5, *;q=0.5');

# Type de langage accepté
$headers->header( 'Accept-Language', 'fr, en');

# Bien pratique, permet de faire croire au serveur que l'on vient du site www.sourceclick.com
$headers->header('Referer', 'www.sourceclick.com');

Lancer la requête et analyser le retour

Une fois construite, la requête se lance simplement comme suit

my $response = $browser->request($request);

Le retour est un objet de type Response. Il contient différent champs dont content contenant le texte de la page. is_success permet quant à lui de savoir si tout c'est bien passé et status_line contient le message d'erreur le cas échéant. Le résultat contient aussi un champs headers contenant différentes informations sur la page envoyée par le serveur.

if ($response->is_success) {
  my $headers = $response->headers();
  print "Encoding : ".$headers->header("Content-Encoding");                
  print "Content:\n".$response->content."\n";
} else {
  print "Erreur:".$response->status_line."\n";  
}

Si vous voulez accéder à un site sécurisé en SSL, vous devez installer le module urpmi perl-Crypt-SSLeay

Authentification

Il y a trois méthodes pour s'authentifier sur le serveur web. Soit on indique les logins/mot de passe à la requête AVANT de la lancer:

$request->authorization_basic("mon_login", "mon_mot_de_passe");

Sinon on peut aussi donner nos droits au navigateur (voir $browser plus haut). C'est un peu plus compliqué car le navigateur peut ainsi contenir une liste de droits (c'est pratique) mais il va savoir quel droit choisir pour un site en fonction du domaine (realm) de celui-ci. Et nom, le domaine n'est pas forcement la partie finale de l'url. C'est spécifique à chaque serveur. Du coup en général, soit on connaît le domaine, soit on doit faire une requête pour rien (et donc essuyer un refus), regarder dans le header de la réponse le champ WWW-Authenticate. Il contient : Basic realm="mon_domaine", c'est le domaine.

Une fois que vous avez le domaine, il suffit de l'injecter dans le navigateur comme suit

$browser->credentials('www.monsite.com:80', 'mon_domaine', 'mon_login', 'mon_mot_de_passe');

Le www.monsite.com:80 correspond à l'url sans le chemin et du port (80 par défaut)

Enfin, si vous utiliser windows comme serveur (une bien drôle d'idée), il est possible que l'authentification utilisé ici ne marche pas (sans blagues ? ;-) ), il faut donc passer le credentials comme suit :

$browser->credentials('www.monsite.com:80', '', 'mon_domaine\\mon_login', 'mon_mot_de_passe');

Accès par proxy

Le paramétrage du proxy est porté par le navigateur ($browser), un peu comme les accréditations.

$browser->proxy (['http'], 'http://monProxy:8080');

Cette ligne indique donc que, concernant les requêtes HTTP, le proxy à utiliser se trouve sur la machine monProxy au port 8080. Il est bien sur possible de rajouter une authentification au proxy lui-même :

$browser->proxy (['http','https'], 'http://monUser:monMotDePasse@monProxy:8080');

Même chose que l'exemple précédent donc, mais pour les deux protocoles HTTP et HTTPS, et cette fois avec une authentification.

Il est enfin possible d'ajouter des domaines d'exception, qui n'utilisent pas le proxy :

$browser->no_proxy(['monDomaineLocal.com', 'monIntranet.com']);

Quelques astuces en vrac

Debuggage

Lorsque tout va mal, un truc pratique pour imposer à LWP de tracer toutes ses transactions. A mettre après le use LWP

use LWP::Debug qw(+);

Ajouter un timeout

Il est possible de limiter le temps d'attente à un serveur. Par exemple ici, 5 secondes :

$browser->timeout(5);

Conclusion

LWP est sans aucun doute une excellente librairie d'accès au web. Elle est relativement intuitive, souple, et pourtant ne laisse sous silence aucun aspect des divers protocoles qu'elle prend en charge. ET ce tutorial n'est qu'un petit aperçu de ce qu'il est possible d'en faire.