与HTML文档中的元素替换多个字符串

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

我有我想要一个HTML文档中绕到HTML标记多个字符串。我要离开的文字相同,但含有该字符串的HTML元素替换字符串。

此外,一些我想替换字符串,包含其他字符串我想替换。在这种情况下,我想申请较大的字符串替代和忽略较小的字符串。

另外,我只想要执行时,这些字符串在同一单元内完全包含这种替换。

这是我的替换列表。

replacement_list = [
    ('foo', '<span title="foo" class="customclass34">foo</span>'),
    ('foo bar', '<span id="id21" class="customclass79">foo bar</span>')
]

考虑下面的HTML:

<html>
<body>
<p>Paragraph contains foo</p>
<p>Paragraph contains foo bar</p>
</body>
</html>

我想替换这样的:

<html>
<body>
<p>Paragraph contains <span title="foo" class="customclass34">foo</span></p>
<p>Paragraph contains <span id="id79" class="customclass79">foo bar</span</p>
</body>
</html>

到目前为止,我已经用美丽的汤库,并通过我的更换名单中减少字符串长度的顺序循环,我可以找到与其他字符串替换我的琴弦,但我不能工作,如何在这些插入HTML尝试点。或者是否有完全有更好的办法。试图用soup.new_tag对象执行字符串替换失败时是否我将它转换为字符串或没有。

编辑:我实现了,甚至不符合我自己的规则,例如,修改示例。

python html beautifulsoup
3个回答
1
投票

我觉得这是非常接近你在找什么。您可以使用soup.find_all(string=True)只得到了NavigableString元素,然后做替换。

from bs4 import BeautifulSoup
html="""
<html>
<body>
<p>Paragraph contains foo</p>
<p>Paragraph contains foo bar</p>
</body>
</html>
"""
replacement_list = [
    ('foo', '<span title="foo" class="customclass34">foo</span>'),
    ('foo bar', '<span id="id21" class="customclass79">foo bar</span>')
]
soup=BeautifulSoup(html,'html.parser')
for s in soup.find_all(string=True):
    for item in replacement_list[::-1]: #assuming that it is in ascending order of length
        key,val=item
        if key in s:
            new_s=s.replace(key,val)
            s.replace_with(BeautifulSoup(new_s,'html.parser')) #restrict youself to this built-in parser
            break#break on 1st match
print(soup)

#generate a new valid soup that treats span as seperate tag if you want
soup=BeautifulSoup(str(soup),'html.parser')
print(soup.find_all('span'))

输出:

<html>
<body>
<p>Paragraph contains <span class="customclass34" title="foo">foo</span></p>
<p>Paragraph contains <span class="customclass79" id="id21">foo bar</span></p>
</body>
</html>

[<span class="customclass34" title="foo">foo</span>, <span class="customclass79" id="id21">foo bar</span>]

1
投票

我发现了一个解决方案。

我通过HTML为每个不同的字符串我想绕到HTML标签进行迭代。这似乎效率不高,但我找不到这样做的更好的方法。

我添加了一个类来所有我插入标签,我用它来检查,如果我试图替换字符串是已经更换一个更大的字符串的一部分。

该解决方案也是不区分大小写的(这将包裹字符串“富”的标签左右),同时保留原始文本的情况。

def html_update(input_html):
    from bs4 import BeautifulSoup
    import re

    soup = BeautifulSoup(input_html)

    replacement_list = [
        ('foo', '<span title="foo" class="customclass34 replace">', '</span>'),
        ('foo bar', '<span id="id21" class="customclass79 replace">', '</span>')
    ]
    # Go through list in order of decreasing length
    replacement_list = sorted(replacement_list, key = lambda k: -len(k[0]))

    for item in replacement_list:
        replace_regex = re.compile(item[0], re.IGNORECASE)
        target = soup.find_all(string=replace_regex)
        for v in target:
            # You can use other conditions here, like (v.parent.name == 'a')
            # to not wrap the tags around strings within links
            if v.parent.has_attr('class') and 'replace' in v.parent['class']:
                # The match must be part of a large string that was already replaced, so do nothing
                continue 

            def replace(match):
                return '{0}{1}{2}'.format(item[1], match.group(0), item[2])

            new_v = replace_regex.sub(replace, v)
            v.replace_with(BeautifulSoup(new_v, 'html.parser'))
    return str(soup)

0
投票

当你在处理小文件,这是很好的逐行读取文件中的行,并在要替换了每行的替换,然后写的一切到一个新文件。

假设你的文件被称为output.html

replacement_list = {'foo': '<span title="foo" class="customclass34">foo</span>', 'foo bar':'<span id="id21" class="customclass79">foo bar</span>'}

with open('output.html','w') as dest :
    with open('test.html','r') as src :
        for line in src:   #### reading the src file line by line
            str_possible = []
            for string in replacement_list.keys(): #### looping over all the strings you are looking for
                if string in line: ### checking if this string is in the line
                    str_possible.append(string)
            if len(str_possible) >0:
                str_final = max(str_possible, key=len)  ###taking the appropriate one, which is the longest
                line = line.replace(str_final,replacement_list[str_final])

            dest.write(line)

我也建议你检查了在Python中的字典,这是我使用的replacement_list的对象。

最后,该代码将工作,如果有就行中最大的一个字符串。如果两个,它需要适应一下,但是这给你的总体思路。

© www.soinside.com 2019 - 2024. All rights reserved.