Las expresiones regulares son extrañamente complejas.

Al menos siempre lo han sido para mí, que aún recuerdo los sudores fríos que me entraban cuando las estudiaba en clase de Álgebra. Siempre pensé que luego nunca me iba a topar con ellas en el mundo real… ironías del destino 🙂

Una expresión regular es una forma de representar un patrón de texto, una cadena que quieres encontrar dentro de un texto. Por ejemplo si quieres sacar los números que hay en este texto

Nací el 10 de abril del 2017. ¿Cuánto vivire?

puedes usar la expresión regular

\d+

El símbolo «d» representa a un número, junto con el símbolo «+» que viene a decir que ese número puede repetirse una o más veces. Se pone un «\» delante del símbolo «d» para distinguirlo de la letra «d».

El resultado buscar en esa frase con ese patrón usando la función «find_multiple_matches» de PluginTools nos devuelve una lista con dos elementos:

cadena = "Nací el 10 de abril del 2017. ¿Cuánto vivire?"
patron = "\d+"
plugintools.find_multiple_matches(cadena,patron)
->
["10","2017"]


En un add-on de XBMC se utilizan las expresiones regulares como un mecanismo eficiente para buscar en una página HTML los elementos que quieren incluir en la lista de items. Los títulos y portadas de un listado de películas, por ejemplo. Si recuerdas la entrada donde explicaba el funcionamiento básico de un add-on, las expresiones regulares se utilizan fundamentalmente en el momento de «extracción de datos».

Lo que te vas a encontrar en una página HTML es algo como esto:

<h3>Blade Runner</h3><a href="http://www.marsilomena.com/blade-runner">Pulsa aqui
para ver Blade Runner<h3><br/>
<h3>Transformers</h3><a href="http://www.marsilomena.com/transformers">Pulsa aqui
para ver Transformers<h3>
...

Y lo que tú necesitas es meter esa página web en una cadena de texto, y usar expresiones regulares para obtener una lista con los siguientes elementos que luego añadirás a la lista de items de XBMC:

[
["Blade Runner","http://www.marsilomena.com/blade-runner"],
["Transformers","http://www.marsilomena.com/transformers"]
]

Puedes usar otras técnicas para extraer datos, como un parser ElementTree si los datos están en XML, o un parser simplejson si están en JSON. Pero probablemente la mejor solución para procesar el HTML del mundo real pasa por usar expresiones regulares, y como también vale en el resto de casos te conviene tener algunos trucos en la maleta para poder recurrir a ellos cuando te surja la necesidad.

Patrones básicos

Hay muchos símbolos para representar patrones en una expresión regular, como usar «\d» para representar un número o «\s» para representar un espacio en blanco. Para una descripción en profundidad te recomiendo leer la documentación básica de expresiones regulares en Python o hacerte con un buen libro.

Si lo que quieres es usar expresiones regulares en tu add-on sin ser un doctorado en matemáticas, sigue leyendo y verás que los patrones utilizados para extraer datos del HTML suelen ser siempre los mismos. Y además resultan muy sencillos.

Obtener el valor de un tag

Habrás observado que el título de la peli está en el ejemplo entre tags «h3»:

<h3>Blade Runner</h3>...
<h3>Transformers</h3>...

La mejor forma de sacar el título del vídeo en el ejemplo anterior es usar este patrón:

<h3>[^<]+</h3>

Los símbolos «[» y «]» encierran una expresión más compleja que puede utilizarse con el símbolo «+» (que si recuerdas representaba «una o más veces»). Así pues, en este caso el patrón buscado es «<h3>» seguido de uno o más caracteres, para terminar en «</h3>». Como no sabemos cuál es el título del vídeo, utilizamos como carácter cualquiera que no sea el «<«, ya que marcaría el final del tag. Eso se representa poniendo el acento circunflejo «^» delante del caracter.

Así pues «[^<]+» puede leerse como «uno o más caracteres que no sean <«.

Y el patrón completo podemos leerlo como «una cadena empieza por <h3>, y luego tiene cualquier cosa excepto «<» para terminar en </h3>».

Este patrón coincidirá con dos subcadenas en el texto, y las devolverá en un array:

plugintools.find_multiple_matches(cadena,"<h3>[^<]+</h3>")
->
["<h3>Blade Runner</h3>","<h3>Transformers</h3>"]

Como lo que te interesa no es el tag h3 entero, sino que solamente quieres obtener el valor que hay dentro, lo que haces es indicar entre paréntesis qué parte es la que quieres extraer.

<h3>([^<]+)</h3>

Y esta vez el array será sólo con los títulos.

plugintools.find_multiple_matches(cadena,"<h3>([^<])+</h3>")
->
["Blade Runner","Transformers"]

Obtener el valor de un atributo

Verás que el patrón «cualquier caracter que no sea X» es muy útil para procesar el HTML, y vamos a usarlo ahora para extraer el enlace al vídeo. Tomemos el ejemplo anterior:

<h3>Blade Runner</h3><a href="http://www.marsilomena.com/blade-runner">Pulsa aqui
para ver Blade Runner</a><br/>
<h3>Transformers</h3><a href="http://www.marsilomena.com/transformers">Pulsa aqui
para ver Transformers</a>
...

No sólo nos interesa el título del vídeo

<h3>([^<]+)</h3>

sino que también nos interesa el enlace:

<h3>([^<]+)</h3><a href="([^"]+)">Pulsa aqui para ver [^<]+</a>

Así que usamos el patrón que nos dice que el atributo es «cualquier caracter que no sea una comilla». Como hemos incluido el patrón para el título y el patrón para el enlace entre paréntesis, nos devuelve una lista cuyos elementos son a su vez una lista (tupla) con los títulos y los enlaces encontrados.

find_multiple_matches(cadena,patron)
->
[
('Blade Runner', 'http://www.marsilomena.com/blade-runner'),
('Transformers', 'http://www.marsilomena.com/transformers')
]

El truco vale para cualquier expresión, por ejemplo es igualmente aplicable si el atributo estuviera expresado con comillas simples:

<h3">([^<]+)</h3><a href='([^']+)'>Pulsa aqui para ver [^<]+</a>

Observa que en la parte del texto que está dentro del tag «a» no hemos puesto paréntesis, ya que tenemos el título del principio así que no lo necesitamos de nuevo.

Como tratar el espacio en blanco entre tags

En el ejemplo anterior los tags «h3» y «a» están juntos, pero podría ocurrir que estuvieran separados por espacios en blanco o incluso por saltos de línea.

<h3>Blade Runner</h3>
<a href="http://www.marsilomena.com/blade-runner">Pulsa aqui
para ver Blade Runner</a><br/>
<h3>Transformers</h3>
<a href="http://www.marsilomena.com/transformers">Pulsa aqui
para ver Transformers</a>
...

En ese caso modificaríamos el patrón para usar el símbolo de «uno o más espacios en blanco», o «\s+»:

<h3">([^<]+)</h3>\s+<a href="([^"]+)">Pulsa aqui para ver [^<]+</a>

Otra técnica consiste en ignorar cualquier carácter hasta el comienzo siguiente tag, que es más complicado de leer pero tiene la ventaja de cubrir más casos.

<h3">([^<]+)</h3>[^<]+<a href="([^"]+)">Pulsa aqui para ver [^<]+</a>

Y hasta aquí, prácticamente todo lo que necesitas saber para procesar HTML. Si ya sabes extraer valores de los tags, y también de los atributos de los tags, ¿qué más podrías necesitar saber?

Próxima entrada

Esta entrada se estaba haciendo demasiado larga, así que continuaremos mañana con algunas técnicas algo más avanzadas para resolver otros problemas más complejos pero también habituales en el procesamiento de HTML.

Veremos cómo usar expresiones regulares para manejar los tags que están unos dentro de otros, donde el truco de buscar el símbolo «<» no sirve, y también veremos algunas técnicas para que las expresiones regulares no se hagan demasiado complejas usando la extracción en dos pasos.

Un comentario

  1. Muy interesantes tus tutoriales, antes que nada no soy experto programando tengo un nivel basico, mi interes es por modificar los skins, tendras algun tutorial que me puedas proporcionar.

    saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *