Web Scraping del Top 250 de Películas de Douban usando Python y BeautifulSoup

Para extraer los datos del listado de las 250 mejores películas de Douban (posición, título, puntuación, frase destacada y enlace), utilizaremos las bibliotecas requests y BeautifulSoup en Python. La URL base implementa paginación mediante el parámetro start, el cual incrementa de 25 en 25: https://movie.douban.com/top250?start=0, start=25, etc.

Antes de escribir el script, es fundamental analizar la estructura HTML de cada elemento en la página. Cada película está encapsulada dentro de un contenedor con la clase item:

<div class="item">
    <div class="pic">
        <em class="">151</em>
        <a href="https://movie.douban.com/subject/24750126/">
            <img width="100" alt="Relatos salvajes" src="...">
        </a>
    </div>
    <div class="info">
        <div class="hd">
            <a href="https://movie.douban.com/subject/24750126/">
                <span class="title">Relatos salvajes</span>
                <span class="title">&nbsp;/&nbsp;Wild Tales</span>
            </a>
        </div>
        <div class="bd">
            <div class="star">
                <span class="rating_num" property="v:average">8.8</span>
            </div>
            <p class="quote">
                <span class="inq">Empieza con lo absurdo y termina en lo surrealista.</span>
            </p>
        </div>
    </div>
</div>

Basándonos en esta estructura, podemos utilizar selectores CSS para localziar los nodos específicos. El siguiente script implementa una extracción robusta, manejando la paginación, añadiendo cabeceras HTTP para evitar bloqueos básicos y gestionando los casos donde la frase destacada (inq) podría estar ausente en el DOM.

import requests
from bs4 import BeautifulSoup
import time

def extraer_top_douban():
    url_base = "https://movie.douban.com/top250"
    encabezados = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    catalogo = []

    with requests.Session() as sesion:
        sesion.headers.update(encabezados)

        # Paginación: 10 páginas, 25 elementos por página
        for offset in range(0, 250, 25):
            parametros = {"start": offset}
            respuesta = sesion.get(url_base, params=parametros)
            sopa = BeautifulSoup(respuesta.text, "html.parser")

            nodos_peliculas = sopa.select("div.item")

            for nodo in nodos_peliculas:
                posicion = nodo.select_one("em").get_text(strip=True)
                titulo = nodo.select_one(".hd a span.title").get_text(strip=True)
                rating = nodo.select_one(".rating_num").get_text(strip=True)
                enlace = nodo.select_one(".hd a")["href"]

                # Manejo de valores nulos para la frase recomendada
                nodo_frase = nodo.select_one(".inq")
                frase = nodo_frase.get_text(strip=True) if nodo_frase else "N/A"

                catalogo.append({
                    "posicion": posicion,
                    "titulo": titulo,
                    "rating": rating,
                    "frase": frase,
                    "url": enlace
                })

            # Pausa para respetar las políticas del servidor
            time.sleep(1.5)

    return catalogo

if __name__ == "__main__":
    datos = extraer_top_douban()
    for pelicula in datos:
        print(f"{pelicula['posicion']}\t{pelicula['titulo']}\t{pelicula['rating']}\t{pelicula['frase']}\t{pelicula['url']}")

Etiquetas: Python BeautifulSoup web-scraping requests html-parsing

Publicado el 6-3 21:50