Cómo extraer datos de Booking.com con Python

Comentarios: 0

En este artículo, demostraremos cómo recopilar datos del sitio web Booking.com con Python. Obtendremos información que incluye, entre otros, nombres de hoteles, valoraciones, precios, direcciones de ubicación y sus descripciones. El código proporcionado permite recuperar datos de las páginas de los hoteles analizando el contenido HTML y extrayendo los datos JSON incrustados.

Instalación de las librerías necesarias

Antes de ejecutar el código para scrapear datos de Booking.com, necesitarás instalar las librerías Python necesarias. Aquí te explicamos cómo puedes instalar las dependencias necesarias:

  1. Requests Biblioteca: Se utiliza para enviar peticiones HTTP al sitio web y obtener el contenido HTML de las páginas.
  2. LXML Biblioteca: Se utiliza para analizar el contenido HTML y extraer datos utilizando XPath.
  3. JSON: Módulo incorporado de Python utilizado para manejar datos JSON.
  4. CSV: Módulo de Python integrado para escribir los datos raspados en un archivo CSV.

Para instalar las bibliotecas necesarias, puede utilizar pip:


pip install requests lxml

Estas son las únicas librerías externas que necesitas, y el resto (json, csv) vienen preinstaladas con Python.

Entendiendo la URL y la estructura de datos

A la hora de scrapear datos de Booking.com, es importante entender la estructura de la página web y el tipo de datos que quieres extraer. Cada página de hotel en Booking.com contiene datos estructurados incrustados en forma de JSON-LD, un formato que permite extraer fácilmente detalles como el nombre, la ubicación y el precio. Vamos a raspar estos datos.

Proceso de raspado paso a paso

Dado que Booking.com es un sitio dinámico e implementa medidas para combatir las acciones automatizadas, utilizaremos cabeceras HTTP y proxies adecuados para garantizar un scraping fluido sin riesgo de bloqueo.

Envío de solicitudes HTTP con cabeceras

Las cabeceras imitan una sesión de usuario en un navegador y evitan la detección por parte de los sistemas anti-scraping de Booking.com. Sin unas cabeceras bien configuradas, el servidor puede identificar fácilmente los scripts automatizados, lo que puede provocar bloqueos de IP o retos de captcha.

Para evitar ser bloqueados por los mecanismos anti-scraping de Booking.com, utilizaremos cabeceras personalizadas para simular un usuario legítimo navegando por el sitio web. A continuación te explicamos cómo enviar una petición HTTP con las cabeceras adecuadas:


import requests
from lxml.html import fromstring

urls_list = ["https links"]

for url in urls_list:
    headers = {
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'en-IN,en;q=0.9',
        'cache-control': 'no-cache',
        'dnt': '1',
        'pragma': 'no-cache',
        'priority': 'u=0, i',
        'sec-ch-ua': '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Linux"',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-site': 'none',
        'sec-fetch-user': '?1',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
    }

    response = requests.get(url, headers=headers)

Importancia de los proxies

El uso de proxies es necesario cuando se scrapean sitios como Booking.com, que aplican estrictos límites de tasa de peticiones o rastrean direcciones IP. Los proxies ayudan a distribuir la carga de peticiones entre diferentes direcciones IP, evitando bloqueos. Para ello, se pueden utilizar tanto proxies gratuitos como servicios proxy de pago con autenticación por nombre de usuario y contraseña o dirección IP. En nuestro ejemplo, utilizamos esta última opción.


proxies = {
    'http': '',
    'https': ''
}
response = requests.get(url, headers=headers, proxies=proxies)

Parear el HTML y extraer los datos JSON

Después de enviar la solicitud, analizamos el contenido HTML utilizando lxml para localizar los datos JSON-LD incrustados que contienen detalles del hotel. Este paso extrae los datos estructurados de la página web que incluyen nombres de hoteles, precios, ubicaciones y más.


parser = fromstring(response.text)

# Extraer datos JSON incrustados
embeded_jsons = parser.xpath('//script[@type="application/ld+json"]/text()')
json_data = json.loads(embeded_jsons[0])

Extracción de información sobre hoteles

Una vez que tenemos los datos JSON parseados, podemos extraer campos relevantes como el nombre del hotel, la dirección, la valoración y el precio. A continuación se muestra el código para extraer la información del hotel desde el JSON:


name = json_data['name']
location = json_data['hasMap']
priceRange = json_data['priceRange']
description = json_data['description']
url = json_data['url']
ratingValue = json_data['aggregateRating']['ratingValue']
reviewCount = json_data['aggregateRating']['reviewCount']
type_ = json_data['@type']
postalCode = json_data['address']['postalCode']
addressLocality = json_data['address']['addressLocality']
addressCountry = json_data['address']['addressCountry']
addressRegion = json_data['address']['addressRegion']
streetAddress = json_data['address']['streetAddress']
image_url = json_data['image']
room_types = parser.xpath("//a[contains(@href, '#RD')]/span/text()")

# Añade los datos a la lista all_data
all_data.append({
    "Name": name,
    "Location": location,
    "Price Range": priceRange,
    "Rating": ratingValue,
    "Review Count": reviewCount,
    "Type": type_,
    "Postal Code": postalCode,
    "Address Locality": addressLocality,
    "Country": addressCountry,
    "Region": addressRegion,
    "Street Address": streetAddress,
    "URL": url,
    "Image URL": image_url,
    "Room Types": room_types
})

Guardar los datos en CSV

Una vez extraídos los datos, podemos guardarlos en un archivo CSV para su posterior análisis:


# Una vez procesadas todas las URL, escriba los datos en un archivo CSV
with open('booking_data.csv', 'w', newline='') as csvfile:
    fieldnames = ["Name", "Location", "Price Range", "Rating", "Review Count", "Type", "Postal Code", 
                  "Address Locality", "Country", "Region", "Street Address", "URL", "Image URL", "Room Types"]
    
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    
    # Escribir la cabecera
    writer.writeheader()
    
    # Escribir las filas de datos
    writer.writerows(all_data)

Código completo

Aquí está el código completo combinando todas las secciones:


import requests
from lxml.html import fromstring
import json
import csv

# Lista de URL de hoteles que se van a raspar
urls_list = [
    "Https link", 
    "Https link"
]

# Inicializar una lista vacía para contener todos los datos raspados
all_data = []

proxies = {
    'http': ''
}

# Recorre cada URL para extraer datos
for url in urls_list:
    headers = {
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'en-IN,en;q=0.9',
        'cache-control': 'no-cache',
        'dnt': '1',
        'pragma': 'no-cache',
        'priority': 'u=0, i',
        'sec-ch-ua': '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Linux"',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-site': 'none',
        'sec-fetch-user': '?1',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
    }

    # Envío de la solicitud al sitio web
    response = requests.get(url, headers=headers, proxies=proxies)
    
    # Análisis del contenido HTML
    parser = fromstring(response.text)
    
    # Extraer datos JSON incrustados
    embeded_jsons = parser.xpath('//script[@type="application/ld+json"]/text()')
    json_data = json.loads(embeded_jsons[0])

    # Extraer todos los detalles del hotel de JSON
    name = json_data['name']
    location = json_data['hasMap']
    priceRange = json_data['priceRange']
    description = json_data['description']
    url = json_data['url']
    ratingValue = json_data['aggregateRating']['ratingValue']
    reviewCount = json_data['aggregateRating']['reviewCount']
    type_ = json_data['@type']
    postalCode = json_data['address']['postalCode']
    addressLocality = json_data['address']['addressLocality']
    addressCountry = json_data['address']['addressCountry']
    addressRegion = json_data['address']['addressRegion']
    streetAddress = json_data['address']['streetAddress']
    image_url = json_data['image']

    room_types = parser.xpath("//a[contains(@href, '#RD')]/span/text()")
    
    # Añade los datos a la lista all_data
    all_data.append({
        "Name": name,
        "Location": location,
        "Price Range": priceRange,
        "Rating": ratingValue,
        "Review Count": reviewCount,
        "Type": type_,
        "Postal Code": postalCode,
        "Address Locality": addressLocality,
        "Country": addressCountry,
        "Region": addressRegion,
        "Street Address": streetAddress,
        "URL": url,
        "Image URL": image_url,
        "Room Types": room_types
    })

# Una vez procesadas todas las URL, escriba los datos en un archivo CSV
with open('booking_data.csv', 'w', newline='') as csvfile:
    fieldnames = ["Name", "Location", "Price Range", "Rating", "Review Count", "Type", "Postal Code", 
                  "Address Locality", "Country", "Region", "Street Address", "URL", "Image URL", "Room Types"]
    
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    
    # Escribir la cabecera
    writer.writeheader()
    
    # Escribir las filas de datos
    writer.writerows(all_data)

print("Data successfully saved to booking_data.csv")

Este artículo mostraba cómo scrapear datos de hoteles de Booking.com usando Python. Hicimos hincapié en la importancia de utilizar cabeceras HTTP y proxies adecuados para eludir las medidas anti-scraping. Los datos extraídos se pueden guardar en un archivo CSV para su posterior análisis. Al hacer scraping de sitios web, comprueba siempre las condiciones del servicio para evitar infringirlas.

Comentarios:

0 Comentarios