克隆元素与beautifulsoup

Ant*_*gor 15 python beautifulsoup

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

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

当我使用真实文件时,我可以在修改后不保存document1,但有没有办法在不损坏文档的情况下执行此操作?

Mar*_*ers 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
Run Code Online (Sandbox Code Playgroud)

这种方法对当前的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)
Run Code Online (Sandbox Code Playgroud)

让你.clone()直接调用元素:

document2.body.append(document1.find('div', id_='someid').clone())
Run Code Online (Sandbox Code Playgroud)

我对BeautifulSoup项目的功能请求被接受并调整为使用该copy.copy()功能 ; 既然BeautifulSoup 4.4已经发布,你可以使用该版本(或更新版本)并执行:

import copy

document2.body.append(copy.copy(document1.find('div', id_='someid')))
Run Code Online (Sandbox Code Playgroud)


and*_*ate 6

它可能不是最快的解决方案,但它很短,似乎有效......

clonedtag = BeautifulSoup(str(sourcetag))

这个想法源于彼得·伍兹上面的评论.

  • 如果我试试这个,我在标签周围得到一个额外的`<html> <body> ... </ body> </ html>`(因为它应该 - BeautifulSoup试图将它变成一个理智的HTML文档,因为它是要求).需要从该文档中提取埋藏标签的另一个方法是:`clonedtag = BeautifulSoup(str(sourcetag)).body.contents [0]` (5认同)
  • 谢谢克莱门斯,你是对的。自发布以来,我发现我的kludge也很慢,这表明它必须进行大量的工作来创建字符串,然后再次将其解析回新的BeautifulSoup实例。 (2认同)

小智 5

对于Python:

您可以复制父元素,例如:

import copy
p_copy = copy.copy(soup.p)
print p_copy
# <p>I want <b>pizza</b> and more <b>pizza</b>!</p>

Run Code Online (Sandbox Code Playgroud)

参考: https: //www.crummy.com/software/BeautifulSoup/bs4/doc/ 部分:复制 Beautiful Soup 对象

问候。