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"> / 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']}")