我必须将一个文档的一部分复制到另一个文档,但我不想修改我复制的文档。
如果我使用.extract()
,它会从树中删除元素。如果我只是追加像document2.append(document1.tag)
这样的选定元素,它仍会从document1中删除该元素。
当我使用真实文件时,我可以在修改后不保存document1,但有没有办法在不损坏文档的情况下执行此操作?
答案 0 :(得分:24)
在4.4之前的版本(2015年7月发布)中,BeautifulSoup中没有本机克隆功能;你必须自己创建一个深层拷贝,这很棘手,因为每个元素都保持与树的其余部分的链接。
要克隆元素及其所有元素,您必须复制所有属性并重置其父子关系;这必须递归发生。最好不要复制关系属性并重新安置每个递归克隆的元素:
from bs4 import Tag, NavigableString
def clone(el):
if isinstance(el, NavigableString):
return type(el)(el)
copy = Tag(None, el.builder, el.name, el.namespace, el.nsprefix)
# work around bug where there is no builder set
# https://bugs.launchpad.net/beautifulsoup/+bug/1307471
copy.attrs = dict(el.attrs)
for attr in ('can_be_empty_element', 'hidden'):
setattr(copy, attr, getattr(el, attr))
for child in el.contents:
copy.append(clone(child))
return copy
这种方法对当前的BeautifulSoup版本很敏感;我用4.3测试了这个,未来的版本可能会添加需要复制的属性。
您还可以将此功能monkeypatch到BeautifulSoup:
from bs4 import Tag, NavigableString
def tag_clone(self):
copy = type(self)(None, self.builder, self.name, self.namespace,
self.nsprefix)
# work around bug where there is no builder set
# https://bugs.launchpad.net/beautifulsoup/+bug/1307471
copy.attrs = dict(self.attrs)
for attr in ('can_be_empty_element', 'hidden'):
setattr(copy, attr, getattr(self, attr))
for child in self.contents:
copy.append(child.clone())
return copy
Tag.clone = tag_clone
NavigableString.clone = lambda self: type(self)(self)
让您直接在元素上调用.clone()
:
document2.body.append(document1.find('div', id_='someid').clone())
我的feature request到BeautifulSoup项目was accepted and tweaked以使用copy.copy()
function;现在,BeautifulSoup 4.4已经发布,您可以使用该版本(或更新版本)并执行:
import copy
document2.body.append(copy.copy(document1.find('div', id_='someid')))
答案 1 :(得分:5)
它可能不是最快的解决方案,但它很短,似乎有效......
clonedtag = BeautifulSoup(str(sourcetag))
这个想法源于彼得·伍兹上面的评论。
答案 2 :(得分:0)
对于Python:
您可以复制父元素,例如:
import copy
p_copy = copy.copy(soup.p)
print p_copy
# <p>I want <b>pizza</b> and more <b>pizza</b>!</p>
参考:https://www.crummy.com/software/BeautifulSoup/bs4/doc/ 部分:复制美丽汤对象
致谢。