|
Vérifier les liens et les ancres d'un site Internet |
Niveau : initié
Compatibilité : Java 1.1 + Swing 1.1 ou Java 2Contexte
L'astuce précédente vous a présenté la classe HTMLDocumentLinks qui permet de récupérer la liste des liens et des ancres d'un fichier HTML.
Dans la suite de cette astuce, voici le programme BadLinksRecorder vérifiant si tous les liens et les ancres utilisées dans l'ensemble des fichiers HTML d'un site Internet sont valides. Ce programme vous donne en sortie la liste de tous les liens et toutes les ancres qui sont incorrectes, afin que vous puissiez les corriger.
Voici la liste des types de liens dont ce programme vérifie la validité :
- Lien hyper texte déclaré avec les balises <A HREF=...> ou <AREA HREF=...>.
- Lien vers une image déclaré avec les balises <IMG SRC=...>, <BODY BACKGROUND=...>, <TABLE BACKGROUND=...>, <TR BACKGROUND=...> ou <TD BACKGROUND=...>.
- Lien vers une applet déclaré avec la balise <APPLET CODE=...> et les attributs éventuels ARCHIVE et CODEBASE.
- Lien vers une frame déclarée avec la balise <FRAME SRC=...>.
Rappel : si vous utilisez Java 1.1, vous devez té7lécharger Swing 1.1 à l'adresse (Swing 1.1 est inclus dans Java 2) :
http://java.sun.com/products/jfc/download.html.Programme BadLinksRecorder
La classe BadLinksRecorder qui suit, permet de lire et de gérer l'ensemble des fichiers d'un site Internet (fichiers HTML, images, classes Java). Son constructeur prend en paramètre l'URL d'un fichier HTML qui est utilisée par la classe comme point de départ pour retrouver tous les fichiers dépendant directement ou indirectement de cette URL.
Tous les liens vers des fichiers qui ne sont pas relatifs à l'URL de départ sont ignorés, mais en modifiant la méthode ignoreURL () de la classe HTMLDocumentLinks, vous pouvez changer cette contrainte.
Tous les fichiers sont manipulés sous forme d'URL ce qui permet d'accéder aussi bien à des fichiers sur un disque local avec le protocole file: ou sur des fichiers accessibles sur Internet par le protocole http:.La méthode principale de cette classe est parseFiles (). Bien que longue, elle effectue un ensemble d'opérations assez simples, dont voici la description :
- Elle parcourt dans une boucle l'ensemble des fichiers HTML mémorisés dans le vecteur parsedHtmlFiles. Ce vecteur ne contient au départ que l'URL passée au constructeur. A chaque tour de boucle, on essaye d'ouvrir un fichier HTML : Si l'ouverture échoue, l'URL du fichier est ajoutée au vecteur badFiles ; si elle réussit, une nouvelle instance de la classe HTMLBadLinks (qui dérive de HTMLDocumentLinks) est créée et l'ensemble des liens et des ancres de ce fichier est lu grâce à la méthode read ().
Parmi ces liens, tous ceux qui désignent des fichiers HTML et qui ne sont pas déjà dans le vecteur parsedHtmlFiles, sont ajoutés à la fin de parsedHtmlFiles, pour être lus plus tard. Ainsi tous les fichiers qui dépendent directement ou indirectement de l'URL de départ seront parcourus dans cette boucle.- Toutes les URLs des fichiers HTML inaccessibles sont enlevés du vecteur parsedHtmlFiles.
- Chaque fichier non HTML (images, classes Java) du vecteur otherCheckedFiles est ouvert pour vérifier s'il existe ou non. S'il est inaccessible, son URL est retirée de otherCheckedFiles pour être ajoutée au vecteur badFiles.
Arrivé à ce point, cette méthode a mémorisé les trois ensembles d'URLs suivants :
- L'ensemble parsedHtmlFiles des fichiers HTML existants. La table de hash htmlFiles mémorise le même ensemble en associant à chacune de ces URLs, une instance de la classe HTMLBadLinks. La classe HTMLBadLinks mémorise tous les liens et toutes les ancres d'un fichier HTML.
- L'ensemble otherCheckedFiles des autres types de fichiers existants.
- L'ensemble badFiles de tous les fichiers inaccessibles et référencés par les fichiers HTML.
- Pour vérifier la cohérence des liens et des ancres de tous les fichiers HTML, il suffit alors de parcourir l'ensemble htmlFiles, en vérifiant que tous les liens de chacun des fichiers HTML sont corrects ou non.
- Pour manipuler plus facilement l'ensemble parsedHtmlFiles, un tri bulle est effectué sur cet ensemble pour qu'il soit classé par ordre alphabétique.
- Finalement, la méthode parseFiles () renvoie true ou false pour indiquer que tous les liens ou les ancres sont corrects ou non.
La méthode main () de la classe BadLinksRecorder prend en paramètre une URL. Cette URL est utilisée comme point de départ pour vérifier l'ensemble d'un site Internet et doit contenir des liens vers les autres fichiers du site. Typiquement, cette URL est le fichier d'index du site.
Après avoir créé une instance de BadLinksRecorder, et appelé la methode parseFiles (), la méthode main () imprime sur la sortie standard la liste de tous les liens et toutes les ancres qui sont incorrectes, suivie de la liste des fichiers HTML vérifiés.
/* * BadLinksRecorder.java 1.0 * * Copyright (c) 1999 Emmanuel PUYBARET - eTeks. * All Rights Reserved. * */ import java.net.*; import java.io.*; import java.util.*; import java.text.*; import javax.swing.text.*; import javax.swing.text.html.*; public class BadLinksRecorder { private URL searchedURL; // URL de départ private Vector parsedHtmlFiles; // Ensemble des fichiers HTML lus private Vector otherCheckedFiles; // Ensemble des autre types de fichiers private Vector badFiles; // Ensemble des fichiers incorrects private Hashtable htmlFiles; // Hashtable ayant pour clé une URL et // pour valeur les documents HTML lus private int badURLsCount; // Nombre de mauvaises URLs private int badAnchorsCount; // Nombre d'ancres non définies public BadLinksRecorder (String searchedURL) throws IOException { this.searchedURL = new URL (searchedURL); // Tentative d'ouverture pour vérifier la validité de l'URL // Déclenchement d'une exception en cas de problème InputStream inputStream = getInputStream (this.searchedURL); inputStream.close (); } private InputStream getInputStream (URL url) throws IOException { // Tentative d'ouverture du fichier URLConnection connection = url.openConnection (); // Si le fichier est accédé via le protocole http // vérification si un code 4xx n'a pas été renvoyé if ( connection instanceof HttpURLConnection && ((HttpURLConnection)connection).getResponseCode () / 100 == 4) throw new IOException (); return connection.getInputStream (); } // Méthode d'interrogation des résultats du parsing public Vector getHTMLFiles () { return parsedHtmlFiles; } public Vector getMalformedURLs (URL file) { return ((HTMLBadLinks)htmlFiles.get (file)).getMalformedURLs (); } public Vector getBadURLs (URL file) { return ((HTMLBadLinks)htmlFiles.get (file)).badURLs; } public Vector getBadAnchors (URL file) { return ((HTMLBadLinks)htmlFiles.get (file)).badAnchors; } public int getBadURLsCount () { return badURLsCount; } public int getBadAnchorsCount () { return badAnchorsCount; } // Parcours du fichier HTML donné au constructeur et de tous les fichiers // qui lui sont liés. public boolean parseFiles () { parsedHtmlFiles = new Vector (); // Ensemble des fichiers HTML rencontrés otherCheckedFiles = new Vector (); // Ensemble des autre types de fichiers htmlFiles = new Hashtable (); badFiles = new Vector (); parsedHtmlFiles.addElement (searchedURL); // Parcours de toutes les urls qui sont ajoutées à parsedHtmlFiles HTMLEditorKit html = new HTMLEditorKit (); for (int i = 0; i < parsedHtmlFiles.size (); i++) { URL searchURL = (URL)parsedHtmlFiles.elementAt (i); Reader urlReader = null; try { InputStream inputStream = getInputStream (searchURL); urlReader = new BufferedReader ( new InputStreamReader (inputStream)); } catch (IOException e) { // En cas d'échec, ajout à l'ensemble des mauvais fichiers badFiles.addElement (searchURL); continue; } try { System.out.println ("Lecture de " + searchURL + "..."); // Création d'un document HTML ajouté à l'ensemble htmlFiles HTMLBadLinks doc = new HTMLBadLinks (searchURL, parsedHtmlFiles, otherCheckedFiles); htmlFiles.put (searchURL, doc); // Démarrage de la lecture et du parsing du fichier HTML html.read (urlReader, doc, 0); urlReader.close (); for (Enumeration e = doc.getURLs ().elements (); e.hasMoreElements (); ) try { URL url = (URL)e.nextElement (); // Construction de l'URL sans ancre URL urlWithNoAnchor = new URL (url.getProtocol (), url.getHost (), url.getPort (), url.getFile ()); String lowerCaseFile = url.getFile ().toLowerCase (); if ( lowerCaseFile.endsWith (".htm") || lowerCaseFile.endsWith (".html")) { // Si le fichier est un fichier HTML, ajout à l'ensemble // des fichiers HTML (vérification de l'extension en minuscules) if (!parsedHtmlFiles.contains (urlWithNoAnchor)) parsedHtmlFiles.addElement (urlWithNoAnchor); } else // Pour les autres types de fichier (GIF, JPG,...), ajout // à l'ensemble des autres fichiers if (!otherCheckedFiles.contains (url)) otherCheckedFiles.addElement (url); } catch (MalformedURLException exception) { } // Ne peut arriver } catch (IOException e) { System.out.println ("Probleme de lecture de " + searchURL); } catch (BadLocationException e) { } } // Suppression des mauvais fichiers de parsedHtmlFiles for (int i = 0; i < parsedHtmlFiles.size (); ) if (badFiles.contains (parsedHtmlFiles.elementAt (i))) parsedHtmlFiles.removeElementAt (i); else i++; // Suppression des mauvais fichiers de otherCheckedFiles for (int i = 0; i < otherCheckedFiles.size (); ) { URL otherFile = (URL)otherCheckedFiles.elementAt (i); try { // Tentative d'ouverture du fichier InputStream inputStream = getInputStream (otherFile); inputStream.close (); i++; } catch (IOException e) { badFiles.addElement (otherFile); otherCheckedFiles.removeElementAt (i); } } badURLsCount = 0; badAnchorsCount = 0; // Recherche des URLs et ancres mauvaises dans tous les fichiers lus for (Enumeration e = htmlFiles.elements (); e.hasMoreElements (); ) { HTMLBadLinks parsedDocument = (HTMLBadLinks)e.nextElement (); badURLsCount += parsedDocument.getMalformedURLs ().size (); // Parcours de toutes les URLs du fichier for (Enumeration eURL = parsedDocument.getURLs ().elements (); eURL.hasMoreElements (); ) try { URL url = (URL)eURL.nextElement (); // Construction de l'URL sans ancre URL urlWithNoAnchor = new URL (url.getProtocol (), url.getHost (), url.getPort (), url.getFile ()); // Vérification si l'URL sans ancre est dans les mauvais fichiers if (badFiles.contains (urlWithNoAnchor)) { parsedDocument.badURLs.addElement (urlWithNoAnchor); badURLsCount++; } else if ( !otherCheckedFiles.contains (url) && url.getRef () != null) { HTMLBadLinks htmlDocument = (HTMLBadLinks)htmlFiles.get (urlWithNoAnchor); // Recherche de l'existence de l'ancre dans le fichier indiqué if (!htmlDocument.getAnchors ().contains (url.getRef ())) { parsedDocument.badAnchors.addElement (url); badAnchorsCount++; } } } catch (MalformedURLException ex) { } // Ne peut arriver } // Tri bulle simple sur le vecteur parsedHtmlFiles // pour une sortie des fichiers par ordre alphabétique boolean sorted; do { sorted = true; for (int i = 0; i < parsedHtmlFiles.size () - 1; i++) { URL url1 = (URL)parsedHtmlFiles.elementAt (i); URL url2 = (URL)parsedHtmlFiles.elementAt (i + 1); if (url1.toString ().compareTo (url2.toString ()) > 0) { parsedHtmlFiles.setElementAt (url2, i); parsedHtmlFiles.setElementAt (url1, i + 1); sorted = false; } } } while (!sorted); // Renvoie true si pas d'erreur rencontrée return badURLsCount == 0 && badAnchorsCount == 0; } // Classe dérivée de HTMLDocumentLinks qui mémorise en plus les URLs // et les ancres mauvaises private class HTMLBadLinks extends HTMLDocumentLinks { Vector badAnchors = new Vector (); Vector badURLs = new Vector (); public HTMLBadLinks (URL file, Vector htmlFiles, Vector otherFiles) { super (file); } } // Méthode main () d'exemple de mise en oeuvre // (prend en argument un nom de fichier HTML de départ // sous forme d'URL, par exemple file:/disk/dir1/index.html) public static void main (String args []) { try { BadLinksRecorder recorder = new BadLinksRecorder (args [0]); if (recorder.parseFiles ()) System.out.println ("\nToutes les URL et ancres sont correctes."); else { // Pour chacun des fichiers HTML lus, listing des erreurs for (Enumeration e = recorder.getHTMLFiles ().elements (); e.hasMoreElements (); ) { URL htmlFile = (URL)e.nextElement (); for (Enumeration e2 = recorder.getMalformedURLs (htmlFile).elements (); e2.hasMoreElements (); ) System.out.println ( "Dans le fichier " + htmlFile + " l'URL " + e2.nextElement () + " est incorrecte."); for (Enumeration e2 = recorder.getBadURLs (htmlFile).elements (); e2.hasMoreElements (); ) System.out.println ( "Dans le fichier " + htmlFile + " l'URL " + e2.nextElement () + " n'existe pas."); for (Enumeration e2 = recorder.getBadAnchors (htmlFile).elements (); e2.hasMoreElements (); ) { URL url = (URL)e2.nextElement (); System.out.println ( "Dans le fichier " + htmlFile + " l'ancre" + url.getRef () + " de l'URL " + url + " est inconnue."); } } System.out.println ( "" + recorder.getBadURLsCount () + " URL et " + recorder.getBadAnchorsCount () + " ancres sont incorrectes.\n"); } // Liste de tous les fichiers HTML lus System.out.println ("\nListe des " + recorder.getHTMLFiles ().size () + " fichiers verifies :\n"); for (Enumeration e = recorder.getHTMLFiles ().elements (); e.hasMoreElements (); ) System.out.println (e.nextElement ()); } catch (IOException e) { System.out.println ("Probleme d'acces a l'URL : " + args [0]); } } }Compilation
Pour utiliser le programme précédent, recopiez les programmes BadLinksRecorder.java et HTMLDocumentLinks.java, puis compilez-les d'une des manières suivantes :
- Si vous utilisez Java 1.1 sous Windows et si vous avez installé Swing dans le répertoire c:\jdk\Swing-1.1, vous utiliserez la ligne de commande suivante :
javac -classpath c:\jdk\Swing-1.1\swing.jar;c:\jdk\lib\classes.zip BadLinksRecorder.java HTMLDocumentLinks.java
- Si vous utilisez Java 2 dans lequel Swing est inclus, vous utiliserez la ligne de commande suivante :
javac BadLinksRecorder.java HTMLDocumentLinks.javaExécution
L'exemple de ce programme prend en paramètre l'URL du fichier HTML de base d'un site Internet (situé localement ou sur un serveur HTTP).
Si vous utilisez Java 2, vous pouvez exécuter le programme avec par exemple, la ligne de commande suivante :
java BadLinksRecorder http://www.unsite.com/index.htmlAttention ! Tous les fichiers dont l'URL est relative à l'URL de départ seront lus qu'ils dépendent directement ou indirectement (via d'autres fichiers) du fichier HTML de base. Ceci peut représenté pour les gros sites une très grande quantité d'information longue à lire et à traiter...
|