【问题标题】:Using Beautiful Soup for HTML tables that lack </td> tags对缺少 </td> 标记的 HTML 表格使用 Beautiful Soup
【发布时间】:2012-08-14 05:10:18
【问题描述】:

我正在努力使用 Beautiful Soup 将一些易碎的 HTML 表格解析为列表。有问题的表缺少 标签。

使用以下代码(不是我正在解析的真实表格,但功能相似):

import bs4
test = "<table> <tr><td>1<td>2<td>3</tr> <tr><td>1<td>2<td>3</tr> </table>"
def walk_table2(text):
    "Take an HTML table and spit out a list of lists (of entries in a row)."
    soup = bs4.BeautifulSoup(text)
    return [[x for x in row.findAll('td')] for row in soup.findAll('tr')]

print walk_table2(test)

给我:

[[<td>1<td>2<td>3</td></td></td>, <td>2<td>3</td></td>, <td>3</td>], [<td>4<td>5<td>6</td></td></td>, <td>5<td>6</td></td>, <td>6</td>]]

而不是预期:

[[<td>1</td>, <td>2</td>, <td>3</td>], [<td>1</td>, <td>2</td>, <td>3</td>]]

Beautiful Soup 使用的 lxml 解析器似乎决定在 的下一个实例之前添加 标记,而不是在

的下一个实例之前添加。

此时,我想知道是否有一个好的选项可以让解析器将结束 td 标记放置在正确的位置,或者在将字符串放入之前使用正则表达式手动放置它们是否更容易BeautifulSoup...有什么想法吗?提前致谢!

【问题讨论】:

  • 美汤的行为似乎完全理性。它找到 `' 标记并得出结论,表格行内的任何打开标记都需要关闭。虽然它是完全合理的,但它也可能是错误的。
  • 我不知道 Beautiful Soup 做了什么,但根据 HTML 5 的规则,解析器应该处于“单元格中”插入模式,它指定在打开新的之前关闭第一个 td .在 HTML 4 中,根据 SGML 解析规则,TD 有一个可选的结束标记,并且不能包含嵌套的 TD,因此在遇到新的开始标记时应该关闭:&lt;!ELEMENT (TH|TD) - O (%flow;)* -- table header cell, table data cell--&gt; - 所以这种行为在客观上是错误的任何一个标准,不能被称为“完全合理”:此代码是合法的 HTML,并且毫无疑问是一个结构合理的表格。

标签: python html beautifulsoup


【解决方案1】:

您会看到 Python 的内置 HTML 解析器做出的决定。如果你不喜欢解析器做事的方式,你可以tell Beautiful Soup to use a different parser。 html5lib 解析器和 lxml 解析器都给出了你想要的结果:

>>> soup = bs4.BeautifulSoup(test, "lxml")
>>> [[x for x in row.findAll('td')] for row in soup.findAll('tr')]
[[<td>1</td>, <td>2</td>, <td>3</td>], [<td>1</td>, <td>2</td>, <td>3</td>]]

>>> soup = bs4.BeautifulSoup(test, "html5lib")
>>> [[x for x in row.findAll('td')] for row in soup.findAll('tr')]
[[<td>1</td>, <td>2</td>, <td>3</td>], [<td>1</td>, <td>2</td>, <td>3</td>]]

【讨论】:

    【解决方案2】:

    对我来说,这听起来像是一个 BeautifulSoup 错误。我发现this page 详细说明了为什么 BS 3.1 从 3.0.8 出现回归(包括“'bad end tag' 错误”),这表明,为了解析错误的 HTML,一种选择是跳回几个版本。也就是说,该页面说它已被取代,现在仅用于历史参考。但目前尚不清楚 BS4 究竟在多大程度上解决了 BS 3.1 中引入的问题 - 至少,尝试旧版本并没有什么坏处。

    【讨论】:

      【解决方案3】:

      修补程序可帮助您度过这一特殊时期:

      用正则表达式按摩传入的数据(这非常脆弱,我知道 stackoverflow 对正则表达式和 html 的感觉,但来吧,就这一次......)

      import re
      r1 = re.compile('(?<!\<tr\>)\<td', re.IGNORECASE)
      r2 = re.compile('\<\/tr>', re.IGNORECASE)
      test = "<table> <tr><td>1<td>2<td>3</tr> <tr><td>1<td>2<td>3</tr> </table>"
      test = r1.sub('</td><td', test)
      test = r2.sub('</td></tr>', test)
      print test
      

      哦,然后test

      <table> <tr><td>1</td><td>2</td><td>3</td></tr> <tr><td>1</td><td>2</td><td>3</td></tr> </table>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-20
        • 1970-01-01
        • 2022-01-03
        • 1970-01-01
        • 2014-12-16
        • 2013-09-07
        • 2015-11-08
        • 1970-01-01
        相关资源
        最近更新 更多