Extraer datos de la tabla HTML

Estoy buscando una manera de obtener cierta información de HTML en el entorno de shell de Linux.

Este es el bit que me interesa:

Tests Failures Success Rate Average Time Min Time Max Time
103 24 76.70% 71 ms 0 ms 829 ms

Y quiero almacenar en variables de shell o hacer eco en estos pares de valores clave extraídos del código HTML anterior. Ejemplo:

 Tests : 103 Failures : 24 Success Rate : 76.70 % and so on.. 

Lo que puedo hacer en este momento es crear un progtwig java que use el analizador sax o el analizador html como jsoup para extraer esta información.

Pero el uso de java aquí parece ser una sobrecarga al incluir el contenedor ejecutable dentro del script “wrapper” que desea ejecutar.

Estoy seguro de que debe haber lenguajes “shell” que puedan hacer lo mismo, es decir, perl, python, bash, etc.

Mi problema es que no tengo experiencia con estos, ¿puede alguien ayudarme a resolver este problema “bastante fácil”?

Actualización rápida:

Olvidé mencionar que tengo más tablas y más filas en el documento .html, perdón por eso (temprano en la mañana).

Actualización # 2:

Intenté instalar Bsoup así porque no tengo acceso de root:

 $ wget http://www.crummy.com/software/BeautifulSoup/bs4/download/4.0/beautifulsoup4-4.1.0.tar.gz $ tar -zxvf beautifulsoup4-4.1.0.tar.gz $ cp -r beautifulsoup4-4.1.0/bs4 . $ vi htmlParse.py # (paste code from ) Tichodromas' answer, just in case this (http://pastebin.com/4Je11Y9q) is what I pasted $ run file (python htmlParse.py) 

error:

 $ python htmlParse.py Traceback (most recent call last): File "htmlParse.py", line 1, in ? from bs4 import BeautifulSoup File "/home/gdd/setup/py/bs4/__init__.py", line 29 from .builder import builder_registry ^ SyntaxError: invalid syntax 

Actualización # 3:

Corriendo la respuesta de Tichodromas obtienes este error:

 Traceback (most recent call last): File "test.py", line 27, in ? headings = [th.get_text() for th in table.find("tr").find_all("th")] TypeError: 'NoneType' object is not callable 

¿algunas ideas?

Una solución de Python que utiliza BeautifulSoup4 ( Edición: con omisión adecuada. Edición3: Uso de class="details" para seleccionar la table ):

 from bs4 import BeautifulSoup html = """ 
Tests Failures Success Rate Average Time Min Time Max Time
103 24 76.70% 71 ms 0 ms 829 ms
""" soup = BeautifulSoup(html) table = soup.find("table", attrs={"class":"details"}) # The first tr contains the field names. headings = [th.get_text() for th in table.find("tr").find_all("th")] datasets = [] for row in table.find_all("tr")[1:]: dataset = zip(headings, (td.get_text() for td in row.find_all("td"))) datasets.append(dataset) print datasets

El resultado se ve así:

 [[(u'Tests', u'103'), (u'Failures', u'24'), (u'Success Rate', u'76.70%'), (u'Average Time', u'71 ms'), (u'Min Time', u'0 ms'), (u'Max Time', u'829 ms')]] 

Edit2: Para producir la salida deseada, use algo como esto:

 for dataset in datasets: for field in dataset: print "{0:<16}: {1}".format(field[0], field[1]) 

Resultado:

 Tests : 103 Failures : 24 Success Rate : 76.70% Average Time : 71 ms Min Time : 0 ms Max Time : 829 ms 

Suponiendo que su código html se almacena en un archivo mycode.html, aquí está una forma bash:

 paste -d: <(grep '' mycode.html | sed -e 's,,,g') <(grep '' mycode.html | sed -e 's,,,g') 

nota: la salida no está perfectamente alineada

Aquí está la respuesta principal, adaptada para la compatibilidad con Python3, y mejorada al eliminar el espacio en blanco en las celdas:

 from bs4 import BeautifulSoup html = """ 
Tests Failures Success Rate Average Time Min Time Max Time
103 24 76.70% 71 ms 0 ms 829 ms
""" soup = BeautifulSoup(s, 'html.parser') table = soup.find("table") # The first tr contains the field names. headings = [th.get_text().strip() for th in table.find("tr").find_all("th")] print(headings) datasets = [] for row in table.find_all("tr")[1:]: dataset = dict(zip(headings, (td.get_text() for td in row.find_all("td")))) datasets.append(dataset) print(datasets)
 undef $/; $text = ; @tabs = $text =~ m!(.*?)!gms; for (@tabs) { @th = m!(.*?)!gms; @td = m!(.*?)!gms; } for $i (0..$#th) { printf "%-16s\t: %s\n", $th[$i], $td[$i]; } __DATA__ 
Tests Failures Success Rate Average Time Min Time Max Time
103 24 76.70% 71 ms 0 ms 829 ms

salida de la siguiente manera:

 Tests : 103 Failures : 24 Success Rate : 76.70% Average Time : 71 ms Min Time : 0 ms Max Time : 829 ms 

Una solución de Python que usa solo la biblioteca estándar (aprovecha el hecho de que el HTML es un XML bien formado). Se puede manejar más de una fila de datos.

(Probado con Python 2.6 y 2.7. La pregunta se actualizó diciendo que el OP usa Python 2.4, por lo que esta respuesta puede no ser muy útil en este caso. ElementTree se agregó en Python 2.5)

 from xml.etree.ElementTree import fromstring HTML = """ 
Tests Failures Success Rate Average Time Min Time Max Time
103 24 76.70% 71 ms 0 ms 829 ms
A B C D E F
""" tree = fromstring(HTML) rows = tree.findall("tr") headrow = rows[0] datarows = rows[1:] for num, h in enumerate(headrow): data = ", ".join([row[num].text for row in datarows]) print "{0:<16}: {1}".format(h.text, data)

Salida:

 Tests : 103, A Failures : 24, B Success Rate : 76.70%, C Average Time : 71 ms, D Min Time : 0 ms, E Max Time : 829 ms, F 

A continuación se muestra una solución basada en expresiones regulares de python que he probado en python 2.7. No depende del módulo xml, por lo que funcionará en caso de que xml no esté completamente bien formado.

 import re # input args: html string # output: tables as a list, column max length def extract_html_tables(html): tables=[] maxlen=0 rex1=r'' rex2=r'' rex3=r'<(td|th).*?/(td|th)>' s = re.search(rex1,html,re.DOTALL) while s: t = s.group() # the table s2 = re.search(rex2,t,re.DOTALL) table = [] while s2: r = s2.group() # the row s3 = re.search(rex3,r,re.DOTALL) row=[] while s3: d = s3.group() # the cell #row.append(strip_tags(d).strip() ) row.append(d.strip() ) r = re.sub(rex3,'',r,1,re.DOTALL) s3 = re.search(rex3,r,re.DOTALL) table.append( row ) if maxlen  Tests Failures Success Rate Average Time Min Time Max Time   103 24 76.70% 71 ms 0 ms 829 ms  """ print extract_html_tables(html)