Analyse HTML dans Bash – –



Extraction d’images à partir de HTML avec Bash : une approche alternative

Dans le cadre d’un processus nécessitant la copie de toutes les images d’une page web, j’utilisais auparavant xmllint, un outil permettant de traiter des fichiers XML ou HTML et d’afficher les données spécifiées. Cependant, suite à une mise à niveau des systèmes de mon hébergeur, xmllint n’était plus inclus. J’ai donc dû trouver une autre méthode pour extraire la liste des images d’une page HTML. Il s’avère que cela peut être réalisé directement avec Bash.

Bien qu’il ne soit pas intuitif de penser que Bash puisse analyser des fichiers de données, il en est tout à fait capable avec un peu d’ingéniosité. Bash, comme d’autres shells UNIX avant lui, peut parcourir un fichier ligne par ligne grâce à la commande read.

Par défaut, la commande read lit une ligne de données et la divise en champs. Généralement, read utilise les espaces et les tabulations comme séparateurs, avec un retour à la ligne marquant la fin de chaque ligne. Il est toutefois possible de modifier ce comportement en configurant le séparateur de champ interne (IFS) et le délimiteur de fin de ligne (-d).

Pour analyser un fichier HTML à l’aide de read, on peut définir IFS comme le symbole supérieur à (>) et le délimiteur comme le symbole inférieur à (<). Ainsi, à chaque lecture, Bash analyse jusqu’au prochain < (début d’une balise HTML) puis divise les données en utilisant > (fin d’une balise HTML) comme séparateur. L’exemple de code suivant illustre la division des données en variables TAG et VALUE :

local IFS='>'
read -d '<' TAG VALUE

Analysons le fonctionnement de ce code. Considérons ce fragment HTML simple :

<img src="https://www.cloudsavvyit.com/8315/parsing-html-in-bash/logo.png"
alt="Mon logo" />
<p>du texte</p>

Lors de la première analyse, read s’arrête au premier symbole <. Puisque < est le premier caractère de l’entrée, Bash trouve une chaîne vide. Par conséquent, les variables TAG et VALUE sont également vides. Néanmoins, cela convient parfaitement à mon cas d’utilisation.

La fois suivante, Bash lit l’entrée suivante: img src="https://www.cloudsavvyit.com/8315/parsing-html-in-bash/logo.png"↲alt="Mon logo" />↲ avec un retour à la ligne juste avant « alt », et s’arrête avant le symbole < de la ligne suivante. Puis, read divise la ligne en utilisant > comme séparateur, ce qui assigne à TAG la valeur img src="https://www.cloudsavvyit.com/8315/parsing-html-in-bash/logo.png"↲alt="Mon logo" / et à VALUE une nouvelle ligne vide.

Lors de la troisième lecture, read récupère p>du texte. Bash divise cette chaîne au niveau du symbole >, attribuant ainsi p à TAG et du texte à VALUE.

Maintenant que le fonctionnement de read est clair, il est aisé d’analyser un fichier HTML plus conséquent avec Bash. L’approche consiste à créer une fonction Bash nommée xmlgetnext pour gérer l’analyse des données à l’aide de read, étant donné qu’elle sera utilisée à plusieurs reprises dans le script. J’ai choisi le nom xmlgetnext en clin d’œil au programme Linux xmllint, mais j’aurais tout aussi bien pu l’appeler htmlgetnext.

xmlgetnext () {
local IFS='>'
read -d '<' TAG VALUE
}

Voici maintenant le script complet htmltags qui utilise la fonction xmlgetnext pour analyser le fichier HTML :

#!/bin/sh
# Afficher une liste de toutes les balises HTML

xmlgetnext () {
local IFS='>'
read -d '<' TAG VALUE
}

cat $1 | while xmlgetnext ; do echo $TAG ; done

La dernière ligne est essentielle. Elle utilise xmlgetnext pour parcourir et analyser le fichier HTML, affichant uniquement les valeurs de TAG. De plus, grâce au comportement d’echo avec les séparateurs de champs, toutes les lignes telles que img src="https://www.cloudsavvyit.com/8315/parsing-html-in-bash/logo.png"↲alt="Mon logo" / (contenant un retour à la ligne) sont affichées sur une seule ligne : img src="https://www.cloudsavvyit.com/8315/parsing-html-in-bash/logo.png" alt="Mon logo" /.

Analyse de HTML avec Bash

Pour extraire uniquement la liste des images, on peut canaliser la sortie de ce script vers grep afin de n’afficher que les lignes commençant par la balise img.