Ответ 1
В BeautifulSoup нет версий функции native clone в версиях до 4.4 (выпущен в июле 2015 года); вам нужно будет создать глубокую копию самостоятельно, что сложно, поскольку каждый элемент поддерживает ссылки на остальную часть дерева.
Чтобы клонировать элемент и все его элементы, вам нужно скопировать все атрибуты и reset их отношения родитель-потомок; это должно произойти рекурсивно. Это лучше всего сделать, не копируя атрибуты отношений и не переставляя каждый рекурсивно-клонированный элемент:
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, будущие версии могут добавлять атрибуты, которые также нужно скопировать.
Вы также можете обезвредить эту функцию в 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())
Мой запрос функции в проект BeautifulSoup был принят и изменен, чтобы использовать copy.copy()
функция; теперь, когда выпущен BeautifulSoup 4.4, вы можете использовать эту версию (или новее) и делать:
import copy
document2.body.append(copy.copy(document1.find('div', id_='someid')))