Analizando HTML en Bash
Tengo un proceso en el que necesito copiar todas las imágenes de una página web. Solía ejecutar este proceso con xmllint
, que procesará un archivo XML o HTML e imprimirá las entradas que especifique. Pero cuando mi proveedor de host de servidor actualizó sus sistemas, no incluyeron xmllint
. Así que tuve que encontrar otra forma de extraer una lista de imágenes de una página HTML. Resulta que puedes hacer esto en Bash.
Es posible que no crea que Bash puede analizar archivos de datos, pero puede hacerlo con un pensamiento inteligente. Bash, al igual que otros shells de UNIX anteriores, puede analizar las líneas una a la vez desde un archivo a través de la instrucción read
incorporada.
De forma predeterminada, la instrucción read
escanea una línea de datos y la divide en campos. Por lo general, read
divide los campos usando espacios y tabulaciones, con nuevas líneas al final de cada línea, pero puede cambiar este comportamiento configurando el valor del Separador de campo interno (IFS
) y el final- delimitador fuera de línea (-d
).
Para analizar un archivo HTML utilizando read
, establezca el IFS
en un símbolo mayor que (>
) y el delimitador en un símbolo menor que (<
(el comienzo de una etiqueta HTML) y luego divide esos datos en cada >
(el final de una etiqueta HTML ). Este código de muestra toma una línea de entrada y divide los datos en las variables TAG
y VALUE
:
local IFS='>'
read -d '<' TAG VALUE
Exploremos cómo funciona esto. Considere este simple archivo HTML:
<img src="logo.png"
alt="My logo" />
<p>some text</p>
La primera vez que read
analiza este archivo, se detiene en el primer símbolo <
. Dado que <
es el primer carácter de esta entrada de muestra, eso significa que Bash encuentra una cadena vacía. Las cadenas TAG
y VALUE
resultantes también están vacías. Pero eso está bien para mi caso de uso.
La próxima vez que Bash lea la entrada, obtiene img src=\logo.png\↲alt=\My logo\ />↲
con una nueva línea justo antes de alt, y se detiene antes el símbolo <
en la siguiente línea. Luego, read
divide la línea en el símbolo >
, lo que deja TAG
con img src=\logo.png\↲alt =\Mi logo\ //
y VALUE
con una nueva línea vacía.
La tercera vez que read
analiza el archivo HTML, obtiene p>algo de texto
. Bash divide la cadena en >
dando como resultado TAG
que contiene p
y VALUE
con algo de texto
.
Ahora que comprende cómo usar read
, es fácil analizar un archivo HTML más largo con Bash. Comience con una función de Bash llamada xmlgetnext
para analizar los datos usando read
, ya que hará esto una y otra vez en el script. Llamé a mi función xmlgetnext
para recordarme que este es un reemplazo para el programa xmllint
de Linux, pero podría haberlo llamado fácilmente htmlgetnext
.
xmlgetnext () {
local IFS='>'
read -d '<' TAG VALUE
}
Ahora llame a esa función xmlgetnext
para analizar el archivo HTML. Este es mi script completo htmltags
:
#!/bin/sh
# print a list of all html tags
xmlgetnext () {
local IFS='>'
read -d '<' TAG VALUE
}
cat $1 | while xmlgetnext ; do echo $TAG ; done
La última línea es la clave. Recorre el archivo usando xmlgetnext
para analizar el HTML e imprime solo las entradas de TAG
. Y debido a cómo funciona echo
con los separadores de campo estándar, cualquier línea como img src=\logo.png\↲alt=\My logo\
que contienen una nueva línea se imprimen en una sola línea, como img src=\logo.png\ alt=\Mi logo\ //
.
Para obtener solo la lista de imágenes, ejecuto la salida de este script a través de grep
para imprimir solo las líneas que tienen una etiqueta img
al comienzo de la línea.