我必须将一个文档的一部分复制到另一个文档,但我不想修改我从中复制的文档。
如果我使用 .extract()
它会从树中删除该元素。如果我只是附加选定的元素,如 document2.append(document1.tag)
,它仍然会从 document1 中删除该元素。
因为我使用的是真实文件,所以我不能在修改后保存 document1,但是有什么方法可以在不损坏文档的情况下做到这一点吗?
最佳答案
BeautifulSoup在4.4(2015年7月发布)之前的版本中没有原生克隆功能;您必须自己创建一个深拷贝,这很棘手,因为每个元素都维护到树的其余部分的链接。
要克隆一个元素及其所有元素,您必须复制所有属性并重置它们的父子关系;这必须递归发生。最好不要复制关系属性并重新放置每个递归克隆的元素:
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 测试了这个, future 的版本可能会添加需要复制的属性。
您还可以将此功能猴子修补到 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')))
关于python - 用 beautifulsoup 克隆元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23057631/