我已经读过,BeautifulSoup在与号(&)上有问题,这些符号在HTML中并不严格正确,但大多数浏览器仍然能正确解释。然而奇怪的是,我在Mac系统和Ubuntu系统上的行为却不一样,这两个系统都使用bs4版本4.3.2:

html='<td>S&P500</td>'
s=bs4.BeautifulSoup(html)

在Ubuntu系统上,s等于:
<td>S&amp;P500;</td>

注意在末尾添加的分号,这是一个真正的问题
在mac系统上:
<html><head></head><body>S&amp;P500</body></html>

别介意html/head/body标签,我可以处理这个问题,但请注意,这次标普500的解释是正确的,没有添加“;”。
知道怎么回事吗?如何使跨平台代码不诉诸丑陋的黑客?谢谢,

最佳答案

首先,我无法使用python2.7.1和beautifulsoup4.3.2复制mac结果,也就是说,我在所有系统上都得到了额外的分号。
简单的解决方法是a)使用严格有效的HTML,或者b)在与号后面添加一个空格。很可能您无法更改源代码,如果您能够在python中解析并替换这些代码,您就不需要BeautifulSoup;)
所以问题是BeautifulSoupHTMLParser首先将S&P500转换为S&P500;,因为它假定P500是字符名,而您只是忘记了分号。
然后,它重新解析字符串并找到&P500;。现在它无法将P500识别为有效名称,并在不接触其他名称的情况下将&转换为&amp;
这里有一个愚蠢的monkeypatch只是为了证明我的观点。我对美联的内部运作还不太了解,无法提出一个恰当的解决方案。

from bs4 import BeautifulSoup
from bs4.builder._htmlparser import BeautifulSoupHTMLParser
from bsp.dammit import EntitySubstitution

def handle_entityref(self, name):
    character = EntitySubstitution.HTML_ENTITY_TO_CHARACTER.get(name)
    if character is not None:
        data = character
    else:
        # Previously was
        # data = "&%s;" % name
        data = "&%s" % name
    self.handle_data(data)

html = '<td>S&P500</td>'

# Pre monkeypatching
# <td>S&amp;P500;</td>
print(BeautifulSoup(html))

BeautifulSoupHTMLParser.handle_entityref = handle_entityref

# Post monkeypatching
# <td>S&amp;P500</td>
print(BeautifulSoup(html))

希望精通bs4的人能给你一个合适的解决方案,祝你好运。

09-03 18:08