5

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

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

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 解析器似乎决定在 </tr> 的下一个实例之前添加 </td> 标记,而不是在 <td> 的下一个实例之前添加。

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

4

3 回答 3

4

您会看到 Python 的内置 HTML 解析器做出的决定。如果你不喜欢 parser 做事的方式,你可以告诉 Beautiful Soup 使用不同的 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>]]
于 2012-08-17T19:45:29.073 回答
2

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

于 2012-08-17T18:28:14.810 回答
1

一个不完整的修复让你度过这个特殊的困境:

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

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>
于 2012-08-17T18:47:14.857 回答