用beautifulsoup克隆元素

2024-09-27 04:21:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我必须将一个文档的一部分复制到另一个文档,但我不想修改从中复制的文档。

如果我使用.extract(),它将从树中删除元素。如果我只是像document2.append(document1.tag)那样附加所选元素,它仍然会从document1中删除该元素。

因为我使用的是真实的文件,所以在修改后我不能保存document1,但是有没有什么方法可以在不损坏文档的情况下这样做呢?


Tags: 文件方法文档元素tag情况extractappend
2条回答

在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测试了这个,将来的版本可能也会添加需要复制的属性。

您也可以将此功能添加到美化组:

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使用^{} function;既然BeautifulSoup 4.4发布了,您可以使用该版本(或更新版本)并执行以下操作:

import copy

document2.body.append(copy.copy(document1.find('div', id_='someid')))

这可能不是最快的解决方案,但它很短,似乎可以。。。

clonedtag = BeautifulSoup(str(sourcetag))

这个想法是彼得·伍兹在上面评论的。

相关问题 更多 >

    热门问题