« Retour

Cas d'usage : JSoup et Gatling pour repérer les liens morts

Comment maintenir la qualité d'un blog ?

Les liens morts : un des aléas du web

Quelle satisfaction de voir qu'au bout de plusieurs mois, un article de blog est encore souvent visité et bien référencé. Mais il ne faut pas se reposer sur ses lauriers, car malgré ces bons résultats, il se peut qu'il ne soit plus ce qu'il était.

Il y a un mois, nous avions le nom d'un outil d'accessibilité sur le bout de la langue, nous nous sommes rendus sur le blog Hightest car on en avait parlé précédemment. Et là, on tombe par hasard sur un lien mort. Une question s'impose : combien y en a-t-il en tout sur le blog et quelle solution mettre en place contre ce problème ?

Dénombrer les liens morts en quelques clics

Nous avons d'abord procédé à un état des lieux avec le Link Checker du W3C. C'est un peu fastidieux, l'outil vérifie absolument tous les liens (même les liens vers les fichiers css et js, qui ne nous importent pas dans ce contexte), et on se retrouve sous une marée d'informations. On y a passé un peu plus de temps qu'on l'aurait voulu.

Le verdict ? Sur 162 liens externes, le Link Checker a trouvé 7 liens morts répartis sur 30 articles. En plus de ces 7 liens, beaucoup de faux positifs, en particulier lorsqu'il vérifie la disponibilité de documents PDF en ligne, sans compter les liens d'exemple fournis dans le corps des articles (ex : http://votresuperdepot.git). En effet, notre moteur de blog crée automatiquement des liens sur les chaînes commençant par "http://".

Pas mal de redirections aussi, qui sont moins graves que des liens morts mais qui nécessitent aussi de mettre à jour les liens, ne serait-ce que pour faire gagner un peu de temps de chargement à l'utilisateur.

Les liens morts ont été remplacés ou supprimés dans la foulée.

Trouvailles et avantages collatéraux

En plus du diagnostic des liens morts et redirigés, le check nous a permis de :

  • constater un nouveau bug sur notre blog, corrigé dans la foulée par notre webmaster
  • découvrir un problème sur le forum de Katalon (disparition de commentaires de membres de l'équipe Katalon), signalé dans la foulée aux administrateurs
  • relire certains passages et consolider le souvenir de certains points un peu oubliés au fil des mois.

L'exercice en valait donc la peine.

Automatiser la vérification des liens morts

A quelle fréquence devrions-nous vérifier que les liens sont toujours valides ? Tous les ans, c'est trop peu. Tous les jours, cela prendrait trop de temps... à moins que nous l'automatisions.

Nous avons donc mis en place un petit check automatisé à l'aide de JSoup, Gatling et Jenkins.

Vue d'ensemble de la solution

Voici comment ça se passe :

  • Jenkins lance le test tous les jours à minuit.
  • Juste avant le test, le parseur JSoup récupère tous les liens présents dans les articles du blog et les stocke dans un fichier. Les liens internes sont ignorés, ce qui enlève du bruit par rapport au Link Checker du W3C. Une liste de "faux liens morts" est également ignorée, qui contient les liens type localhost etc.
  • Puis, un test Gatling accède à chacun des documents vers lequels pointent les liens et vérifie les codes de statut de réponse HTTP.
  • Si, parmi tous les liens, il existe au moins un code différent de 200 (qui signifie que la requête s'est effectuée de manière nominale), le test est en erreur. Un mail est envoyé à l'équipe pour analyse.

Le script Gatling

Ce script récupère lit fichier CSV (ici, "urls_in_blog_hightest.csv") pour récupérer l'adresse des liens cités. Il vérifie que chacun des liens pointe vers une ressource disponible.

Le fichier CSV ressemble à cela :

Article Lien
http://www.hightest.nc/blog/posts/urldelarticle1 http://www.unsite.nc
http://www.hightest.nc/blog/posts/urldelarticle1 http://www.unautresite.nc/superarticle
http://www.hightest.nc/blog/posts/urldelarticle2 http://www.encoreunautresite.nc/merveilleuseinfographie

 

Et le script Gatling est le suivant :

package simulations

import io.gatling.core.Predef._
import io.gatling.core.feeder.RecordSeqFeederBuilder
import io.gatling.core.structure.{ChainBuilder, ScenarioBuilder}
import io.gatling.http.Predef.{http, status}
import io.gatling.http.protocol.HttpProtocolBuilder

class CheckForDeadLinks_BlogHightest extends Simulation {

  val successStatus: Int = 200
  val httpProtocol: HttpProtocolBuilder = http
    .check(status.is(successStatus))
  
  val liensBlog: RecordSeqFeederBuilder[String] = csv("src/test/resources/jeux_de_donnees/urls_in_blog_hightest.csv")

  def checkUrlOK(url: String): ChainBuilder = exec(
    http("check_url_" + url)
      .get(url))
  
  val scnVerificationLiensBlog: ScenarioBuilder = scenario("Vérification des liens présents sur le blog Hightest")
    .repeat(liensBlog.records.size) {
      feed(liensBlog)
        .exec(checkUrlOK("${Lien}")) // C'est ici que Gatling utilise la valeur du fichier CSV
    }

  setUp(scnVerificationLiensBlog.inject(constantUsersPerSec(1) during 1).protocols(httpProtocol)).assertions(
    global.successfulRequests.percent.is(100)
  )
}

Récupération des liens et alimentation du fichier CSV

Le fichier CSV montré précédemment est alimenté par JSoup. Pour chacun des liens présents dans le blog, cette méthode est appelée et retourne la liste des liens présents dans la page conformément au format du fichier ("article, lien trouvé") :

private ArrayList<String> recupererLiensArticle(String site, String article){
    ArrayList<String> urlsDansLarticle = new ArrayList<>();
    try {
        Document dom = Jsoup.parse(new URL(article).openStream(), "UTF-8", article);
        Elements liens = dom.getElementsByTag("a");
        for (Element lien : liens) {
            String destinationLien = lien.attr("href");
            if (!urlsDansLarticle.contains(article + "," + destinationLien)
                    && !urlsDansLarticle.contains(article + "," + site + destinationLien)) {
                if(destinationLien.contains("http")){
                    urlsDansLarticle.add(article + "," + destinationLien); // liens absolus
                } else {
                    urlsDansLarticle.add(article + "," + site + destinationLien); // liens relatifs
                }
            }
        }
    } catch (IOException e) {
        System.out.println(article + " : " + e);
    }
    return urlsDansLarticle;
}

Résultat : chacune des destination des liens est stockée, les doublons sur la page sont gérés. Nous conseillons de gérer aussi les doublons globalement, pour éviter de charger plusieurs fois une même ressource citée dans différents articles.

Mission accomplie !

Après un mois de checks quotidiens, nous n'avons pas détecté de nouveaux liens morts, seulement un faux positif, un des sites mentionnés étant temporairement indisponible. Mais nous avons gagné en confiance et savons que nous serons probablement les premiers à être au courant si un de nos liens "meurt".

Et vous, comment testez-vous votre blog ?

Vous aimerez peut-être...

Gérer les paramètres Jenkins quand on est maniaque (ou flemmard)

SonarQube met son grain de sel dans Gitlab !

Un avis ? Un commentaire ?

Cet espace est pour vous.



1 commentaire(s)

  • "Gagner en confiance", le but principal des tests! Merci pour ce retour, les liens morts sont souvent problématiques et je sais qu'il y en a au moins sur une cinquantaine de mes articles avec un lien sur l'ensemble de mes articles depuis la suppression de ce lien par linkedIn. Au delà des liens, il existe aussi des problèmes avec les images, récemment il y en a eu sur LinkedIn et de très nombreuses images (toutes celles avec des transparences) se sont retrouvées altérées ce qui nuit gravement à la qualité des articles :( Je vous félicite pour le temps passer à supprimer ces liens morts et assurer une bonne disponibilité des autres!