我已经读过,BeautifulSoup在与号(&)上有问题,这些符号在HTML中并不严格正确,但大多数浏览器仍然能正确解释。然而奇怪的是,我在Mac系统和Ubuntu系统上的行为却不一样,这两个系统都使用bs4版本4.3.2:
html='<td>S&P500</td>'
s=bs4.BeautifulSoup(html)
在Ubuntu系统上,s等于:
<td>S&P500;</td>
注意在末尾添加的分号,这是一个真正的问题
在mac系统上:
<html><head></head><body>S&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
识别为有效名称,并在不接触其他名称的情况下将&
转换为&
。
这里有一个愚蠢的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&P500;</td>
print(BeautifulSoup(html))
BeautifulSoupHTMLParser.handle_entityref = handle_entityref
# Post monkeypatching
# <td>S&P500</td>
print(BeautifulSoup(html))
希望精通bs4的人能给你一个合适的解决方案,祝你好运。