python - ejemplos - ¿Cómo obtener "subsuelos" y concatenar/unirlos?
bs4 (2)
Puede usar findAll
con pasar los ids
de los elementos que desea usar.
import bs4
soup = bs4.BeautifulSoup(my_document)
#EDIT -> I discovered you do not need regex, you can pass in a list of `ids`
sub = soup.findAll(attrs={''id'': [''first'', ''third'', ''loner'']})
#EDIT -> adding `html.parser` will force `BeautifulSoup` to not auto append `html` and `body` tags.
sub = bs4.BeautifulSoup(''/n/n''.join(str(s) for s in sub), ''html.parser'')
print(sub)
>>> <div id="first">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<p>A paragraph.</p>
</div>
<div id="third">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<a href="yet_another_doc.html">A link</a>
</div>
<p id="loner">A paragraph.</p>
Tengo un documento HTML que necesito procesar. Estoy usando ''beautifoulsoup'' para eso. Ahora me gustaría recuperar algunos "subsoups" de ese documento y unirlos en una sola sopa para que luego pueda usarlo como parámetro para una función que espera un objeto de sopa.
Si no está claro, te daré un ejemplo ...
from bs4 import BeautifulSoup
my_document = """
<html>
<body>
<h1>Some Heading</h1>
<div id="first">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<p>A paragraph.</p>
</div>
<div id="second">
<p>A paragraph.</p>
<p>A paragraph.</p>
</div>
<div id="third">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<a href="yet_another_doc.html">A link</a>
</div>
<p id="loner">A paragraph.</p>
</body>
</html>
"""
soup = BeautifulSoup(my_document)
# find the needed parts
first = soup.find("div", {"id": "first"})
third = soup.find("div", {"id": "third"})
loner = soup.find("p", {"id": "loner"})
subsoups = [first, third, loner]
# create a new (sub)soup
resulting_soup = do_some_magic(subsoups)
# use it in a function that expects a soup object and calls its methods
function_expecting_a_soup(resulting_soup)
El objetivo es tener un objeto en resulting_soup
que sea / se comporte como una sopa con el siguiente contenido:
<div id="first">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<p>A paragraph.</p>
</div>
<div id="third">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<a href="yet_another_doc.html">A link</a>
</div>
<p id="loner">A paragraph.</p>
¿Hay una manera conveniente de hacer eso? Si hay una forma mejor de recuperar los "subsoups" que find()
, puedo usarlo en su lugar. Gracias.
Actualizar
Existe una solución recomendada por Wondercricket que concatena cadenas que contienen las etiquetas encontradas y las analiza de nuevo en un nuevo objeto BeautifulSoup. Si bien es una forma posible de resolver el problema, el re-análisis puede llevar más tiempo del que me gustaría, especialmente cuando quiero recuperar la mayoría de ellos y hay muchos documentos que necesito procesar. find()
devuelve un bs4.element.Tag
. ¿No hay una forma de concatenar varias Tag
en una sola sopa sin convertir las Tag
en una cadena y analizar la cadena?
SoupStrainer
haría exactamente lo que estás preguntando y, como SoupStrainer
adicional, obtendrás un aumento en el rendimiento ya que analizará exactamente lo que quieres que analice, no el árbol de documentos completo:
from bs4 import BeautifulSoup, SoupStrainer
parse_only = SoupStrainer(id=["first", "third", "loner"])
soup = BeautifulSoup(my_document, "html.parser", parse_only=parse_only)
Ahora, el objeto soup
contendría solo los elementos deseados:
<div id="first">
<p>
A paragraph.
</p>
<a href="another_doc.html">
A link
</a>
<p>
A paragraph.
</p>
</div>
<div id="third">
<p>
A paragraph.
</p>
<a href="another_doc.html">
A link
</a>
<a href="yet_another_doc.html">
A link
</a>
</div>
<p id="loner">
A paragraph.
</p>
¿También es posible especificar no solo identificadores sino también etiquetas? Por ejemplo, si quiero filtrar todos los párrafos con class = "someclass pero no divs con la misma clase?
En este caso, puede hacer una función de búsqueda para unir múltiples criterios para el SoupStrainer
:
from bs4 import BeautifulSoup, SoupStrainer, ResultSet
my_document = """
<html>
<body>
<h1>Some Heading</h1>
<div id="first">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<p>A paragraph.</p>
</div>
<div id="second">
<p>A paragraph.</p>
<p>A paragraph.</p>
</div>
<div id="third">
<p>A paragraph.</p>
<a href="another_doc.html">A link</a>
<a href="yet_another_doc.html">A link</a>
</div>
<p id="loner">A paragraph.</p>
<p class="myclass">test</p>
</body>
</html>
"""
def search(tag, attrs):
if tag == "p" and "myclass" in attrs.get("class", []):
return tag
if attrs.get("id") in ["first", "third", "loner"]:
return tag
parse_only = SoupStrainer(search)
soup = BeautifulSoup(my_document, "html.parser", parse_only=parse_only)
print(soup.prettify())