Solutions
Nous allons voir ici comment résoudre les différent critères énumérés dans le cahier des charges. Pour les optimisations non-traitées, on essaiera tout de même d'énoncer un minimum de choses les concernant.
Vous pouvez voir le résultat ici
Structure générale du code
Avant même de rentrer dans des déluges d'explications plus techniques nous pouvons au préalable regarder d'un point de vue plus général la structure du code. Nous savons que le script devra lire ligne par ligne toutes les URLs contenues dans un fichier. A partir de là, nous pouvons définir deux manière de procéder pour produire le tableau final en html. Soit nous le construisons ligne par ligne, soit colonne par colonne. Par commodité, nous le ferons ligne par ligne. C'est à dire que pour chaque adresse, le script va mettre son lien, le lien du fichier téléchargé, le lien vers le fichier texte, le contexte et enfin recommencer pour l'adresse suivante. Nous aurions tout à fait pu lire le fichier et faire la premiere colonne avec les liens de toutes ces adresses, puis faire la colonne des pages téléchargées, des fichiers textes et enfin des aperçus. Cela permet de pouvoir insérer des éléments entre chaque colonne, la première méthode le permettra mais entre chaque lignes.
Notons donc l'omniprésence du concept d'itérations. Nous allons répéter la même opération pour chaque adresse, ce qui évidemment, limite la marge de manoeuvre possible.
Le début du code...
Voyons voir de plus près comment fonctionne le script. Il ne sera nullement question d'expliquer en détail toutes les fonction qu'offre Perl, ni même sa syntaxe. Je vous invite à consulter les nombreux tutoriaux sur internet si vous voulez en savoir plus dessus.
#!/usr/bin/perl #indique où se trouve ce qui va interpréter le code qui suit
$i=0;
$j=0;
print "File le nom du fichier url qui se trouve dans le folder LISTES-URL! \n";
$url=<STDIN>;
print "$url";
chomp($url);
open(LECTURE, "../LISTES-URL/$url") or die"impossible de trouver $url!! `\n";
print "File le nom du file SANS EXTENSION pour le tableau en html qui sera saved
dans le folder programmes/ ffs! \n";
$my_tab=<STDIN>;
print "$my_tab";
chomp($my_tab);
open(ECRITURE, ">$my_tab$j.html");
print ECRITURE "<html>\n<head>\n<title>tableau de liens</title>\n</head><body>\n
<table border=\"1\">\n" ;
while($ligne=<LECTURE>)
Ce bout de code va demander à l'utilisateur en premier le nom du fichier où sont stockées les adresses.
open(LECTURE, "../LISTES-URL/$url") or die"impossible de trouver $url!! `\n";
Ici, il va essayer d'ouvrir ce fichier, le cas échéant, le programme s'interrompra et affichera impossible de trouver $url!!
$url est la variable dans laquelle est stockée le nom du fichier bien entendu. Il va demander ensuite le nom du fichier html qu'il devra créer. ATTENTION, il est vital que l'utilisateur ne mette seulement le nom sans l'extension. En effet on comprend pourquoi une telle mesure est nécessaire si on regarde la suite du code.
open(ECRITURE, ">$my_tab$j.html");
Le script va créer ce fichier et l'ouvrir en mode écriture. Son nom est du type "NOM-chiffre- . html". Le chiffre correspond à une variable qu'on incrémentra selon le nombre de pages html. Les vingt premières lignes du tableau seront contenues dans la page "NOM 0.html", puis "NOM 1.html" pour la suivante et ainsi de suite. Le chiffre est placé devant l'extension du fichier, ce qui implique que l'utilisateur devra l'omettre et que le programme le mettra lui-même.
while($ligne=<LECTURE>)
Puis le script va rentrer dans une itération (la commande "while") qui s'arretera lorsqu'il aura lu tout le fichier contenant les adresses.
Nous n'allons pas entrer dans les détails du code, mais nous allons plûtot nous intéresser aux outils qui sont à notre disposition pour accomplir notre tâche avant de voir la suite du script.
L'outil WGET
WGET est un outil sur la console en ligne de commande qui permet de télécharger une page web. Sa syntaxe est simple :
wget www.blabla.com/index.html
De nombreuses options sont implémentées et je vous invite donc à consulter cette page pour de plus amples informations.
Nous allons examiner ici l'option -O, qui va nous permettre de spécifier l'endroit où sera sauvegardé la page téléchargée, ainsi que son nom. La syntaxe deviendra alors:
wget -O PAGES-ASPIREES/toto.html www.blabla.com/index.html
Cette fois-ci, la page www.blabla.com/index.html sera sauvegardée dans le répertoire PAGES-ASPIREES et sera nommé toto.html.
Hélas, WGET ne fonctionnera à 100% qu'avec les pages en html. Sur les sites en php, les redirections et autres formes de différences ne donneront pas forcément les résultats attendus. Il faudrait donc un autre outil qui prendrait en charge ce genre de problèmes.
Le navigateur LYNX
Lynx est un navigateur en ligne de commande. Evidemment, par définition, il semblera basique et pas très intuitif quant à son interface, mais une de ses options va avoir un grand intéret pour nous. L'option -dump va afficher sur la sortie standard (l'écran) le contenu textuel du fichier en question. Et c'est bien ce que l'on recherche. Cependant, nous voulons stocker ce texte dans un fichier à part. Il nous faudra alors utiliser la redirection de flux marquée par l'opérateur ">". La syntaxe ressemblera à quelque chose comme:
lynx -dump ../PAGES-ASPIREES/toto1.html > ../DUMP-TEXT/toto1.txt
Cette ligne de commande va demander à Lynx de rediriger le contenu textuel du fichier toto1.html dans le fichier toto1.txt. Il nous restera plus qu'à mettre le lien pointant sur ce fichier dans notre tableau.
Mais cela n'est pas si simple que cela en perl, car il faut bien un moyen de pouvoir appeler les dites commandes qui ne sont normalement effectives que sous une console (type BASH ou TCSH). Comment faire cela?
Redescendre d'un niveau en perl
Pour redescendre d'un niveau en perl, et utiliser ce que la console nous propose, il existe une fonction très utile nommée system()
. Elle prend en paramètre une chaîne de caractère, qui sera appliquée au program qui a appelé le script, ici notre console sous un système UNIX donc.
A noter que de cette manière, il est possible de faire un script Bash en Perl, et d'utiliser toutes les opérations réalisables à la console. Perl offre la possibilité de redescendre de niveau, ce qui peut-être fort utile, comme dans le cas présent.
Le code ressemblera à:
$wgett="wget -O ../PAGES-ASPIREES/toto$i.html $ligne";
system($wgett);
$lynx="lynx -dump ../PAGES-ASPIREES/toto$i.html > ../DUMP-TEXT/toto$i.txt";
system($lynx);
Cela reste un peu fastidieux à mettre en place, donc on évitera d'utiliser cet outil à toutes les sauces, notamment pour ce qui suit, c'est à dire l'utilisation des expressions régulières.
Aperçu et expressions régulières
La 4eme colonne et étape consiste à chercher le mot barrage et un petit contexte que l'on va afficher dans notre tableau. Perl offre des outils puissants équivalants au grep et au sed, conjugué aux experssions régulières, mais comporte également des spécificités fortes utiles pour ce que nous voulons faire.
if($lignetxt =~ /barrage/i)
{
$avant = $`;
$apres = $';
$barrage = $&;
print ECRITURE "<td><i>...$avant<b>$barrage</b>$apres...</i></td></tr>";
if($lignetxt =~ /barrage/i)
va regarder chaque ligne du fichier text (qui a été lyxné donc) et regarder si cette ligne contient l'occurence du mot placé entre les "/". Ici c'est le mot barrage. L'option "i" placé après signifie que cette recherche s'effectue indépendamment de la casse. Elle reconnaîtra donc Barrage, bArRage, barrage etc...
Si une telle occurence est trouvée, Perl stocke automatiquement ce qui est avant et après sur la ligne dans des variables, ainsi que le mot lui-même, dans une troisème variable. Leur nom est respectivement $`
(avant), $'
(après), $&
(le mot en question ou plûtot ce qui a été trouvé par l'expression régulière). Il suffit ensuite de les stocker, et nous pouvons ainsi formater ces chaînes de caractères comme bon nous semble. Ici, le contexte est en italique (balise <I>), et l'occurence du mot en gras (balise <B>).
optimsations
Nous avons vu les quatres étapes afin de constituer une ligne de tableau. Il ne reste plus qu'à itérer ceci. Mais il est possible d'ajouter quelque modifications pour améliorer l'ensemble et le résultat obtenu.
Portabilité du code
Nous avons défini ce qu'est la portabilité absolue du code dans le cahier des charges. Néanmoins, le script ici ne répond pas à tous les critères nécessaires. Mais cela n'empèche en aucun cas d'examiner les solutions possibles, qu'elles soient implémentées ou non.
Système d'exploitation différent
La première ligne du script va d'hors et déjà limiter le système d'exploitation sur lequel le script fonctionnera.
#!/usr/bin/perl
placé en début de code, précise où se trouve l'interpète du code qui suit. Hélas, ce chemin n'est valable que sous un système UNIX. Sous windows ou sur Mac, l'interprète du langage Perl n'est pas placé au même endroit. Il faut savoir que Perl a le statut de logiciel libre et porté sur la plupart des systèmes d'exploitations mais excelle particulièrement en environnement POSIX
(Linux, MacOS X, Cygwin sous windows). Il est également populaire sous windows (hors cygwin) grace à la distribution active Perl dont la version 5.8 permet l'utilisation d'unicode et surtout d'interface graphique.
Chemins relatifs
L'utilisation de chemins relatifs à travers tout le script ici, permet de transporter le projet et son arborescence à n'importe quelle machine et à n'importe quel endroit de l'arborescence de cette machine. Toutefois, il demeure une condition sine qua non, selon laquelle le script doit être impérativement lancé à partir du répertoire programmes/. Car la notion de repertoire courant est abondamment utilisée, et celui-ci doit être ce répertoire programmes/ .
Lancer le script de n'importe où
Mais il reste possible de pallier à ceci grâce à une variable d'environnement. En effet, lorsque vous appelez un programme, le chemin d'accès à ce programme sera stocké dans la variable d'environnement $.
qui garde le même nom en Perl, comme en Bash. Il suffit ensuite à l'aide d'une expression régulière de récupérer la partie du chemin qui nous intéresse et de l'inclure dans les chemins utilisés dans le script. Sous windows, intuitivement, l'utilisateur se mettra toujours dans le répertoire programmes/ pour lancer le script. Cela est dû aux qualités intrinsèques de navigation graphique de windows. Sous un shell Unix, la touche de tabulation qui complète les noms disponibles permet de lancer le script de n'importe où. En effet, c'est assez agaçant de devoir taper la commande "cd" (change directory) et se placer dans le répertoire programmes/.
Présentation du résultat
Nous savons faire notre tableau, soit. Mais si la liste d'URLs en contient énormément, il serait assez maladroit de présenter un tableau contenant une ou plusieurs centaines de lignes. Les liens en html vont nous permettre de faire plusieurs pages, où chaque page contiendra un tableau d'une vingtaine de lignes, accompagnées d'un lien vers la page précédente et la page suivante.
Cela semble simple formulé de la sorte, mais cela implique quelques complications. Après avoir compléter chaque ligne il nous faudra vérifier si nous sommes à la 20eme ligne ou pas du tableau. Il suffit alors de créer un compteur et lorsque nous arrivons à un multiple de 20, on change de page.
Pour vérifier cette condition, nous allons utiliser l'opérateur "modulo" représenté par le signe %
. Cet opérateur calcule le reste d'une division.
$i % 20
, cette opération va donc calculer le reste entre la valeur de la variable "i", divisée par 20. Si ce reste est égale à 0, nous avons un multiple de 20, et nous pouvons donc changer de page.
Mais il y a deux conditions supplémentaires a vérifier: Si nous sommes à la première page, et si nous sommes à la dernière page. En effet, si nous sommes à la première, il nous faudra un lien uniquement sur la page suivante, et si nous sommes à la dernières, il nous faudra un lien vers la page précédente seulement.
Comment vérifier ces deux conditions ?
Pour savoir si nous sommes à la première page, il suffit de créer un compteur de pages, et de regarder sa valeur. Si celle-ci est à 0 (valeur pour la première page), nous mettrons que le lien vers la page suivante.
Savoir si nous sommes à la dernière page est un peu plus compliqué. En fait nous serons à la dernière page lorsque nous aurons terminé de lire l'intégrale du fichier contenant les URLs. On traduira ceci en perl par :
if(eof(LECTURE))
eof signifie "end of file" ou fin de fichier. Donc si nous sommes à la fin de fichier, nous inscrirons uniquement le lien vers la page précédente.
Gestion d'erreurs diverses
Voyons comment résoudre (ou pas) certaines erreurs qui peuvent survenir
Le fichier URL ne s'ouvre pas
Pour une raison X ou Y, il se peut que le script ne puisse pas ouvrir le fichier contenant la liste d'URLs. Le nom entré par l'utilisateur peut être erroné, ou un autre programme utilise le fichier et empèche qu'un autre programme y accède. En perl, cela prend une moitié de ligne à résoudre.
open(LECTURE, "../LISTES-URL/$url") or die"impossible de trouver $url!! `\n";
Cette instruction va tenter d'ouvrir le fichier $url, et le cas échant (or die) sortira du programme et affichera "impossible de trouver $url!! `\n". Il faudra alors relancer le script.
Wget n'a pas fait son travail
Il se peut que wget ne télécharge pas le fichier listé dans les URLs. Le lien peut être erroné, ou le server qui l'héberge ne peut ne pas fonctionner à ce moment là. Wget ne téléchargera pas la page, Lynx n'aura rien à transformer en texte, et par transitivité, aucun aperçu ne sera afficher.
Lorsqu'on appelle un programme sous UNIX, si celui-ci se déroule bien, il renverra la valeur 0
dans une variable d'environnement. Sinon il renverra 1
.
On peut accéder à cette variable sous perl comme sous bash par son appellation: $?
. Il suffit en suite de vérifier à chaque utilisation de wget le contenu de cette variable. Si elle est à 0, alors wget a bien téléchargé la page en question et le script peut continuer sa tâche. Si elle est à 1, on inscrira dans le tableau à ce niveau (mais aussi au niveau de la colonne des pages lynxées et la colonne des aperçus) quelque chose comme "lien mort" ou "problème".
Impossible de traiter les pages autres qu'en html
Wget ne fonctionne bien qu'avec les pages en html pur. Les pages en php et autres, ainsi que les redirections peuvent aboutir à un contenu qui nous interesse pas. Malheureusement, nous n'avons aucun moyen de régler ceci. La solution réside dans le fait que l'utilisateur ne mettra que des liens de fichier en html dans la liste.
On pourra également intégrer une condition avant de traiter le lien qui stipule que si celui-ci ne se finit pas en .html ou .htm, il ne le traitera pas.
Je vous invite à regarder l'arbre du script afin de mieux saisir ce qu'il fait.