Volver al blog
Guías
Sorin-Gabriel MaricaLast updated on Mar 31, 20267 min read

Extracción y análisis de datos web con Python y BeautifulSoup

Extracción y análisis de datos web con Python y BeautifulSoup

Los rastreadores web son herramientas muy útiles que te ayudan a extraer información específica de un sitio web. En teoría, podrías hacerlo manualmente, pero el rastreo web te permite procesar grandes cantidades de datos de forma más eficiente y productiva.

Uno de los lenguajes de programación más populares para el web scraping es Python. Este lenguaje incluye la biblioteca BeautifulSoup, que simplifica el proceso. Juntos, este dúo hace que el web scraping sea mucho más fácil que en otros lenguajes.

En mi opinión personal, usar BeautifulSoup es la forma más fácil de crear un scraper web sencillo desde cero. Si quieres saber más sobre esto, sigue leyendo porque te mostraré cómo crear tu propio scraper web usando Python y BeautifulSoup.

Una visión general de BeautifulSoup

BeautifulSoup, tal y como se indica en su documentación, es una biblioteca de Python para extraer datos de archivos HTML y XML. Así, puedes usar Python para extraer el contenido HTML de un sitio web y luego usar BeautifulSoup para analizar ese HTML y obtener solo la información relevante.

La principal ventaja de utilizar BeautifulSoup es la sencilla sintaxis que ofrece. Con esta biblioteca, puedes navegar por el árbol DOM, buscar elementos específicos o modificar el contenido HTML. Todas estas ventajas la han convertido en la biblioteca de Python más popular para analizar documentos HTML y XML.

Instalación

Para instalar BeautifulSoup, debes consultar la guía desde aquí, ya que la instalación varía en función del sistema que utilices. En este artículo, estoy utilizando un sistema Linux y solo necesito ejecutar el siguiente comando:

pip install beautifulsoup4

Si utilizas Python 3, es posible que tengas que instalar la biblioteca utilizando el siguiente comando en su lugar:

pip3 install beautifulsoup4

Ten en cuenta que mi máquina ya tiene Python 3 instalado. Si eres nuevo en Python, puedes encontrar una guía sobre cómo instalarlo aquí. Además, deberías consultar nuestra guía definitiva para crear un rastreador web con Python para obtener aún más información sobre el tema.

Creación de un scraper con BeautifulSoup

Ahora, si todo ha ido bien, estamos listos para empezar a crear nuestro propio rastreador. Para este artículo, he decidido recuperar las 100 mejores películas de todos los tiempos de RottenTomatoes y guardarlo todo en formatos JSON y CSV.

Recuperación del código fuente de la página

Para calentar motores y familiarizarnos con BeautifulSoup, primero recuperaremos el HTML completo de la página y lo guardaremos en un nuevo archivo llamado «page.txt».

Si quieres ver el código fuente HTML de cualquier página, puedes hacerlo en Google Chrome pulsando CTRL+U. Esto abrirá una nueva pestaña y verás algo como esto:

Para obtener el mismo código fuente con BeautifulSoup y Python, podemos usar el siguiente código:

import requests
from bs4 import BeautifulSoup

scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)

soup = BeautifulSoup(page.content, 'html.parser')

file = open('page.txt', mode='w', encoding='utf-8')
file.write(soup.prettify())

En este código, enviamos una solicitud a la página de RottenTomatoes y luego añadimos todo el contenido de la página a un objeto BeautifulSoup. El único uso de BeautifulSoup en este ejemplo es la función final llamada «prettify()», que formatea el código HTML para facilitar su lectura.

Para entender mejor la función, para este código HTML «<div><span>Test&lt;/span></div>», prettify añadirá las tabulaciones y lo transformará en este código formateado:

<div>

   <span>

       Test

   </span>

</div>

El resultado final del código es la creación de un archivo llamado page.txt que contiene todo el código fuente de nuestra página:

Debes tener en cuenta que este es el código fuente de la página antes de que se ejecute cualquier código JavaScript. A veces, los sitios web pueden optar por cambiar el contenido de sus páginas de forma dinámica. En estos casos, el código fuente de la página tendrá un aspecto diferente al contenido real que se muestra al usuario. Si necesitas que tu rastreador ejecute JavaScript, puedes leer nuestra guía sobre cómo crear un rastreador web con Selenium, o puedes utilizar WebScrapingAPI, nuestro producto que se encarga de este tema por ti.

Obtención de los datos web

Si miras el código fuente de la página anterior, verás que puedes encontrar los nombres de las películas y su puntuación. Afortunadamente para nosotros, RottenTomatoes no carga la lista de películas de forma dinámica, por lo que podemos seguir adelante y extraer la información necesaria.

En primer lugar, inspeccionamos la página y vemos cómo está estructurado el HTML. Para ello, puedes hacer clic con el botón derecho del ratón sobre el título de una película y seleccionar la opción «Inspeccionar elemento». Debería aparecer la siguiente ventana:

He utilizado la línea roja para resaltar la información útil de esta imagen. Puedes ver que la página muestra las películas más populares en una tabla y que hay cuatro celdas en cada fila de la tabla (elemento <tr>).

La primera celda contiene la posición de la película, la segunda tiene información sobre las valoraciones (elemento con la clase tMeterScore), la tercera incluye el título de la película y la última celda nos da el número de reseñas.

Conociendo esta estructura, ya podemos empezar a extraer la información que necesitamos.

import requests
from bs4 import BeautifulSoup
 
links_base = 'https://www.rottentomatoes.com'
scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)
 
soup = BeautifulSoup(page.content, 'html.parser')
 
table = soup.find("table", class_="table") # We extract just the table code from the entire page
rows = table.findAll("tr") # This will extract each table row, in an array
 
movies = []
 
for index, row in enumerate(rows):
    if index > 0: # We skip the first row since this row only contains the column names
        link = row.find("a") # We get the link from the table row
        rating = row.find(class_="tMeterScore") # We get the element with the class tMeterScore from the table row
        movies.append({
            "link": links_base + link.get('href'), # The href attribute of the link
            "title": link.string.strip(), # The strip function removes blank spaces at the beginning and the end of a string
            "rating": rating.string.strip().replace("&nbsp;", ""), # We remove &nbsp; from the string and the blank spaces
        })
        
print(movies)

Al ejecutar este código, deberías obtener un resultado como este:

En este ejemplo, estamos extrayendo el contenido de la tabla y recorriendo las filas de la tabla. Dado que la primera fila solo contiene los nombres de las columnas, la omitiremos.

En el resto de las filas, continuamos el proceso extrayendo el elemento de anclaje (<a>) y el elemento span con la clase «tMeterScore». Una vez que los tenemos, ya podemos recuperar la información necesaria.

El título de la película se encuentra dentro del elemento de ancla, el enlace es el atributo «href» del ancla y la puntuación se encuentra dentro del elemento span con la clase «tMeterScore». Simplemente creamos un nuevo diccionario para cada fila y lo añadimos a nuestra lista de películas.

Guardar los datos web

Hasta ahora, el scraper ha recuperado y formateado los datos, pero solo los hemos mostrado en la terminal. Como alternativa, podemos guardar la información en nuestro ordenador como JSON o como CSV. El código completo del scraper (incluida la creación de un archivo local) es:

import requests
from bs4 import BeautifulSoup
import csv
import json
 
links_base = 'https://www.rottentomatoes.com'
scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)
 
soup = BeautifulSoup(page.content, 'html.parser')
 
table = soup.find("table", class_="table") # We extract just the table code from the entire page
rows = table.findAll("tr") # This will extract each table row from the table, in an array
 
movies = []
 
for index, row in enumerate(rows):
    if index > 0: # We skip the first row since this row only contains the column names
        link = row.find("a") # We get the link from the table row
        rating = row.find(class_="tMeterScore") # We get the element with the class tMeterScore from the table row
        movies.append({
            "link": links_base + link.get('href'), # The href attribute of the link
            "title": link.string.strip(), # The strip function removes blank spaces at the beginning and the end of a string
            "rating": rating.string.strip().replace("&nbsp;", ""), # We remove &nbsp; from the string and the blank spaces
        })
        
file = open('movies.json', mode='w', encoding='utf-8')
file.write(json.dumps(movies))
 
writer = csv.writer(open("movies.csv", 'w'))
for movie in movies:
    writer.writerow(movie.values())

Raspando aún más

Ahora que tienes toda la información, puedes optar por profundizar en el scraping. Recuerda que cada película tiene un enlace. Podrías continuar raspando las páginas de las películas y extraer aún más información sobre ellas.

Por ejemplo, si consultas la página de la película It Happened One Night (1934), verás que aún puedes extraer información útil, como la puntuación del público, la duración de la película, el género, etc.

Sin embargo, realizar todas estas solicitudes en un breve periodo de tiempo parece muy inusual y podría dar lugar a validaciones CAPTCHA o incluso a bloqueos de IP. Para evitarlo, debes utilizar proxies rotativos para que el tráfico enviado parezca natural y provenga de múltiples IP.

Otras características de BeautifulSoup

Aunque nuestro scraper de RottenTomatoes está completo, BeautifulSoup sigue teniendo mucho que ofrecer. Siempre que trabajes en un proyecto, debes tener abierto el enlace a la documentación para poder buscar rápidamente una solución cuando te quedes atascado.

Por ejemplo, BeautifulSoup permite navegar por el árbol DOM de la página:

from bs4 import BeautifulSoup

soup = BeautifulSoup("<head><title>Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>", 'html.parser')

print(soup.head.title) # Will print "<title>Title</title>"
print(soup.body.div.p.span) # Will print "<span>Span</span>"

Esta característica puede ayudarte cuando necesites seleccionar un elemento que no se pueda identificar por sus atributos. En ese caso, la única forma de encontrarlo es a través de la estructura del DOM.

Otra cosa interesante de BeautifulSoup es que puedes modificar el código fuente de la página:

from bs4 import BeautifulSoup

soup = BeautifulSoup("<head><title>Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>", 'html.parser')

soup.head.title.string = "New Title"
print(soup)
# The line above will print "<head><title>New Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>"

Esto puede ser muy valioso si quieres crear un servicio que permita a los usuarios optimizar sus páginas. Por ejemplo, puedes usar el script para extraer datos de un sitio web, obtener el CSS, minificarlo y sustituirlo en el código fuente HTML. ¡Las posibilidades son infinitas!

Extrae siempre de forma inteligente

Me gustaría que recordaras esto: utilizar Python y BeautifulSoup para el scraping web es una idea excelente. Facilita mucho el proceso en comparación con otros lenguajes de programación.

El rastreador que hemos creado para recuperar las películas mejor valoradas de todos los tiempos de RottenTomatoes se puede programar en solo unos minutos, e incluso puedes utilizarlo junto con el rastreador de IMDB de nuestra guía definitiva para el rastreo con PHP.

Sin embargo, algunos sitios web son más accesibles para los rastreadores que otros. Aunque el proyecto de este artículo es sencillo y divertido, otros no lo son en absoluto. A veces, los sitios web hacen todo lo posible para evitar que se extraiga su contenido.

En ciertas situaciones, la única forma de extraer contenido es enmascarando tu trabajo con múltiples direcciones IP y un navegador real. Para este tipo de situaciones, hemos creado WebScrapingAPI, una potente solución que ofrece proxies rotativos, renderización de JavaScript y te permite extraer datos de cualquier sitio web que desees con el mínimo de complicaciones.

¡No te fíes solo de mi palabra, pruébalo tú mismo! Puedes empezar tu prueba gratuita ahora mismo y obtener 5000 llamadas a la API sin tener que facilitar ningún dato confidencial, como los datos de tu tarjeta de crédito.

Acerca del autor
Sorin-Gabriel Marica, Desarrollador full-stack @ WebScrapingAPI
Sorin-Gabriel MaricaDesarrollador full-stack

Sorin Marica es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.