1

我正在尝试使用 BeautifulSoup 解析类似于以下内容的表格,以提取每个人的姓名、年龄和职位。

<TABLE width="100%" align="center" cellspacing="0" cellpadding="0" border="0">

<TR>
    <TD></TD>
    <TD></TD>
    <TD align="center" nowrap colspan="3"><FONT size="2"><B>Age as of</B></FONT></TD>
    <TD></TD>
    <TD></TD>
</TR>

<TR>
    <TD align="center" nowrap><FONT size="2"><B>Name</B></FONT></TD>
    <TD></TD>
    <TD align="center" nowrap colspan="3"><FONT size="2"><B>November 1, 1999</B></FONT></TD>
    <TD></TD>
    <TD align="center" nowrap><FONT size="2"><B>Position</B></FONT></TD>
</TR>

<TR>
    <TD align="center" nowrap><HR size="1"></TD>
    <TD></TD>
    <TD align="center" nowrap colspan="3"><HR size="1"></TD>
    <TD></TD>
    <TD align="center" nowrap><HR size="1"></TD>
</TR>

<TR>
    <TD align="left" valign="top"><FONT size="2">
    Terry S. Jacobs</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="right" valign="top" nowrap><FONT size="2">57</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="left" valign="top"><FONT size="2">
    Chairman of the Board, Chief Executive Officer, Treasurer and
    director</FONT></TD>
</TR>

<TR><TD><TR><TD><TR><TD><TR><TD>

<TR>
    <TD align="left" valign="top"><FONT size="2">
    William L. Stakelin</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="right" valign="top" nowrap><FONT size="2">56</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="left" valign="top"><FONT size="2">
    President, Chief Operating Officer, Secretary and director</FONT></TD>
</TR>

<TR><TD><TR><TD><TR><TD><TR><TD>

<TR>
    <TD align="left" valign="top"><FONT size="2">
    Joel M. Fairman</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="right" valign="top" nowrap><FONT size="2">70</FONT></TD>
    <TD></TD>
    <TD></TD>
    <TD align="left" valign="top"><FONT size="2">
    Vice Chairman and director</FONT></TD>
</TR>

</TABLE>

我目前的尝试如下:

    soup = BeautifulSoup(in_file)
    out = []
    headers = soup.findAll(['td','th'])
    for header in headers:
        if header.find(text = re.compile(r"^age( )?", re.I)):
            out.append(header)
    table = out[0].find_parent("table")
    rows = table.findAll('tr')
    filter_regex = re.compile(r'[\w][\w .,]*', re.I)
    data = [[td.find(text=filter_regex) for td in tr.findAll("td")] for tr in rows]

对于第一个人来说,事情很有效,但糟糕的<tr><td><tr><td>……台词真的把事情搞砸了。我正在尝试对几千个 HTML 文件执行此操作,每个文件的表结构都略有不同。也就是说,未关闭标签的这一特性<tr><td>文件中似乎很常见。

任何人都对如何概括上述解析以使用具有此类结构的表有想法?非常感谢!

4

2 回答 2

0

您可以利用该属性在您想要保留的所有字段valign中设置为的事实,而您不想保留的字段中没有一个:top

soup = BeautifulSoup(in_file)
cells = [cell.text.strip() for cell in soup('td', valign='top')]

然后您可以将这个单元格列表排序为二维结构。每个条目有三个单元格,因此您可以通过执行以下操作非常简单地对其进行排序:

entries = []
for i in range(0, len(cells), 3):
    entries.append(cells[i:i+3])
于 2012-07-25T02:34:32.450 回答
0

万一其他人遇到这个问题并在这里绊倒,现代解决方案是更改您正在使用的解析器。默认解析器“html.parser”在使用足够接近的 HTML 和正确关闭的标签时非常好,但第二个你必须处理边缘情况(如下面的示例 1,类似于 OP 问题),仍然即使在 8 年后也会消失(下面的示例 2)。

在 BeautifulSoup4(当前版本 4.9.3)的文档中,有一个部分详细说明了解析器的选择:https ://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser

示例 1,原始 HTML:

<TABLE >
  <TR VALIGN="top">
    <td>&nbsp;<td><b>Title:</b>
    <td>&nbsp;title is here <i>-subtitle</i><br>
  <TR VALIGN="top">
    <td>&nbsp;
    <td><b>Date:</b>
    <td>&nbsp;Thursday , August 27th, 2020
  <TR VALIGN="top">
    <td>&nbsp;<td><b>Type:</b>
    <td>&nbsp;61
  <TR VALIGN="top">
    <td>&nbsp;
    <td><b>Status:</b>
    <td>&nbsp;ACTIVE - ACTIVE
</TABLE>

示例 2,使用时的结果BeautifulSoup(html, 'html.parser')

<table>
<tr valign="top">
<td> <td><b>Title:</b>
<td> title is here <i>-subtitle</i><br/>
<tr valign="top">
<td>
    <td><b>Date:</b>
<td> Thursday , August 27th, 2020
  <tr valign="top">
<td> <td><b>Type:</b>
<td> 61
  <tr valign="top">
<td>
    <td><b>Status:</b>
<td> ACTIVE - ACTIVE
</td></td></td></tr></td></td></td></tr></td></td></td></tr></td></td></td></tr></table>

示例 3,使用时的结果BeautifulSoup(html, 'html5lib')

<table>
  <tbody><tr valign="top">
    <td> </td><td><b>Title:</b>
    </td><td> title is here <i>-subtitle</i><br/>
  </td></tr><tr valign="top">
    <td>
    </td><td><b>Date:</b>
    </td><td> Thursday , August 27th, 2020
  </td></tr><tr valign="top">
    <td> </td><td><b>Type:</b>
    </td><td> 61
  </td></tr><tr valign="top">
    <td>
    </td><td><b>Status:</b>
    </td><td> ACTIVE - ACTIVE
</td></tr></tbody></table>

还有一些用 C 语言外部编写的解析器,例如“lxml”,根据文档,您可能会使用它更快。

于 2021-03-13T10:29:55.660 回答