BeautifulSoup 解析器在裸露的&上加分号,搞坏了网址?

7 投票
1 回答
1999 浏览
提问于 2025-04-17 00:19

我正在用Python解析一个网站,这个网站里面有指向其他网站的链接,但这些链接是以纯文本的形式出现的,而不是用“a”标签包裹起来的。使用BeautifulSoup的时候,我得到了错误的结果。看看这段代码:

import BeautifulSoup

html = """<html>
            <head>
              <title>Test html</title>
            </head>
            <body>
              <div>
                example.com/a.php?b=2&c=15
              </div>
            </body>
          </html>"""

parsed = BeautifulSoup.BeautifulSoup(html)
print parsed

当我运行上面的代码时,输出结果是:

<html>
  <head>
    <title>Test html</title>
  </head>
  <body>
    <div>
      example.com/a.php?b=2&c;=15
    </div>
  </body>
</html>

注意“div”里的链接,以及那部分b=2&c=15。它和原始的HTML不一样。为什么BeautifulSoup会这样处理链接呢?它是在试图自动生成HTML实体吗?我该如何防止这种情况发生?

1 个回答

7

看起来,Beautiful Soup(简称BS)在处理网址中的“&”符号时,有一个文档里没详细说明的问题。我刚在他们的讨论论坛上搜索了“分号”。根据2009年的讨论,单独的&其实是不合法的,应该用&amp;来替代,虽然浏览器能接受这种写法,所以这听起来有点过于严格了。

我觉得这种解析方式真是有点问题,你应该联系他们的讨论组,建议他们至少把这个问题记录下来,并在未来的版本中修复。

解决方法:无论如何,你的解决方法很可能是用re.sub(...)来捕捉并替换网址中的&&amp;。可能你还需要一个反向的函数来在输出时压缩它们。你需要一个更复杂的正则表达式来只捕捉网址中的“&”符号,不过无论如何:

# Minimal string to tickle this
#html = "<html>example.com/a.php?b=2&c=15&d=42</html>"
html = "<html>example.com/a.php?b=2&c=15&amp;d=29&e=42</html>"

html = re.sub(r'&(?!amp;)', r'&amp;', html)

parsed = BeautifulSoup.BeautifulSoup(html)
>>> print parsed.text.encode('utf-8')
'example.com/a.php?b=2&amp;c=15'

>>> re.sub(r'&amp;', r'&', parsed.text.encode('utf-8'))
'example.com/a.php?b=2&c=15'

可能还有其他更符合BS风格的方法。你也许想要帮助测试一下4.0的测试版。

撰写回答