我有我想要一个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对象执行字符串替换失败时是否我将它转换为字符串或没有。
编辑:我实现了,甚至不符合我自己的规则,例如,修改示例。
我觉得这是非常接近你在找什么。您可以使用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>]
我发现了一个解决方案。
我通过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)
当你在处理小文件,这是很好的逐行读取文件中的行,并在要替换了每行的替换,然后写的一切到一个新文件。
假设你的文件被称为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
的对象。
最后,该代码将工作,如果有就行中最大的一个字符串。如果两个,它需要适应一下,但是这给你的总体思路。