如何使用beautifulsoup处理嵌套的html表?

时间:2019-07-18 13:59:42

标签: python html beautifulsoup

我正在使用BeautifulSoup将HTML文件加载到数据框中。我正在解析的表的每一行都包含一个嵌套表,我不确定如何处理它,因为它给了我一个AssertionError ...试图在数据帧中只有3列时加载4列。 / p>

这是html表的开头,显示标题和数据的第一行:

<table border="0" cellpadding="0" cellspacing="0" width="99%" style="font-family:Helvetica;font-size:12" id="tableid1">
         <colgroup span="3"></colgroup>
         <tr style="background-color: #CCDDFF;" class="header">
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Bundle Name</td>
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Insulation Name / Layer / Layer PN</td>
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Bundle Width</td>
         </tr>
         <tr style="white-space: pre-wrap;background-color: #E4E4E4;">
            <td>BN100175-100861</td>
            <td>
               <table border="0" cellpadding="0" cellspacing="0" style="font-family:Helvetica;font-size:12">
                  <tr>
                     <td>B29* / 10 / POLYETHYLENE_CONDUIT</td>
                  </tr>
               </table>
            </td>
            <td>25.53825</td>
         </tr>

下面是我编写的将数据读入数据帧的代码:

    table = soup.find('table', id = 'tableid1')
    table_rows = table.find_all('tr')

    allData=[]
    for tr in table_rows:
        td = tr.find_all('td')
        row = [i.text for i in td]
        allData.append(row)
     headers = allData.pop(0)
     self.d1_bundle_df = pd.DataFrame(allData, columns = headers)

以上代码运行时,将产生以下错误: AssertionError:传递了3列,传递的数据有4列

处理这些嵌套表的最佳方法是什么? 对我来说,这仍然是相对较新的,因此任何方向都将不胜感激。

1 个答案:

答案 0 :(得分:1)

问题是您要在行中搜索所有<td>,但是在您的情况下,这些<td>可能包含其他<td>。一种解决方案是使用CSS选择器,并仅搜索没有其他<td>的{​​{1}}:

<td>

打印:

data = '''<table border="0" cellpadding="0" cellspacing="0" width="99%" style="font-family:Helvetica;font-size:12" id="tableid1">
         <colgroup span="3"></colgroup>
         <tr style="background-color: #CCDDFF;" class="header">
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Bundle Name</td>
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Insulation Name / Layer / Layer PN</td>
            <td style="vertical-align:top;text-align:left; padding: 0px; font-weight: bold; " width="33%">Bundle Width</td>
         </tr>
         <tr style="white-space: pre-wrap;background-color: #E4E4E4;">
            <td>BN100175-100861</td>
            <td>
               <table border="0" cellpadding="0" cellspacing="0" style="font-family:Helvetica;font-size:12">
                  <tr>
                     <td>B29* / 10 / POLYETHYLENE_CONDUIT</td>
                  </tr>
               </table>
            </td>
            <td>25.53825</td>
         </tr>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'lxml')

rows = []
for tr in soup.select('#tableid1 > tr'):
    rows.append([td.get_text(strip=True) for td in tr.select('td:not(:has(td))')])

from pprint import pprint
pprint(rows)

CSS选择器[['Bundle Name', 'Insulation Name / Layer / Layer PN', 'Bundle Width'], ['BN100175-100861', 'B29* / 10 / POLYETHYLENE_CONDUIT', '25.53825']] 将使用#tableid1 > tr搜索位于标签正下方的所有<tr>

CSS选择器id=tableid1将搜索不包含其他td:not(:has(td))的所有<td>

进一步阅读:

CSS Selectors Reference