2011-06-12 8 views
28

Me gustaría tomar una tabla HTML y analizarla para obtener una lista de diccionarios. Cada elemento de lista sería un diccionario correspondiente a una fila en la tabla.¿Parse la tabla HTML a la lista de Python?

Si, por ejemplo, tenía una tabla HTML con tres columnas (marcadas con etiquetas de encabezado), "Evento", "Fecha de inicio" y "Fecha de finalización" y esa tabla tenía 5 entradas, me gustaría analizar a través de esa tabla para obtener una lista de longitud 5 donde cada elemento es un diccionario con las teclas "Evento", "Fecha de inicio" y "Fecha de finalización".

¡Gracias por la ayuda!

Respuesta

52

Se debe utilizar una biblioteca de análisis de HTML como lxml:

from lxml import etree 
s = """<table> 
    <tr><th>Event</th><th>Start Date</th><th>End Date</th></tr> 
    <tr><td>a</td><td>b</td><td>c</td></tr> 
    <tr><td>d</td><td>e</td><td>f</td></tr> 
    <tr><td>g</td><td>h</td><td>i</td></tr> 
</table> 
""" 
table = etree.HTML(s).find("body/table") 
rows = iter(table) 
headers = [col.text for col in next(rows)] 
for row in rows: 
    values = [col.text for col in row] 
    print dict(zip(headers, values)) 

impresiones

{'End Date': 'c', 'Start Date': 'b', 'Event': 'a'} 
{'End Date': 'f', 'Start Date': 'e', 'Event': 'd'} 
{'End Date': 'i', 'Start Date': 'h', 'Event': 'g'} 
+0

Mi tabla tiene un número variable de filas. ¿Cómo puedo hacer que funcione si este es el caso? Gracias por la respuesta, por cierto. – Andrew

+0

@Andrew: El código anterior funciona para cualquier cantidad de filas y cualquier cantidad de columnas, siempre que cada fila tenga el mismo número de columnas. –

+0

Sugeriría 'HTMLParser' /' html.parser', pero esta solución es mucho mejor en este caso. – Robin

22

Sven Marnach excellent solution es directamente traducible en ElementTree que forma parte de las distribuciones de Python recientes:

from xml.etree import ElementTree as ET 

s = """<table> 
    <tr><th>Event</th><th>Start Date</th><th>End Date</th></tr> 
    <tr><td>a</td><td>b</td><td>c</td></tr> 
    <tr><td>d</td><td>e</td><td>f</td></tr> 
    <tr><td>g</td><td>h</td><td>i</td></tr> 
</table> 
""" 

table = ET.XML(s) 
rows = iter(table) 
headers = [col.text for col in next(rows)] 
for row in rows: 
    values = [col.text for col in row] 
    print dict(zip(headers, values)) 

mismo resultado que La respuesta de Sven Marnach ...

+1

+1 porque permite usar cElementTree en lugar de ElementTree, que es considerablemente más rápido que lxml si hay una gran cantidad de tablas implicadas – Cerno

+0

Tengo una página web guardada de wikipedia ¿Cómo puedo especificar a ET qué tabla para analizar y recuperar datos? ¿Es posible por nombre de tabla o ID de tabla? – Massimo

14

Si el HTML es no XML que no puede hacerlo con etree. Pero incluso entonces, no tiene que usar una biblioteca externa para analizar una tabla HTML. En python 3 puede alcanzar su objetivo con HTMLParser desde html.parser. Tengo el código de la clase HTMLParser derivada simple here in a github repo.

Puede utilizar esa clase (aquí llamado HTMLTableParser) de la siguiente manera:

import urllib.request 
from html_table_parser import HTMLTableParser 

target = 'http://www.twitter.com' 

# get website content 
req = urllib.request.Request(url=target) 
f = urllib.request.urlopen(req) 
xhtml = f.read().decode('utf-8') 

# instantiate the parser and feed it 
p = HTMLTableParser() 
p.feed(xhtml) 
print(p.tables) 

La salida de este es una lista de 2D-listas que representan tablas. Se ve tal como esto:

[[[' ', ' Anmelden ']], 
[['Land', 'Code', 'Für Kunden von'], 
    ['Vereinigte Staaten', '40404', '(beliebig)'], 
    ['Kanada', '21212', '(beliebig)'], 
    ... 
    ['3424486444', 'Vodafone'], 
    [' Zeige SMS-Kurzwahlen für andere Länder ']]] 
+0

Analizador impresionante !! – Naive

8

Sin duda la forma más fácil de analizar una tabla HTML es utilizar pandas.read_html() - acepta ambas direcciones URL y HTML.

import pandas as pd 
url = r'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies' 
tables = pd.read_html(url) # Returns list of all tables on page 
sp500_table = tables[0] # Select table of interest 

El único inconveniente es que read_html() no preserva los hipervínculos.

+0

¡Impresionante! Gracias. – Raf

+1

Gracias! Esto fue muy rápido y fácil. –