Cómo raspar páginas web en Python con una hermosa sopa Búsqueda y modificación de DOM

En el último tutorial, aprendiste los conceptos básicos de la biblioteca Beautiful Soup. Además de navegar por el árbol DOM, también puede buscar elementos con un determinado clase o carné de identidad. También puede modificar el árbol DOM usando esta biblioteca. 

En este tutorial, aprenderá sobre los diferentes métodos que lo ayudarán con la búsqueda y las modificaciones. Estaremos raspando la misma página de Wikipedia sobre Python de nuestro último tutorial.

Filtros para buscar el árbol

Beautiful Soup tiene muchos métodos para buscar en el árbol DOM. Estos métodos son muy similares y toman los mismos tipos de filtros que los argumentos. Por lo tanto, tiene sentido entender correctamente los diferentes filtros antes de leer sobre los métodos. Yo estare usando el mismo encuentra todos() Método para explicar la diferencia entre diferentes filtros..

El filtro más simple que puede pasar a cualquier método de búsqueda es una cadena. Beautiful Soup buscará en el documento para encontrar una etiqueta que coincida exactamente con la cadena.

para encabezar en soup.find_all ('h2'): print (heading.text) # Contenido # Historia [editar] # Características y filosofía [editar] # Sintaxis y semántica [editar] # Bibliotecas [editar] # Entornos de desarrollo [editar] #… y así.

También puede pasar un objeto de expresión regular a la encuentra todos() método. Esta vez, Beautiful Soup filtrará el árbol al comparar todas las etiquetas con una expresión regular dada.

importar para el encabezado en soup.find_all (re.compile ("^ h [1-6]")): print (heading.name + "+ heading.text.strip ()) # h1 Python (lenguaje de programación) # h2 Contenido # h2 Historial [editar] # h2 Características y filosofía [editar] # h2 Sintaxis y semántica [editar] # h3 Indentación [editar] # h3 Declaraciones y flujo de control [editar] #… y así sucesivamente.

El código buscará todas las etiquetas que comienzan con "h" y van seguidas de un dígito del 1 al 6. En otras palabras, buscará todas las etiquetas de encabezado en el documento.

En lugar de usar expresiones regulares, puede obtener el mismo resultado al pasar una lista de todas las etiquetas que desea que Beautiful Soup haga coincidir con el documento.

para el encabezado en soup.find_all (["h1", "h2", "h3", "h4", "h5", "h6"]): print (heading.name + "+ heading.text.strip ())

También puedes pasar Cierto como parámetro a la encuentra todos() método. El código devolverá todas las etiquetas en el documento. El resultado a continuación significa que actualmente hay 4,339 etiquetas en la página de Wikipedia que estamos analizando.

len (soup.find_all (Verdadero)) # 4339

Si aún no puede encontrar lo que está buscando con cualquiera de los filtros anteriores, puede definir su propia función que toma un elemento como único argumento. La función también necesita volver. Cierto si hay un partido y Falso de otra manera. Dependiendo de lo que necesite, puede hacer que la función sea tan complicada como debe ser para hacer el trabajo. Aquí hay un ejemplo muy simple:

def big_lists (tag): return len (tag.contents)> 20 y tag.name == 'ul' len (soup.find_all (big_lists)) # 13

La función anterior pasa por la misma página de Wikipedia Python y busca listas desordenadas que tienen más de 20 niños.

Buscando el árbol DOM usando funciones incorporadas

Uno de los métodos más populares para buscar a través del DOM es encuentra todos(). Pasará por todos los descendientes de la etiqueta y devolverá una lista de todos los descendientes que coincidan con sus criterios de búsqueda. Este método tiene la siguiente firma:

find_all (nombre, attrs, recursivo, cadena, límite, ** kwargs)

los nombre argumento es el nombre de la etiqueta que desea que esta función busque mientras atraviesa el árbol. Tiene la libertad de proporcionar una cadena, una lista, una expresión regular, una función o el valor Cierto como un nombre.

También puede filtrar los elementos en el árbol DOM en base a diferentes atributos como carné de identidad, href, etc. También puede obtener todos los elementos con un atributo específico independientemente de su valor usando atributo = Verdadero. La búsqueda de elementos con una clase específica es diferente de la búsqueda de atributos regulares. Ya que clase es una palabra clave reservada en Python, tendrá que usar el clase_ argumento de palabra clave cuando se buscan elementos con una clase específica.

import re len (soup.find_all (id = True)) # 425 len (soup.find_all (class_ = True)) # 1734 len (soup.find_all (class _ = "mw-headline")) # 20 len (soup.find_all (href = Verdadero)) # 1410 len (soup.find_all (href = re.compile ("python"))) # 102

Puedes ver que el documento tiene 1,734 tags con un clase atributo y 425 etiquetas con una carné de identidad atributo. Si solo necesita los primeros resultados, puede pasar un número al método como el valor de límite. Pasar este valor indicará a Beautiful Soup que deje de buscar más elementos una vez que haya alcanzado un cierto número. Aquí hay un ejemplo:

soup.find_all (class _ = "mw-headline", limit = 4) # Historia # Caracteristicas y filosofia # Sintaxis y semantica # Sangría

Cuando usas el encuentra todos() Método, le está diciendo a Beautiful Soup que pase por todos los descendientes de una etiqueta determinada para encontrar lo que está buscando. A veces, desea buscar un elemento solo en los hijos directos de una etiqueta. Esto se puede lograr pasando recursivo = falso al encuentra todos() método.

len (soup.html.find_all ("meta")) # 6 len (soup.html.find_all ("meta", recursive = False)) # 0 len (soup.head.find_all ("meta", recursive = False) ) # 6

Si está interesado en encontrar solo un resultado para una consulta de búsqueda en particular, puede usar el encontrar() Método para encontrarlo en lugar de pasar. límite = 1 a encuentra todos(). La única diferencia entre los resultados devueltos por estos dos métodos es que encuentra todos() devuelve una lista con un solo elemento y encontrar() solo devuelve el resultado.

soup.find_all ("h2", limit = 1) # [

Contenido

] soup.find ("h2") #

Contenido

los encontrar() y encuentra todos() Los métodos buscan a través de todos los descendientes de una etiqueta dada para buscar un elemento. Hay otros diez métodos muy similares que puede utilizar para recorrer en iteración el árbol DOM en diferentes direcciones..

find_parents (name, attrs, string, limit, ** kwargs) find_parent (name, attrs, string, ** kwargs) find_next_siblings (name, attrs, string, limit, ** kwargs) find_next_sibling (name, attrs, string, ** kwargs) find_previous_siblings (name, attrs, string, limit, ** kwargs) find_previous_sibling (name, attrs, string, ** kwargs) find_all_next (name, attrs, string, limit, ** kwargs) find_next (name, attrs, string, ** kwargs) find_all_previous (nombre, attrs, cadena, límite, ** kwargs) find_previous (nombre, attrs, cadena, ** kwargs)

los buscar_parente () y buscar_parentes () Los métodos atraviesan el árbol DOM para encontrar el elemento dado. los find_next_sibling ()find_next_siblings () Los métodos iterarán sobre todos los hermanos del elemento que vienen después del actual. Del mismo modo, el find_previous_sibling () y find_previous_siblings () Los métodos iterarán sobre todos los hermanos del elemento que precede al actual..

los buscar_next () y find_all_next () los métodos iterarán sobre todas las etiquetas y cadenas que vienen después del elemento actual. Del mismo modo, el find_previous () y find_all_previous () los métodos iterarán sobre todas las etiquetas y cadenas que vienen antes del elemento actual.

También puede buscar elementos utilizando los selectores de CSS con la ayuda de seleccionar() método. Aquí están algunos ejemplos:

len (soup.select ("p a")) # 411 len (soup.select ("p> a")) # 291 soup.select ("h2: nth-of-type (1)") # [

Contenido

] len (soup.select ("p> a: nth-of-type (2)")) # 46 len (soup.select ("p> a: nth-of-type (10)")) # 6 len (soup.select ("[class * = section]")) # 80 len (soup.select ("[class $ = section]")) # 20

Modificando el arbol

No solo puede buscar a través del árbol DOM para encontrar un elemento, sino también modificarlo. Es muy fácil cambiar el nombre de una etiqueta y modificar sus atributos.

heading_tag = soup.select ("h2: nth-of-type (2)") [0] heading_tag.name = "h3" print (heading_tag) # 

Feat ... heading_tag ['class'] = 'headingChanged' print (heading_tag) #

Continuando con nuestro último ejemplo, puede reemplazar el contenido de una etiqueta con una cadena dada usando la .cuerda atributo. Si no desea reemplazar el contenido pero agrega algo adicional al final de la etiqueta, puede usar la adjuntar() método. 

Del mismo modo, si desea insertar algo dentro de una etiqueta en una ubicación específica, puede usar la insertar() método. El primer parámetro para este método es la posición o el índice en el que desea insertar el contenido, y el segundo parámetro es el contenido en sí. Puede eliminar todo el contenido dentro de una etiqueta usando la claro() método. Esto te dejará con la etiqueta y sus atributos..

heading_tag.string = Impresión de "Características y Filosofía" (heading_tag) # 

Características y filosofía

heading_tag.append ("[Adjunto esta parte].") print (heading_tag) #

Características y filosofía [adjunto esta parte].

print (heading_tag.contents) # ['Features and Philosophy', '[Addended This Part].'] heading_tag.insert (1, 'Inserts this part') print (heading_tag) #

Características y filosofía Insertó esta parte [Se adjunta esta parte].

heading_tag.clear () imprimir (heading_tag) #

Al comienzo de esta sección, seleccionó un encabezado de nivel dos del documento y lo cambió a un encabezado de nivel tres. Volver a usar el mismo selector ahora le mostrará el siguiente encabezado de nivel dos que vino después del original. Esto tiene sentido porque el encabezado original ya no es un encabezado de nivel dos. 

El encabezado original ahora se puede seleccionar usando h3: nth-of-type (2). Si desea eliminar por completo un elemento o etiqueta y todo el contenido que contiene dentro del árbol, puede usar descomponer() método.

soup.select ("h3: nth-of-type (2)") [0] #  soup.select ("h3: nth-of-type (3)") [0] # 

Sangría... soup.select ("h3: nth-of-type (2)") [0] .decompose () soup.select ("h3: nth-of-type (2)") [0] #

Sangría...

Una vez que haya descompuesto o quitado el encabezado original, el encabezado en el tercer lugar toma su lugar..

Si desea eliminar una etiqueta y su contenido del árbol, pero no quiere destruirla por completo, puede usar la extraer() método. Este método devolverá la etiqueta que extrajo. Ahora tendrás dos árboles diferentes que puedes analizar. La raíz del nuevo árbol será la etiqueta que acaba de extraer..

heading_tree = soup.select ("h3: nth-of-type (2)") [0] .extract () len (heading_tree.contents) # 2

También puede reemplazar una etiqueta dentro del árbol con otra cosa de su elección usando el reemplazar con() método. Este método devolverá la etiqueta o cadena que reemplazó. Puede ser útil si desea colocar el contenido reemplazado en otro lugar del documento..

soup.h1 # 

Python (lenguaje de programación)

bold_tag ​​= soup.new_tag ("b") bold_tag.string = "Python" soup.h1.replace_with (bold_tag) print (soup.h1) # Ninguno print (soup.b) # Pitón

En el código anterior, el encabezado principal del documento ha sido reemplazado por un segundo etiqueta. El documento ya no tiene una h1 etiqueta, y es por eso imprimir (soup.h1) ahora imprime Ninguna.

Pensamientos finales

Después de leer los dos tutoriales de esta serie, ahora debería poder analizar diferentes páginas web y extraer datos importantes del documento. También debe poder recuperar la página web original, modificarla para que se ajuste a sus propias necesidades y guardar la versión modificada localmente.

Si tiene alguna pregunta sobre este tutorial, hágamelo saber en los comentarios..