Estoy intentando extraer filas de una tabla html y anexarlas a un DataFrame o directamente en una hoja de cálculo de Excel.

Quiero mantener la estructura original de la tabla porque asigna el diseño físico de un sistema de matriz. Por ejemplo, los datos que estoy intentando extraer siguen este formulario.

<div id="FA_DSC"><p>Table_Title</p><table border="1" cellpadding="4"style="border: 1px solid #000000; border-collapse: collapse;">
<tr>
<td> </td>
<td> </td>
<td>X68</td>
<td>X20</td>
<td>X17</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>X80</td>
<td>X84</td>
<td>V28</td>
<td>X02</td>
<td>X12</td>
<td> </td>
</tr>
<tr>
<td>X22</td>
<td>X55</td>
<td>V57</td>
<td>U15</td>
<td>V29</td>
<td>X51</td>
<td>X40</td>
</tr>
</table></div>

Me gustaría tomar una < tr > e insertarla en una hoja de Excel / marco de datos para que pueda seguir este formato,

            Table_Title             
            X68 X20 X17     
        X80 X84 V28 X02 X12 
    X22 X55 V57 U15 V29 X51 X40

Usando BeautifulSoup pude encontrar todas las tablas que quiero extraer usando el siguiente

with open(r'D:\yolo\frolo\dolo.html','r') as f:
    contents = f.read()
    soup = BeautifulSoup(contents.encode("UTF8"),'lxml')
    table = soup.find_all('div',{'id':'table'})

Desde aquí, he intentado extraer todo lo que hay entre < tr > pero no soy consciente de una manera de hacerlo manteniendo la integridad de las filas.

Por ejemplo, he intentado

for i in table:
    for k in i:
        text = i.get_text().split('\n')
        print(text)

pero devolverá iteraciones como esta.

['Table_Title']
['', '', ' ', ' ', 'X68', 'X20', 'X17', ' ', ' ', 
'', '', ' ', 'X80', 'X84', 'V28', 'X02', 'X12', ' ', 
'', '', 'X22', 'X55', 'V57', 'U15', 'V29', 'X51', 'X40',
'', '', 'X14', 'W05', 'T34', 'U36', 'T38', 'S75', 'X24', 
'', '', 'X83', 'X57', 'U48', 'V10', 'T82', 'X04', 'X11',
'', '', ' ', 'X82', 'X59', 'T39', 'X03', 'X18', ' ', '',
'', ' ', ' ', 'X78', 'X15', 'X41', ' ', ' ', '', '']

También lo he intentado,

table.find_all('td')

Que regresa,

AttributeError: ResultSet object has no attribute 'find_all'. 
You're probably treating a list of items like a single item. 
Did you call find_all() when you meant to call find()?

Lo más cerca que he llegado es obtener los datos en una lista usando

k.contents

Cuando intento hacernos expresiones regulares

print(re.findall("<tr>(.*?)</tr>", "".join(k.contents)))

Entiendo esto,

TypeError: sequence item 1: expected str instance, Tag found

En resumen, este es mi código inicial y esperaba obtener alguna orientación sobre cómo mudarse desde aquí.

with open(r'D:\yolo\frolo\dolo.html','r') as f:
    contents = f.read()
    soup = BeautifulSoup(contents.encode("UTF8"),'lxml')
    table = soup.find_all('div',{'id':'table'})

Soy nuevo en BeautifulSoup y html y esperaba que alguien pudiera ayudar a extraer estas filas. ¿BeautifulSoup tiene una característica que puedo usar para extraer la tabla fila por fila?

Espero comunicar esto claramente y me disculpo por el largo post. sólo tratando de equipar a todos con suficiente información para ayudarme a resolver el problema.

0
StupidPanda 7 nov. 2019 a las 23:35

2 respuestas

Esto almacenará los datos de cada tabla en su propia lista y almacenará los datos de cada fila debajo de esa tabla en su propia lista:

from bs4 import BeautifulSoup
html = """
<div id="FA_DSC"><p>Table_Title</p><table border="1" cellpadding="4"style="border: 1px solid #000000; border-collapse: collapse;">
<tr>
<td> </td>
<td> </td>
<td>X68</td>
<td>X20</td>
<td>X17</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>X80</td>
<td>X84</td>
<td>V28</td>
<td>X02</td>
<td>X12</td>
<td> </td>
</tr>
<tr>
<td>X22</td>
<td>X55</td>
<td>V57</td>
<td>U15</td>
<td>V29</td>
<td>X51</td>
<td>X40</td>
</tr>
</table></div>
"""

soup = BeautifulSoup(html, 'lxml')

data = []
for table in soup.select('table'):
    table_data = []
    data.append(table_data)
    for tr in table.select('tr'):
        row_data = []
        table_data.append(row_data)
        for td in tr.select('td'):
            row_data.append(td.get_text())

print(data)

Salida

[[[' ', ' ', 'X68', 'X20', 'X17', ' ', ' '], [' ', 'X80', 'X84', 'V28', 'X02', 'X12', ' '], ['X22', 'X55', 'V57', 'U15', 'V29', 'X51', 'X40']]]
0
facelessuser 7 nov. 2019 a las 21:00

Puede usar pandas.read_html

import pandas as pd

html="""<div id="FA_DSC"><p>Table_Title</p><table border="1" cellpadding="4"style="border: 1px solid #000000; border-collapse: collapse;">
<tr>
<td> </td>
<td> </td>
<td>X68</td>
<td>X20</td>
<td>X17</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>X80</td>
<td>X84</td>
<td>V28</td>
<td>X02</td>
<td>X12</td>
<td> </td>
</tr>
<tr>
<td>X22</td>
<td>X55</td>
<td>V57</td>
<td>U15</td>
<td>V29</td>
<td>X51</td>
<td>X40</td>
</tr>
</table></div>"""
pd.read_html(html)

Fuera:

     0    1    2    3    4    5    6
0  NaN  NaN  X68  X20  X17  NaN  NaN
1  NaN  X80  X84  V28  X02  X12  NaN
2  X22  X55  V57  U15  V29  X51  X40
0
Ricky Kim 7 nov. 2019 a las 21:27