在 HTML BeautifulSoup 中按文本查找和替换

Posted

技术标签:

【中文标题】在 HTML BeautifulSoup 中按文本查找和替换【英文标题】:Find by Text and Replace in HTML BeautifulSoup 【发布时间】:2013-05-23 21:43:53 【问题描述】:

我正在尝试使用 python 和 BeautifulSoup 标记一个 html 文件(字面上将字符串包装在“标记”标签中)。问题基本如下...

假设我有我的原始 html 文档:

test = "<h1>oh hey</h1><div>here is some <b>SILLY</b> text</div>"

我想对此文档中的字符串进行不区分大小写的搜索(忽略 HTML)并将其包装在“标记”标签中。所以假设我想在 html 中找到“这里有一些愚蠢的文本”(忽略粗体标签)。我想获取匹配的 html 并将其包装在“标记”标签中。

例如,如果我想在 test 中搜索“here is some silly text”,那么想要的输出是:

"<h1>oh hey</h1><div><mark>here is some <b>SILLY</b> text</mark></div>"

有什么想法吗?如果使用 lxml 或正则表达式更合适,我也愿意接受这些解决方案。

【问题讨论】:

接近另一个问题的副本。 ***.com/questions/8936030/… @melwil - 很接近,但仅涵盖问题的(区分大小写的)文本检索部分。如何使用类似的搜索字符串,在 html 中查找不区分大小写的匹配项,并将这些匹配项包装在标记标签中? 找到文本后,只需将其插入到标记标记中的父级中。 你想如何处理&lt;h1&gt; here is some &lt;/h1&gt; &lt;h2&gt; silly text &lt;/h2&gt;?如果你把它变成&lt;h1&gt;&lt;mark&gt; here is some &lt;/h1&gt; &lt;h2&gt; silly text &lt;/mark&gt;&lt;/h2&gt;,那么mark 标签跨越两个兄弟元素之间。可以吗? @Kevin - 是的!我很好 【参考方案1】:
>>> soup = bs4.BeautifulSoup(test)
>>> matches = soup.find_all(lambda x: x.text.lower() == 'here is some silly text')
>>> for match in matches:
...     match.wrap(soup.new_tag('mark'))
>>> soup
<html><body><h1>oh hey</h1><mark><div>here is some <b>SILLY</b> text</div></mark></body></html>

我必须将一个函数作为name 传递给find_all 来比较x.text.lower(),而不是仅仅使用text 参数和一个比较x.lower() 的函数,因为后者不会在某些情况下找到您显然想要的内容。

wrap 函数在某些情况下可能无法以这种方式工作。如果没有,您将不得不改为enumerate(matches),并设置matches[i] = match.wrap(soup.new_tag('mark'))。 (您不能使用replace_with 将标签替换为引用自身的新标签。)

另请注意,如果您的预期用例允许任何非 ASCII 字符串匹配 'here is some silly text'(或者如果您想扩展代码以处理非 ASCII 搜索字符串),则上面使用 lower() 的代码可能是不正确。您可能想致电str.casefold() 和/或locale.strxfrm(s) 和/或使用locale.strcoll(s, t) 而不是使用==,但您必须了解您想要什么以及如何获得它才能选择正确的答案。

【讨论】:

非常感谢!看起来你可以只用for match in matches: match.wrap(soup.new_tag('mark')) @MuradSalahi:我只是在测试它。它似乎适用于 4.1.3,但不适用于 4.0.5。我不知道为什么,但我会将其更改为简单版本,并附上解释或不适用于任何人。谢谢! .lower() might not be enough for a case-insensitive search in a Unicode text. @J.F.塞巴斯蒂安:是的。但是如果不知道用例,就不可能描述什么是正确。我会更新答案以涵盖这一点。 如果我想要标记的是“傻文字”怎么办?它跨越了2个标签,所以你不能通过iter all tags找到它。

以上是关于在 HTML BeautifulSoup 中按文本查找和替换的主要内容,如果未能解决你的问题,请参考以下文章

在 BeautifulSoup 中创建行和列

使用beautifulsoup在html中查找文本

在文本框中按 Enter 时如何触发 HTML 按钮?

使用 BeautifulSoup 提取标签之间的文本

BeautifulSoup 从评论 html 中提取文本 [重复]

使用 BeautifulSoup 查找包含特定文本的 HTML 标签