ejemplos python html beautifulsoup html-parsing

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())