python - scraping - ¿Cómo evitar que BeautifulSoup4 agregue etiquetas<html><body> adicionales a la sopa?
web scraping python español (2)
Esta pregunta ya tiene una respuesta aquí:
En las versiones de BeautifulSoup anteriores a 3, podría tomar cualquier fragmento de HTML y obtener una representación de cadena de esta manera:
from BeautifulSoup import BeautifulSoup
soup3 = BeautifulSoup(''<div><b>soup 3</b></div>'')
print unicode(soup3)
''<div><b>soup</b></div>''
Sin embargo, con BeautifulSoup4 la misma operación crea etiquetas adicionales:
from bs4 import BeautifulSoup
soup4 = BeautifulSoup(''<div><b>soup 4</b></div>'')
print unicode(soup4)
''<html><body><div><b>soup 4</b></div></body></html>''
^^^^^^^^^^^^ ^^^^^^^^^^^^^^
No necesito las etiquetas externas <html><body>..</body></html>
que BS4 está agregando. He revisado los documentos de BS4 y también busqué dentro de la clase, pero no pude encontrar ninguna configuración para suprimir las etiquetas adicionales en la salida. ¿Cómo lo hago? La degradación a v3 no es una opción ya que el analizador SGML utilizado en BS3 no es tan bueno como los analizadores lxml
o html5lib
que están disponibles con BS4.
Como se señaló en la documentación anterior de BeautifulStoneSoup :
La clase BeautifulSoup está llena de heurísticas similares a un navegador web para adivinar la intención de los autores HTML. Pero XML no tiene un conjunto de etiquetas fijas, por lo que esas heurísticas no se aplican. Así que BeautifulSoup no hace XML muy bien.
Utilice la clase BeautifulStoneSoup para analizar documentos XML. Es una clase general sin conocimiento especial de ningún dialecto XML y reglas muy simples sobre el anidamiento de etiquetas ...
Y en los documentos de BeautifulSoup4 :
Ya no existe una clase BeautifulStoneSoup para analizar XML. Para analizar XML, debe pasar "xml" como segundo argumento al constructor BeautifulSoup. Por la misma razón, el constructor BeautifulSoup ya no reconoce el argumento isHTML.
Tal vez eso cederá lo que quieras.
Si desea que su código funcione en la máquina de todos, sin importar qué analizador (s) hayan instalado, etc. (la misma versión lxml
creada en libxml2
2.9 vs. 2.8 actúa de manera muy diferente, stdlib html.parser
tuvo algunos cambios radicales entre 2.7.2 y 2.7.3, ...), prácticamente necesita manejar todos los resultados legítimos.
Si sabes que tienes un fragmento, algo como esto te dará exactamente ese fragmento:
soup4 = BeautifulSoup(''<div><b>soup 4</b></div>'')
if soup4.body:
return soup4.body.next
elif soup4.html:
return soup4.html.next
else:
return soup4
Por supuesto, si sabe que su fragmento es un solo div
, es aún más fácil, pero no es tan fácil pensar en un caso de uso donde usted sepa que:
soup4 = BeautifulSoup(''<div><b>soup 4</b></div>'')
return soup4.div
Si quieres saber por qué sucede esto:
BeautifulSoup
está diseñado para analizar documentos HTML. Un fragmento HTML no es un documento válido. Está bastante cerca de un documento, pero eso no es lo suficientemente bueno para garantizar que obtendrá exactamente lo que le entregó.
Como dice Diferencias entre analizadores :
También hay diferencias entre los analizadores de HTML. Si le das a Beautiful Soup un documento HTML perfectamente formado, estas diferencias no importarán. Un analizador será más rápido que otro, pero todos le darán una estructura de datos que se ve exactamente como el documento HTML original.
Pero si el documento no está perfectamente formado, diferentes analizadores darán resultados diferentes.
Entonces, si bien esta diferencia exacta no está documentada, es solo un caso especial de algo que sí lo está.