如何使用BeautifulSoup复制标签并插入到被复制标签之后?
问题描述
存在大量class名相同的标签,这类标签结构较长且嵌套了其他标签,简化测试代码如下:
from bs4 import BeautifulSoup HTML = ''' <p class=test>111</p> <p class=test>222</p> <p class=test>333</p> <p class=test>444</p> <p class=test>555</p> ''' soup = BeautifulSoup(HTML, 'lxml') origin_tag = soup.select('p.test') print(len(origin_tag)) # 运行结果为5 origin_tag.insert(1, origin_tag[1]) print(len(origin_tag)) # 运行结果为6 print(soup) # 实际HTML内容无任何变化,未达到预期
预期运行后输出的HTML结构为:
<p class=test>111</p> <p class=test>222</p> <p class=test>222</p> <p class=test>333</p> <p class=test>444</p> <p class=test>555</p>
实际运行时,soup.select('p.test')可正常获取到5个p标签,对返回的列表执行insert操作插入原索引1位置的标签后,列表长度显示为6,但打印soup时HTML内容没有任何变化,无法得到预期结果,需要实现标签的复制与插入操作。
问题原因
soup.select()返回的是Python原生列表,仅保存了匹配到的标签对象引用,直接对这个列表做增删改操作只会修改列表本身,不会改动BeautifulSoup维护的DOM树结构。- 就算直接操作DOM插入已存在的标签对象,也只是移动标签的原有位置,不会生成新的重复标签。
解决方法
需要先对要复制的标签做深拷贝,再调用标签自带的DOM操作方法插入新节点,不要直接修改select返回的列表,参考代码如下:
from bs4 import BeautifulSoup import copy HTML = ''' <p class=test>111</p> <p class=test>222</p> <p class=test>333</p> <p class=test>444</p> <p class=test>555</p> ''' soup = BeautifulSoup(HTML, 'lxml') origin_tags = soup.select('p.test') # 深拷贝目标标签,嵌套标签也会被完整复制,不影响原节点 copied_tag = copy.deepcopy(origin_tags[1]) # 在原索引1的标签后方插入复制出的新标签 origin_tags[1].insert_after(copied_tag) print(soup)
运行上述代码即可得到预期的HTML输出。
注意:如果标签存在多层嵌套,必须使用
copy.deepcopy()做深拷贝,浅拷贝会导致内部子节点仍关联原DOM,引发结构异常。
内容的提问来源于stack exchange,提问作者simon chang
相关产品推荐
相关产品推荐

