Leer y escribir tablas HTML con Pandas

En este artículo, aprenderemos cómo cargar y exportar datos de tablas HTML desde y hacia Pandas DataFrame.

Introducción

Lenguaje de marcado de hipertexto (HTML) es el lenguaje de marcado estándar para crear páginas web. Podemos representar datos tabulares usando el elemento <table> de HTML. La biblioteca de análisis de datos de Pandas proporciona funciones como read_html() y to_html() para que podamos importar y exportar datos a DataFrames.

En este artículo, aprenderemos cómo leer datos tabulares de un archivo HTML y cargarlos en un Pandas DataFrame. También aprenderemos cómo escribir datos desde un Pandas DataFrame y en un archivo HTML.

Nota: En este artículo, leeremos y escribiremos elementos HTML <table>. Este artículo no incluye el análisis de todo el archivo HTML.

Lectura de HTML

Podemos leer tablas de un archivo HTML usando la función read_html(). Esta función lee tablas de archivos HTML como Pandas DataFrames. Puede leer desde un archivo o una URL.

Echemos un vistazo a cada fuente de entrada una por una.

Leer datos HTML de un archivo

Para esta sección, usaremos un conjunto de datos de entrada. Una tabla contiene lenguajes de programación y el año de su creación. La otra tabla tiene tamaños de terrenos y su costo en USD.

Guarde el siguiente contenido HTML en un archivo llamado table_data.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Table Data</title>
</head>

<body>
  <table>
    <thead>
      <tr>
        <th>Programming Language</th>
        <th>Creator</th>
        <th>Year</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>C</td>
        <td>Dennis Ritchie</td>
        <td>1972</td>
      </tr>
      <tr>
        <td>Python</td>
        <td>Guido Van Rossum</td>
        <td>1989</td>
      </tr>
      <tr>
        <td>Ruby</td>
        <td>Yukihiro Matsumoto</td>
        <td>1995</td>
      </tr>
    </tbody>
  </table>
  <table>
    <thead>
      <tr>
        <th>
          Area (sq.ft)
        </th>
        <th>
          Price (USD)
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          12000
        </td>
        <td>
          500
        </td>
      </tr>
      <tr>
        <td>
          32000
        </td>
        <td>
          700
        </td>
      </tr>

    </tbody>
  </table>
</body>

</html>

Pandas necesita ayuda de otra biblioteca, llamada lxml para analizar archivos HTML y XML. Para que la función read_html() funcione, debe instalar lxml:

1
$ pip install lxml

Una vez que lmxl está instalado, podemos usar la función read_html(). Devuelve una lista de DataFrames, donde cada DataFrame es un elemento de tabla completo del archivo HTML dado. Accedemos a cada tabla como un DataFrame indexando la lista.

El siguiente código demuestra el uso de la función read_html() para leer tablas desde un archivo HTML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd

tables = pd.read_html('table_data.html')
print('Tables found:', len(tables))
df1 = tables[0]  # Save first table in variable df1
df2 = tables[1]  # Saving next table in variable df2

print('First Table')
print(df1)
print('Another Table')
print(df2)

Nota: Si bien necesita instalar lxml, no necesita importarlo en su programa para que Pandas funcione.

Ejecutar el código anterior en un intérprete de Python producirá el siguiente resultado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Tables found: 2
First Table
  Programming Language             Creator  Year
0                    C      Dennis Ritchie  1972
1               Python    Guido Van Rossum  1989
2                 Ruby  Yukihiro Matsumoto  1995
Another Table
   Area (sq.ft)  Price (USD)
0         12000          500
1         32000          700

Leer datos HTML desde URL

Así como leemos elementos de tabla de un archivo HTML, también podemos leer elementos de tabla de una página web HTML en un DataFrame con read_html(). Sin embargo, en lugar del nombre del archivo, proporcionaremos una URL como esta:

1
read_html('https://en.wikipedia.org/wiki/Python_(programming_language)')

Y devolverá una lista de DataFrames donde cada DataFrame representa un elemento de tabla de la URL dada.

Aquí hay un código de ejemplo para leer los elementos de la tabla desde la URL de un sitio web usando Pandas:

1
2
3
4
5
6
7
import pandas as pd

tables = pd.read_html('https://en.wikipedia.org/wiki/Python_(programming_language)')
print('Tables found:', len(tables))
df1 = tables[0]  # Save first table in variable df1
print('First Table')
print(df1.head())  # To print first 5 rows

Si ejecutamos con éxito el código anterior, podemos ver el resultado como:

1
2
3
4
5
6
7
8
Tables found: 10
First Table
                0                                                  1
0             NaN                                                NaN
1        Paradigm  Multi-paradigm: functional, imperative, object...
2     Designed by                                   Guido van Rossum
3       Developer                         Python Software Foundation
4  First appeared                              1991; 29 years ago[1]

Leer datos HTML de URL que requieren autenticación

Sabemos que podemos leer los elementos de la tabla de un sitio web. Sin embargo, cuando el sitio requiere autenticación, el código se encuentra con la siguiente excepción:

1
2
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: UNAUTHORIZED

Para leer datos de tales URLs, usaremos el módulo requests. Puedes instalarlo con pip:

1
$ pip install requests

Ahora, usaremos el método get() de la biblioteca requests para realizar una solicitud a la URL de un sitio web mientras proporcionamos el parámetro opcional auth si el sitio requiere autenticación.

Este método devuelve un objeto de respuesta de la página web. Podemos verificar el código de estado (para asegurarnos de que el contenido esté definitivamente allí) y obtener el texto del objeto de respuesta, y luego convertir la tabla en un DataFrame.

Veamos un ejemplo del uso de solicitudes para obtener datos que requieren autenticación. Para este propósito, estamos usando https://httpbin.org:

1
2
3
4
5
6
import requests

r = requests.get('https://httpbin.org/basic-auth/john/johnspassword', auth=('john', 'johnspassword'))

print(r.status_code)
print(r.text)

Al ejecutar el código anterior, podemos ver el siguiente resultado:

1
2
3
4
5
200
{
  "authenticated": true, 
  "user": "john"
}

Esto muestra que accedimos con éxito al contenido de la página web de una URL autenticada. Sin embargo, este sitio web solo contiene datos JSON y necesitamos elementos de tabla HTML como marcos de datos.

Sigamos con la URL anterior y usemos requests para leer tablas HTML como marcos de datos. Si bien el sitio anterior era público, los pasos para acceder al contenido autenticado son los mismos.

Una vez que obtengamos una respuesta, podemos pasar el método r.text a read_html(). Y como de costumbre, obtendremos una lista de tablas que contiene como DataFrames:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd
import requests

# Can use auth parameter for authenticated URLs
r = requests.get('https://en.wikipedia.org/wiki/Python_(programming_language)',
                 auth=('john', 'johnspassword'))
tables = pd.read_html(r.text)
print('Tables found:', len(tables))
df1 = tables[0]
print('First Table')
print(df1.head())

Ejecutar este código generará el siguiente resultado:

1
2
3
4
5
6
7
8
Tables found: 10
First Table
                0                                                  1
0             NaN                                                NaN
1        Paradigm  Multi-paradigm: functional, imperative, object...
2     Designed by                                   Guido van Rossum
3       Developer                         Python Software Foundation
4  First appeared                              1991; 29 years ago[1]

Escribiendo tablas HTML con Python's Pandas

Hemos leído correctamente los datos de las tablas HTML. Escribamos Pandas DataFrame en un archivo HTML. Esto se puede lograr usando el método to_html().

to_html() toma la ruta del archivo al que desea exportar los datos. Si no proporciona una ruta absoluta, guardaría un archivo relativo al directorio actual.

Puede exportar un DataFrame a una tabla HTML como esta:

1
2
3
4
import pandas as pd

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df.to_html('write_html.html')

Este código producirá el siguiente archivo write_html.html en el directorio actual:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>3</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2</td>
      <td>4</td>
    </tr>
  </tbody>
</table>

Tenga en cuenta que la exportación no es un documento HTML completo, sino solo la tabla HTML en sí.

Escritura de tablas HTML con estilo con Python's Pandas

Como podemos ver, por defecto el borde de la tabla es 1, la alineación es correcta y también tiene índices DataFrame en las etiquetas <th>. Podemos cambiar esta estructura predeterminada proporcionando algunos parámetros opcionales.

Ocultar índice

Si no queremos incluir el índice en la salida de la tabla, podemos configurar index=False en to_html():

1
2
3
4
import pandas as pd

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df.to_html('write_html.html', index=False)

Este código produce el archivo write_html.html con el siguiente contenido:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th>A</th>
      <th>B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>3</td>
    </tr>
    <tr>
      <td>2</td>
      <td>4</td>
    </tr>
  </tbody>
</table>
Cambiando el Borde de la Tabla {# Changingtableborder}

El borde de la tabla predeterminado es de 1 píxel. Para cambiar este valor predeterminado, podemos establecer el parámetro borde en un valor en píxeles.

El siguiente código cambia el borde a 3 píxeles:

1
2
3
4
import pandas as pd

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df.to_html('write_html.html', border=3)

El archivo generado ahora establece el atributo de borde de la tabla en "3":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<table border="3" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>3</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2</td>
      <td>4</td>
    </tr>
  </tbody>
</table>
Justificar texto

De forma predeterminada, el texto del encabezado de la tabla está alineado a la derecha. Cambiamos esta alineación con el parámetro justify. Por ejemplo, hacer justify="center" agregará style="text-align: center;" en la etiqueta <tr> de la etiqueta <thead>.

Intentemos alinear el texto del encabezado al centro y ver los resultados:

1
2
3
4
import pandas as pd

df = pd.DataFrame({'A': [1, 'AAA'], 'B': ['BBB', 4]})
df.to_html('write_html.html', justify='center')

La tabla creada por el código anterior se ve así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: center;">
      <th></th>
      <th>A</th>
      <th>B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>BBB</td>
    </tr>
    <tr>
      <th>1</th>
      <td>AAA</td>
      <td>4</td>
    </tr>
  </tbody>
</table>

El texto del encabezado de la mesa ahora está bellamente alineado con el centro.

Conclusión

En este tutorial, hemos aprendido cómo importar y exportar datos de tablas HTML con Pandas DataFrames. Cargamos datos de tablas HTML de archivos, así como de URL de páginas web. En el caso de las URL autenticadas, usamos el módulo de solicitudes para autenticar y recuperar los datos del sitio y luego pasar el texto de respuesta a la función read_html().

También hemos escrito un DataFrame de Pandas como un archivo HTML usando la función to_html(). Luego diseñamos la tabla generada pasando algunos parámetros opcionales como index, border y justify. Esto hace que sea fácil escribir los datos de DataFrame en forma de presentación.