使用BeautifulSoup解析文档但不解析<code>标签内容

10 投票
5 回答
1882 浏览
提问于 2025-04-16 06:00

我正在用Django写一个博客应用。我想让评论者可以使用一些标签(比如 <strong>a 等等),但要禁用其他所有标签。

另外,我还想让他们可以在 <code> 标签中放代码,并让pygments来解析这些代码。

比如,有人可能会写这样的评论:

I like this article, but the third code example <em>could have been simpler</em>:

<code lang="c">
#include <stdbool.h>
#include <stdio.h>

int main()
{
    printf("Hello World\n");
}
</code>

问题是,当我用BeautifulSoup来解析评论,去掉不允许的HTML标签时,它也会解析 <code> 块里的内容,把 <stdbool.h><stdio.h> 当成HTML标签来处理。

我该怎么告诉BeautifulSoup不要解析 <code> 块呢?也许还有其他更适合这个工作的HTML解析器?

5 个回答

0

很遗憾,BeautifulSoup无法阻止解析代码块。

要实现你想要的效果,有一个解决方案是:

1) 移除代码块

soup = BeautifulSoup(unicode(content))
code_blocks = soup.findAll(u'code')
for block in code_blocks:
    block.replaceWith(u'<code class="removed"></code>')

2) 进行常规解析,去掉不允许的标签。

3) 重新插入代码块,并重新生成HTML。

stripped_code = stripped_soup.findAll(u"code", u"removed")
# re-insert pygment formatted code

我本来可以给你一些代码示例,但我最近看到一个博客,里面优雅地解决了这个问题。

1

来自 Python wiki

>>>import cgi
>>>cgi.escape("<string.h>")
>>>'&lt;string.h&gt;'

>>>BeautifulSoup('&lt;string.h&gt;', 
...               convertEntities=BeautifulSoup.HTML_ENTITIES)
1

问题在于,<code> 标签是按照普通的 HTML 规则来处理的,标签里面的内容依然被当作 HTML。其实这些标签主要是为了让 CSS 样式能够正常工作,并不是为了改变解析规则。

你想做的事情是创建一种与 HTML 非常相似但又不完全相同的标记语言。一个简单的解决办法是设定一些规则,比如说,“<code></code> 必须单独占一行”,然后自己进行一些预处理。

  1. 一种非常简单但不完全可靠的方法是把 ^<code>$ 替换成 <code><![CDATA[,把 ^</code>$ 替换成 ]]></code>。这个方法不太可靠,因为如果代码块里面包含 ]]>,就会出问题。
  2. 一个更安全的选择是把代码块里面的危险字符(比如 <>&)替换成它们对应的字符实体引用(比如 &lt;&gt;&amp;)。你可以通过把每个识别出来的代码块传给 cgi.escape(code_block) 来实现。

完成预处理后,像往常一样把结果提交给 BeautifulSoup。

撰写回答