如何使用 BeautifulSoup 从 HTML 中去除评论标签?

Posted

技术标签:

【中文标题】如何使用 BeautifulSoup 从 HTML 中去除评论标签?【英文标题】:How can I strip comment tags from HTML using BeautifulSoup? 【发布时间】:2011-03-31 06:05:51 【问题描述】:

我一直在玩 BeautifulSoup,这很棒。我的最终目标是尝试从页面中获取文本。我只是想从正文中获取文本,在特殊情况下从<a><img> 标签中获取标题和/或alt 属性。

到目前为止,我有这个EDITED & UPDATED CURRENT CODE

soup = BeautifulSoup(page)
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
[comment.extract() for comment in comments]
page = ''.join(soup.findAll(text=True))
page = ' '.join(page.split())
print page

1) 对于我的特殊情况,您有什么建议最好的方法是不要从我上面列出的两个标签中排除这些属性?如果这样做太复杂,则不如执行 #2 重要。

2) 我想剥离<!-- --> 标签以及它们之间的所有内容。我该怎么办?

QUESTION EDIT @jathanism:这里有一些我试图去掉的评论标签,但即使我使用你的例子也保留下来

<!-- Begin function popUp(URL)  day = new Date(); id = day.getTime(); eval("page" + id + " = window.open(URL, '" + id + "', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=300,height=330,left = 774,top = 518');");  // End -->
<!-- var MenuBar1 = new Spry.Widget.MenuBar("MenuBar1", imgDown:"SpryAssets/SpryMenuBarDownHover.gif", imgRight:"SpryAssets/SpryMenuBarRightHover.gif"); //--> <!-- var MenuBar1 = new Spry.Widget.MenuBar("MenuBar1", imgDown:"SpryAssets/SpryMenuBarDownHover.gif", imgRight:"SpryAssets/SpryMenuBarRightHover.gif"); //--> <!-- var whichlink=0 var whichimage=0 var blenddelay=(ie)? document.images.slide.filters[0].duration*1000 : 0 function slideit() if (!document.images) return if (ie) document.images.slide.filters[0].apply() document.images.slide.src=imageholder[whichimage].src if (ie) document.images.slide.filters[0].play() whichlink=whichimage whichimage=(whichimage<slideimages.length-1)? whichimage+1 : 0 setTimeout("slideit()",slidespeed+blenddelay)  slideit() //-->

【问题讨论】:

是否有源文档用作测试用例?如果您能提供一些您想到的东西作为比较的基础,那将非常有帮助。 【参考方案1】:

直接从documentation for BeautifulSoup,您可以使用extract() 轻松剥离 cmets(或任何东西):

from BeautifulSoup import BeautifulSoup, Comment
soup = BeautifulSoup("""1<!--The loneliest number-->
                        <a>2<!--Can be as bad as one--><b>3""")
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
[comment.extract() for comment in comments]
print soup
# 1
# <a>2<b>3</b></a>

【讨论】:

我不知道为什么我没有看到。谢谢你叫醒我! 不错。但是做一个带有副作用的列表理解看起来很恶心:p。 map( lambda x: x.extract(), comments ) 怎么样? 我仍在试图弄清楚为什么它找不到并删除像这样的标签 &lt;!-- //--&gt; 这些反斜杠会导致某些标签被忽略 BeautifulSoup 有什么变化吗?我用 3.2.0 试过了,像 &lt;!-- //--&gt; 这样的 cmets 没有问题。【参考方案2】:

我仍在试图找出原因 没有找到和剥离这样的标签: &lt;!-- //--&gt;。这些反斜杠导致 某些标签会被忽略。

这可能是底层 SGML 解析器的问题:请参阅 http://www.crummy.com/software/BeautifulSoup/documentation.html#Sanitizing%20Bad%20Data%20with%20Regexps。您可以使用 markupMassage 正则表达式覆盖它——直接来自文档:

import re, copy

myMassage = [(re.compile('<!-([^-])'), lambda match: '<!--' + match.group(1))]
myNewMassage = copy.copy(BeautifulSoup.MARKUP_MASSAGE)
myNewMassage.extend(myMassage)

BeautifulSoup(badString, markupMassage=myNewMassage)
# Foo<!--This comment is malformed.-->Bar<br />Baz

【讨论】:

这是一个棘手的问题,这看起来是一个很好的解决方法。遗憾的是它最终仍然使用正则表达式来解析 HTML。愚蠢的正则表达式! 好的,我将处理 re.compile 以检测我列出的混乱 cmets。需要复习我的正则表达式。废话。 @jathanism -- BeautifulSoup 在将 HTML 提供给 sgmllib 之前在内部使用了几个正则表达式来润色 HTML。它不漂亮,但也不是洛夫克拉夫特式的。 只是为了更新这个旧帖子,BeautifulSoup.MARKUP_MASSAGE 已被弃用。 “BeautifulSoup 构造函数不再识别 markupMassage 参数。现在解析器负责正确处理标记。” crummy.com/software/BeautifulSoup/bs4/doc(在他们页面的最底部)【参考方案3】:

如果您正在寻找 BeautifulSoup 版本 3 中的解决方案 BS3 Docs - Comment

soup = BeautifulSoup("""Hello! <!--I've got to be nice to get what I want.-->""")
comment = soup.find(text=re.compile("if"))
Comment=comment.__class__
for element in soup(text=lambda text: isinstance(text, Comment)):
    element.extract()
print soup.prettify()

【讨论】:

【参考方案4】:

如果突变不是你的包,你可以

[t for t in soup.find_all(text=True) if not isinstance(t, Comment)]

【讨论】:

以上是关于如何使用 BeautifulSoup 从 HTML 中去除评论标签?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 beautifulsoup 从 html 页面中抓取纬度/经度数据

如何从 BeautifulSoup4 中的 html 标签中找到特定的数据属性?

如何使用 beautifulsoup 从(可能)损坏的 html 中过滤掉 .mp3 链接? (JSON)

如何使用 BeautifulSoup 在标签内获取 html 文本

Python/BeautifulSoup - 如何从元素中删除所有标签?

如何从 BeautifulSoup 对象中提取 JSON?