mots-clefs : programmation, Perl, CGI, Web, HTML, HTTP, LWP, wget, Lynx, client
Collecte automatique/programmée de données et de renseignements sur les sites Web |
À force de développer les interfaces graphiques, linteraction et lergonomie, on en vient à oublier, pire à concevoir plus difficilement, la création dautomates qui feraient le travail à notre place de façon régulière et autonome. Il est ahurissant de constater quotidiennement le temps perdu en travaux répétitifs sur un ordinateur censé pourtant nous faire gagner en productivité.
Ne nous y trompons pas, il nest nullement question ici de programmer des « aspirateurs » de sites tels que wget ou Websnake, ce serait quelque peu réducteur. Ceux-ci sont initialement développés pour rapatrier des hiérarchies entières de documents statiques diffusés par ces sites, principalement en vue dune consultation locale pour des raisons déconomie (limitation des durées de communication) ou pour la gestion de sites miroirs. Si tel est le cas, je vous invite à vous pencher sur lutilitaire wget (fourni en standard sur les CD de la Red Hat 5.X) qui remplit parfaitement cette fonction. À titre anecdotique, je vous livre ci-dessous la commande qui permet de télécharger les images recto des pochettes de CD proposés par la FNAC sur leur site. (Réfléchissez à deux fois avant de lancer cette commande car il y a environ 37 000 fichiers, représentant un peu plus de 600 Mo) :
wget -b -o pochettes_CD.log -t 10 -T 600 -r -L -np http://www.fnac-direct.fr/images/disques/recto
Non, je le répète, le problème un tout petit peu plus complexe puisque lidée est essentiellement de simuler lenvoi dun formulaire, présenté normalement au format HTML à un utilisateur, comme sil avait été rempli et renvoyé manuellement par ce dernier.
Un peu plus complexe, mais pas la mer à boire tout de même.
Les différentes étapes consistent en : accès au
formulaire à laide dun navigateur quelconque, sauvegarde du
source de la page HTML, analyse de son contenu et plus particulièrement
la zone délimitée par les balises <FORM></FORM>
(attention, plusieurs couples de ces balises peuvent coexister au sein de la même
page, ce qui ne présente aucune erreur ni incohérence dun
point de vue logique ou syntaxique), détermination des différentes
variables présentes, de leurs valeurs et caractéristiques
possibles et même de leur ordre dapparition dans le document.
Lordre dapparition des couples « variable=valeur » dans la requête à rédiger ne devrait pas être pris en compte par les scripts CGI mais vous pouvez être certain que bon nombre de prétendus spécialistes du Web ne respectent pas ce principe.
En guise dapplication typique, vous pouvez regarder le source de notre script de conversions de devises quil suffit dinvoquer avec pour seul paramètre le montant de Dollars à convertir en Francs.
En fait, il sagît juste dun appel à Lynx, navigateur Web en mode texte (employé sur les terminaux privés de capacités graphiques et aussi sur les serveurs Videotex qui assurent un relais vers le Web pour de simples Minitels en mode 80 colonnes) de façon non interactive (implicite avec le paramètre -post_data) que lon a encapsulé dans un script Perl et dont la sortie est redirigée sur un descripteur de fichier (LYNX) afin den analyser le contenu pour y trouver une ligne contenant United States Dollars = X,XXX.XX FRF.
Le paramètre facultatif -nolist évite que Lynx conclut sur un récapitulatif de tous les liens trouvés dans le document reçu.
Pour voir le formulaire HTML correspondant, il vous suffit de consulter la page www.xe.net/currency.
Vous pourrez voir dans le source que la méthode denvoi des données est de type POST, si elle avait été de type GET, le paramètre communiqué à Lynx aurait tout simplement été -get_data plutôt que -post_data et naurait impliqué aucune autre modification. Les trois tirets sont propres à Lynx et lui indique la fin des données à soumettre au serveur. Lynx autorisant lécriture des valeurs à envoyer sur plusieurs lignes, la présence de ces tirets lui indique leur limite.
Comme vous le constatez, Lynx savère excellent pour ce genre dopération, toutefois, sil faut le relancer à chaque requête et que, dans la foulée, il faut filtrer le résultat obtenu dans un script, autant gagner du temps et économiser des ressources tout en gagnant la possibilité daméliorer nos requêtes sur des points particuliers que Lynx ne permet pas de personnaliser. Pour cela, il faut et il suffit demployer une bibliothèque de fonctions spécialisées, tâche que remplit à merveille LWP pour Perl.
Mise en garde, LWP repose sur un nombre important dautres bibliothèques, ce qui rend son installation un rien rébarbative. Bibliothèques qui, par ailleurs, servent une grande diversité dapplications, touchant essentiellement aux services Internet (telnet, SMTP, POP, etc.)
Lynx reste pour la suite de nos développements un outil privilégié en raison de sa richesse. En effet, parmi sa multitude doptions, une partie est consacrée à lanalyse du flux de données qui transitent entre le client (le navigateur Web) et le serveur. Ce sont -dump et -source, pour les plus simples, qui affichent le source HTML du document sollicité plutôt que son contenu mis en forme, -trace (éventuellement associée avec -tlog) qui donnent tout le détail des échanges, -mime_header, option très intéressante qui présente tous les entêtes renvoyés par le serveur et qui précèdent le document.
Revenons une seconde sur létape consistant à répertorier les variables contenues dans un formulaire et leurs valeurs possibles (pour les menus et les divers boutons - à cocher, radio ou image -) et éventuellement les contraintes auxquelles elles sont soumises au moins du côté navigateur (option MAXLENGTH ou vérifications/modifications en JavaScript). Comme il peut savérer fastidieux, et même hasardeux, de tout relever manuellement pour ensuite le remettre en forme dans le cadre dune requête Lynx par exemple pour ressembler à :
variable_1=valeur_1&variable_2=valeur_2&etc.
Une astuce toute simple consiste à remplacer dans le document HTML sauvé sur votre disque dur (en local donc) lURL associée à la variable ACTION dans la balise FORM par quelque chose du genre :
http://localhost/cgi-bin/test-cgi
de sorte que, en louvrant dans votre navigateur et en remplissant les différents champs puis en le soumettant enfin, le script test-cgi vous retournera une valeur pour QUERY_STRING (si la méthode est de type GET) correctement formulée que vous pourrez utiliser telle quelle dans vos programmes.
Traitons un cas concret, la recherche des coordonnées dune société localisée quelque part en France.
Facile me direz-vous ! Pour cela il suffit daller sur www.pageszoom.com, www.annuaire.laposte.fr ou bien encore www.annu.com. Hum! Hum! Exact sauf que dans chacun de ces annuaires (et mis à part que le premier est vraiment en dessous de tout tellement il fait limpasse sur des demandes simples - règlement de compte personnel - ), vous êtes obligé de saisir au moins une référence géographique, ville ou département. Quel plaisir de saisir tour à tour 37000 noms de communes ou alors, dans le meilleur des cas, près dune centaine de numéros de départements si lon a aucune idée de la situation géographique de lentité recherchée.
Par contre, il suffit dun petit script pour résoudre notre problème.
Notez que si ce script, pour des besoins didactiques, utilise LWP, il aurait pu tout aussi bien, et probablement plus facilement, faire uniquement appel à Lynx.
Par contre ce dernier se révélera probablement insuffisant si vous voulez développez un utilitaire équivalent pour chercher linformation sur les sites de la Poste ou de France Telecom.
Et dailleurs, je vous invite à plancher sur ce problème car il représente un beau défi (je suis convaincu que cest réalisable).
Lire la documentation :
pour en savoir plus sur ces trois bibliothèques de fonctions et toutes les options quelles offrent. HTTP::Request a notamment lénorme avantage sur Lynx dautoriser la définition dentêtes spécifiques comme par exemple Referer qui est parfois employé par les serveurs pour tenter de contrôler la provenance de la requête.
Typiquement, lexploitation dun tel méta-annuaire passera par un Intranet qui fera office dintermédiaire entre les utilisateurs et les différents annuaires cités plus haut en présentant son propre formulaire qui invoquera un script CGI dérivé de lembryon proposé ici.
Penchons-nous dessus quelques instants.
La première opération consiste à remplacer les espaces par le caractère + dans le nom passé en paramètre.
La création de lobjet $requete stipule que la méthode pour le passage des données au script CGI est de type POST (par opposition à GET) et que lURL du script est 'http://www.annu.com/annu/cgi-bin/www'.
Dans la boucle qui passera en revue les 95 départements, nous donnons nous-mêmes la valeur correcte pour le champ 'Content-length' qui appartient à lentête de la requête envoyée au script CGI. Les différents champs obligatoires dans lentête seront automatiquement renseignés et insérés pour vous par la méthode request si vous ne les avez pas défini explicitement avant son appel.
La variable dinstance content (dans lexpression $reponse->content) contient le résultat délivré par le script CGI via son serveur Web dans sa représentation source. Cest la raison de la présence des deux substitutions dans la procédure traite_reponse, la première sert à faciliter la délimitation de chaque bloc de lignes constituant les coordonnées dune personne ou société trouvée, et la substitution suivante élimine toutes les balises HTML pour ne conserver que les informations brutes. Ensuite, chaque bloc commençant par son numéro dordre, seul sur une ligne, et finissant par une séquence de quatre tirets, eux aussi isolés sur une ligne, lextraction des coordonnées sen trouve simplifiée. Il suffit dy supprimer les lignes vides et de remplacer le é en e (cette dernière opération étant inutile sur les systèmes affichant correctement les caractères codés à la norme ISO 8859-1).
Notez que, au besoin, les librairies LWP et associées contiennent toutes les méthodes requises pour connaître tout le détail des échanges entre client et serveur.
Quatre optimisations possibles consistent, dune part à lancer les requêtes pour tous les départements en parallèle plutôt quen séquence ; dautre part, en présentant les résultats à lutilisateur au fur et à mesure de leur réception. Ensuite proposer une recherche Région Parisienne ou Province. Enfin, une amélioration dordre esthétique consistera à détecter les coordonnées partageant la même adresse pour les regrouper en une seule entité avec la liste des différents services et/ou numéros de téléphones et/ou de télécopieurs.
Attention, le nom à rechercher doit répondre à la syntaxe attendue par un script CGI quant à la représentation des caractères qui, mis à part les lettres, les chiffres et quelques symboles de ponctuation, sont piochés dans la norme ISO 8859-1 (adoptée avec bonheur et discernement par Linux, et accessoirement par pure chance et hasard sur les dernières versions de Winchose) et codés en hexadécimal sous la forme %HH.
À linverse, le seul caractère non ASCII présent dans les réponses délivrées par www.annu.com semble être le é de Télécopie et Numéris que nous remplaçons par un e à laide de s/\351/e/g.
Soyons clairs, bien que très intéressant, un automate de ce genre qui semble de prime abord simple à programmer révèle tout de même plusieurs cas de figure à prendre en considération comme, exemples très communs, le découpage de la réponse en plusieurs pages HTML contenant un bouton suite qui oblige à soumettre une autre requête au serveur plus ou moins différente de celle de base (raison pour laquelle le source présenté ici se cantonne à nafficher au plus que les dix premières coordonnées trouvées dans chaque département), et plus souvent encore labsence de réponse. Autrement dit, il est indispensable de tester manuellement une majorité de cas, de sauver les pages HTML correspondant aux résultats afin de pouvoir les analyser en détail avant de se lancer dans lécriture dun client Web automatique.
Un cas particulier reste celui de laccès à des sites sécurisés avec le protocole SSL. Normalement, nous ne sommes pas censés en parler puisque, dans le cas de Lynx par exemple, les modifications au code développées pour utiliser ce protocole ou même le code exécutable correspondant ne devraient pas être accessibles depuis la France. Et le site officiel de Lynx est assez intransigeant sur ce sujet, qui ne propose un envoi de ceux-ci que par la poste, uniquement sur le territoire américain. Malgré tout, il peut arriver quun quidam, moins à cheval sur les lois ou moins averti, dépose sur un site FTP public tout ou partie du code en question, disponible alors sous la désignation lynx-ssl-2.8-1.i386.rpm (mais bon, je ne vous ai rien dit, hein ?)
Notez que vous ne pourrez installer cette archive quen ayant préalablement récupéré et installé la librairie SSL (archive SSLeay-0.8.1-4.glibc.i386.rpm par exemple mais chut !)
Notez que lon retrouve sur les serveurs très sollicités par le genre dautomates présentés ici des parades similaires à celles apparues avec lessor du Minitel, la plus simple étant de changer la présentation des données communiquées à lutilisateur afin de rendre caduque, au moins temporairement, lanalyse contenue dans le script.
Si vous désirez approfondir ce sujet, sachez quil existe un ouvrage consacré à ce domaine :
« Programmation de clients Web avec Perl » par Clinton Wong chez OREILLY.