<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Artisan Numérique</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/48"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/node/48/atom/feed"/>
  <id>http://artisan.karma-lab.net/node/48/atom/feed</id>
  <updated>2008-02-12T11:04:00+01:00</updated>
  <entry>
    <title>Perl, accéder facilement au WEB avec LWP</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/48" />
    <id>http://artisan.karma-lab.net/node/48</id>
    <published>2007-12-12T14:20:42+01:00</published>
    <updated>2008-02-12T11:04:00+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Perl" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
  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.
</p>    ]]></summary>
    <content type="html"><![CDATA[<p>
  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.
</p><!--break-->

<p>
  La gestion du protocole HTTP est pris en charge par le module LWP, tout commence donc par :
  </p>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw2">use</span> LWP<span class="sy0">;</span>
  </div>
  
  </div>
</p>
  
<H2>Fabrication d'un navigateur</H2>
<p>
  On va tout d'abord fabriquer un navigateur. LWP appelle cet objet un <kbd>UserAgent</kbd>.
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">my</span> <span class="re0">$browser</span> <span class="sy0">=</span> <span class="kw2">new</span> LWP<span class="sy0">::</span><span class="me2">UserAgent</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>


	<a name='chapter_1'></a>
  <h2>Fabrication d'une requête</h2>
	
<p>
  La fabrication d'une requête de type GET (l'équivalent d'un click sur un lien) procède comme suit :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">my</span> <span class="re0">$request</span> <span class="sy0">=</span> <span class="kw2">new</span> HTTP<span class="sy0">::</span><span class="me2">Request</span><span class="br0">&#40;</span> GET <span class="sy0">=&gt;</span> <span class="st0">&quot;www.monsite.com/chemin/page.html&quot;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  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.
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">my</span> <span class="re0">$headers</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">headers</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Simulation d'un navigateur Konqueror. J'aurais pu mettre </span><br />
<span class="co1"># &nbsp;'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'</span><br />
<span class="co1"># Pour simuler un IE... </span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span> <span class="st0">'User-Agent'</span><span class="sy0">,</span><span class="st0">'Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko)'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Ajoute une liste de contenu supporté (types mime)</span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span> <span class="st0">'Accept'</span><span class="sy0">,</span> <span class="st0">'text/html, image/jpeg, image/png, text/*, image/*, */*'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Authorize le serveur à renvoyer des contenus compressés. Attention, vous devrez les décompresser vous même. A prendre avec précaution.</span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span> <span class="st0">'Accept-Encoding'</span><span class="sy0">,</span><span class="st0">'x-gzip, x-deflate, gzip, deflate'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Type d'encodage caractères accepté</span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span> <span class="st0">'Accept-Charset'</span><span class="sy0">,</span> <span class="st0">'iso-8859-15, utf-8;q=0.5, *;q=0.5'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Type de langage accepté</span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span> <span class="st0">'Accept-Language'</span><span class="sy0">,</span> <span class="st0">'fr, en'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1"># Bien pratique, permet de faire croire au serveur que l'on vient du site www.sourceclick.com</span><br />
<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span><span class="st0">'Referer'</span><span class="sy0">,</span> <span class="st0">'www.sourceclick.com'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
  

	<a name='chapter_2'></a>
  <h2>Lancer la requête et analyser le retour</h2>
	
<p>
  Une fois construite, la requête se lance simplement comme suit
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">my</span> <span class="re0">$response</span> <span class="sy0">=</span> <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">request</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>

<p>
  Le retour est un objet de type <KBD>Response</KBD>. Il contient différent champs dont <kbd>content</kbd> contenant le texte de la page. <kbd>is_success</kbd> permet quant à lui de savoir si tout c'est bien passé et <kbd>status_line</kbd> contient le message d'erreur le cas échéant. Le résultat contient aussi un champs <kbd>headers</kbd> contenant différentes informations sur la page envoyée par le serveur.
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">is_success</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">my</span> <span class="re0">$headers</span> <span class="sy0">=</span> <span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">headers</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://perldoc.perl.org/functions/print.html"><span class="kw3">print</span></a> <span class="st0">&quot;Encoding : &quot;</span>.<span class="re0">$headers</span><span class="sy0">-&gt;</span><span class="me1">header</span><span class="br0">&#40;</span><span class="st0">&quot;Content-Encoding&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; <a target="blank" href="http://perldoc.perl.org/functions/print.html"><span class="kw3">print</span></a> <span class="st0">&quot;Content:<span class="es0">\n</span>&quot;</span>.<span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">content</span>.<span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://perldoc.perl.org/functions/print.html"><span class="kw3">print</span></a> <span class="st0">&quot;Erreur:&quot;</span>.<span class="re0">$response</span><span class="sy0">-&gt;</span><span class="me1">status_line</span>.<span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="sy0">;</span> &nbsp;<br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
  
<div class='inline-box note'>
  Si vous voulez accéder à un site sécurisé en SSL, vous devez installer le module <kbd>urpmi perl-Crypt-SSLeay</kbd>
</div>


<H2>Authentification</H2>
<p>
  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:
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">authorization_basic</span><span class="br0">&#40;</span><span class="st0">&quot;mon_login&quot;</span><span class="sy0">,</span> <span class="st0">&quot;mon_mot_de_passe&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>

<p>
  Sinon on peut aussi donner nos droits au navigateur (voir <kbd>$browser</kbd> 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 <kbd>WWW-Authenticate</kbd>. Il contient : <kbd>Basic realm="mon_domaine"</kbd>, c'est le domaine.
</p>
<p>
  Une fois que vous avez le domaine, il suffit de l'injecter dans le navigateur comme suit
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">credentials</span><span class="br0">&#40;</span><span class="st0">'www.monsite.com:80'</span><span class="sy0">,</span> <span class="st0">'mon_domaine'</span><span class="sy0">,</span> <span class="st0">'mon_login'</span><span class="sy0">,</span> <span class="st0">'mon_mot_de_passe'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>  
<div class='inline-box note'>
  Le <kbd>www.monsite.com:80</kbd> correspond à l'url sans le chemin et du port (80 par défaut)
</div>
<p>
  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 ? <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/> ), il faut donc passer le <kbd>credentials</kbd> comme suit :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">credentials</span><span class="br0">&#40;</span><span class="st0">'www.monsite.com:80'</span><span class="sy0">,</span> <span class="st0">'', '</span>mon_domaine\\mon_login<span class="st0">', '</span>mon_mot_de_passe<span class="st0">');<br />
</span
  </div>
  
  </div>
</p>
  

	<a name='chapter_3'></a>
  <h2>Accès par proxy</h2>
	
<p>
  Le paramétrage du proxy est porté par le navigateur ($browser), un peu comme les accréditations. 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">proxy</span> <span class="br0">&#40;</span><span class="br0">&#91;</span><span class="st0">'http'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="st0">'http://monProxy:8080'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  Cette ligne indique donc que, concernant les requêtes HTTP, le proxy à utiliser se trouve sur la machine <kbd>monProxy</kbd> au port <kbd>8080</kbd>. Il est bien sur possible de rajouter une authentification au proxy lui-même :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">proxy</span> <span class="br0">&#40;</span><span class="br0">&#91;</span><span class="st0">'http'</span><span class="sy0">,</span><span class="st0">'https'</span><span class="br0">&#93;</span><span class="sy0">,</span> <span class="st0">'http://monUser:monMotDePasse@monProxy:8080'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  Même chose que l'exemple précédent donc, mais pour les deux protocoles HTTP et HTTPS, et cette fois avec une authentification. 
</p>
<p>
  Il est enfin possible d'ajouter des domaines d'exception, qui n'utilisent pas le proxy :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">no_proxy</span><span class="br0">&#40;</span><span class="br0">&#91;</span><span class="st0">'monDomaineLocal.com'</span><span class="sy0">,</span> <span class="st0">'monIntranet.com'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>



	<a name='chapter_4'></a>
  <h2>Quelques astuces en vrac</h2>
	

	<a name='chapter_5'></a>
  <h2>Debuggage</h2>
	
<p>
  Lorsque tout va mal, un truc pratique pour imposer à LWP de tracer toutes ses transactions. A mettre après le <kbd>use LWP</kbd>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw2">use</span> LWP<span class="sy0">::</span><span class="me2">Debug</span> <a target="blank" href="http://perldoc.perl.org/functions/qw.html"><span class="kw3">qw</span></a><span class="br0">&#40;</span><span class="sy0">+</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>

	<a name='chapter_6'></a>
  <h2>Ajouter un timeout</h2>
	
<p>
  Il est possible de limiter le temps d'attente à un serveur. Par exemple ici, 5 secondes :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">timeout</span><span class="br0">&#40;</span><span class="nu0">5</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>


	<a name='chapter_7'></a>
  <h2>Conclusion</h2>
	
<p>
  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. 
</p>    ]]></content>
  </entry>
</feed>
