用 BeautifulSoup4 替换 html 中的所有文本,同时保持原始 DOM 结构

问题描述 投票:0回答:1

我正在尝试使用 python 中的 Beutifulsoap4 替换 html 文档中的所有文本,包括其中包含文本和其他元素的元素。例如我想让

<div>text1<strong>text2</strong>text3</div>
变成
<div>text1_changed<strong>text2_changed</strong>text3_changed</div>
.

我知道线程 在所有 dom 元素中替换文本的更快方法?,但是这使用 Javascript,因此使用的函数在 python 中不可用。我想使用本机 python 实现相同的目标

如果所有标签都包含标签或文本(rand_text 函数返回一个随机字符串),我有一个代码已经有效:

from bs4 import BeautifulSoup as bs

def randomize(html):
    soup = bs(html, features='html.parser')
    elements = soup.find_all()

    for el in elements:
        if el.string == None:
            pass
        else:
            replacement = rand_text(el.text)
        el.string.replace_with(replacement)
    return soup

然而,当元素的“string”属性为 None 时,这段代码在上面的示例中不起作用,因为它同时包含其他元素和文本。

如果“string”属性为 None,我也尝试创建一个新元素,然后替换整个元素:

from bs4 import BeautifulSoup as bs

def anonymize2(html):
    soup = bs(html, features='html.parser')
    elements = soup.find_all()
    for el in elements:
        replacement = rand_text(el.text)
        if el.string:
            el.string.replace_with(replacement)
        else:
            new_el = soup.new_tag(el.name)
            new_el.attrs = el.attrs
            for sub_el in el.contents:
                new_el.append(sub_el)
            new_el.string = replacement
            parent = el.parent
            if parent:
                if new_el not in soup:
                    soup.append(new_el)
                parent.replace_with(new_el)
    return soup

但是这个给出了错误“ValueError:当要替换的元素不是树的一部分时,无法用另一个元素替换一个元素。” 我想我收到了这个错误,因为算法已经替换了它试图替换的元素的父元素。我可以实施什么逻辑来解决这个问题?或者我怎样才能用不同的方法实现我最初的目标?

python algorithm dom beautifulsoup
1个回答
0
投票

可以遍历元素的

contents
,检查每一项是否为字符串,然后替换字符串。

from bs4 import BeautifulSoup as bs

def randomize(html):
    soup = bs(html, features='html.parser')
    elements = soup.find_all()

    for el in elements:
        replacement = rand_text(el.text)
        if el.string:
            el.string.replace_with(replacement)
        else:
            for sub_el in el.contents:
                if isinstance(sub_el, str):
                    sub_el.replace_with(rand_text(sub_el))
    return soup

# defined for testing purposes. Replace this with your own logic
def rand_text(text):
    return text + "_changed"



html = "<div>text1<strong>text2</strong>text3</div>"
print(randomize(html))

输出:

<div>text1_changed<strong>text2_changed</strong>text3_changed</div>
© www.soinside.com 2019 - 2024. All rights reserved.