Extracción de datos de anuncios de Airbnb con Python

Comentarios: 0

Acceder a los datos de Airbnb es crucial para analizar el mercado inmobiliario, investigar la dinámica de los precios de alquiler, realizar análisis de la competencia y evaluar reseñas y valoraciones. Esto puede lograrse mediante el scraping de datos web. Sin embargo, acceder a estos datos puede ser complicado, ya que el scraping puede infringir las condiciones de uso del sitio.

A continuación, exploraremos una guía paso a paso sobre cómo desarrollar un raspador web para extraer datos de los listados de Airbnb utilizando Python y Selenium. Esta guía también cubrirá cómo evitar posibles bloqueos y restricciones impuestas por la plataforma.

Entender la arquitectura del sitio web de Airbnb

El primer paso para crear un raspador web es entender cómo acceder a las páginas web que te interesan, ya que la estructura de los sitios web puede cambiar a menudo. Para familiarizarte con la estructura de un sitio, puedes utilizar las herramientas de desarrollo del navegador para inspeccionar el HTML de la página web.

Para acceder a las Herramientas de desarrollo, haga clic con el botón derecho del ratón en la página web y seleccione "Inspeccionar" o utilice el acceso directo:

  • CTRL+SHIFT+I para Windows;
  • Option + ⌘ + I en Mac.

Cada contenedor de listado se envuelve en un elemento div con el siguiente atributo: class="g1qv1ctd".

1.png

Haciendo clic en "ubicación" y escribiendo "Londres, Reino Unido" podemos acceder a la ubicación ofrecida en Londres. El sitio web sugiere añadir las fechas de entrada y salida. Esto les permite calcular el precio de las habitaciones.

2.png

La URL de esta página sería algo parecido a esto:

url = "https://www.airbnb.com/s/London--United-Kingdom/homes?tab_id=home_tab&refinement_paths%5B%5D=%2Fhomes&flexible_trip_lengths%5B%5D=one_week&monthly_start_date=2024-01-01&monthly_length=3&price_filter_input_type=0&channel=EXPLORE&query=London%2C%20United%20Kingdom&place_id=ChIJdd4hrwug2EcRmSrV3Vo6llI&date_picker_type=calendar&source=structured_search_input_header&search_type=autocomplete_click"

Desde la página de búsqueda, rasparemos los siguientes atributos de los datos del listado de productos:

  • URL de la lista;
  • Título;
  • Descripción;
  • Calificación;
  • Precio;
  • Información adicional del anuncio (número de camas y fechas disponibles).

3.png

Guía paso a paso para crear un programa de scraping de Airbnb

Para empezar a raspar datos de Airbnb, primero debe configurar su entorno de desarrollo. Estos son los pasos para hacerlo:

Paso 1: Creación de un entorno virtual

Los entornos virtuales te permiten aislar los paquetes Python y sus dependencias para diferentes proyectos. Esto ayuda a evitar conflictos y garantiza que cada proyecto tenga instaladas las dependencias correctas.

Creación de un entorno virtual en Windows

Abra un símbolo del sistema con privilegios de administrador y ejecute el siguiente comando para crear un nuevo entorno virtual llamado "venv":

python -m venv venv

Active el entorno virtual:

venv\Scripts\activate

Creación de un entorno virtual en macOS/Linux

Abra un terminal y ejecute el siguiente comando para crear un nuevo entorno virtual llamado "venv":

sudo python3 -m venv venv

Active el entorno virtual:

source venv/bin/activate

Para desactivar el entorno virtual, basta con ejecutar el siguiente comando:

deactivate

Paso 2: Instalación de las bibliotecas necesarias

Ahora que ya tienes un entorno virtual configurado, puedes instalar las librerías necesarias.

Comprender las bibliotecas:

  • Selenium: Esta potente herramienta de web scraping te permite controlar mediante programación un navegador web. Esto te permite interactuar con páginas web, incluyendo hacer clic en botones, rellenar formularios y navegar por las páginas como si fueras un usuario real.
  • Seleniumwire: Esta librería extiende Selenium permitiéndote interceptar e inspeccionar peticiones HTTP e integrar proxies con tus operaciones de scraping. Esto es muy importante ya que Selenium no tiene soporte nativo para proxies.
  • BeautifulSoup4: Se trata de una biblioteca diseñada para analizar archivos HTML y XML. Le ayuda a extraer información específica de páginas web de forma estructurada y eficiente.
  • lxml: Un analizador rápido y robusto de HTML y XML que complementa a BeautifulSoup.

En el entorno virtual activado, ejecute el siguiente comando para instalar las bibliotecas necesarias:

pip install selenium beautifulsoup4 lxml seleniumwire

Controladores de selenio

Selenium requiere un controlador para interactuar con el navegador elegido. En esta guía utilizaremos Chrome. Sin embargo, asegúrese de haber instalado el WebDriver adecuado para el navegador de su elección.

Una vez descargado, asegúrese de que el controlador se coloca en un directorio accesible por la variable de entorno PATH de su sistema. Esto permitirá a Selenium encontrar el driver y controlar el navegador.

Paso 3: Importar bibliotecas

Al principio de tu archivo Python, importa las librerías Seleniumwire y BeautifulSoup. Así es como se hace:

from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
import csv
import random

También importaremos las bibliotecas `random`, `time` y `csv` para diversas utilidades.

Paso 4: Integración de proxy

A continuación, definimos una lista de proxies para evitar ser bloqueados por Airbnb. Al intentar enviar una solicitud sin un proxy premium, puede encontrarse con una respuesta de "Acceso denegado".

4.png

Puede configurar un proxy de la siguiente manera:

# Lista de proxies
proxies = [
     "username:password@Your_proxy_IP_Address:Your_proxy_port1",
     "username:password@Your_proxy_IP_Address:Your_proxy_port2",
     "username:password@Your_proxy_IP_Address:Your_proxy_port3",
     "username:password@Your_proxy_IP_Address:Your_proxy_port4",
     "username:password@Your_proxy_IP_Address:Your_proxy_port5",

]

Asegúrese de sustituir "Your_proxy_IP_Address" y "Your_proxy_port" por la dirección proxy real que obtuvo de Proxy-seller y sustituya también los valores de "username" y "password" por sus credenciales reales.

Paso 5: Rotación de proxies

La rotación de proxies es un aspecto crucial del web scraping. Los sitios web suelen bloquear o restringir el acceso a bots y scrapers cuando reciben varias solicitudes desde la misma dirección IP. Rotando a través de diferentes direcciones IP proxy, puedes evitar la detección, aparecer como múltiples usuarios orgánicos y eludir la mayoría de las medidas anti-scraping implementadas en el sitio web.

Para configurar la rotación de proxy, importa la librería "random". También definimos una función `get_proxy()` para seleccionar un proxy de nuestra lista. Esta función selecciona aleatoriamente un proxy de la lista de proxies usando el método random.choice() y devuelve el proxy seleccionado.

def get_proxy():
    return random.choice(proxies)

Paso 6: Configurar WebDriver

A continuación, definimos la función principal llamada `listings()`. Aquí es donde configuraremos nuestro "ChromeDriver". Esta función utiliza Selenium para navegar por la página de listados de propiedades, espera a que la página se cargue y analiza el HTML utilizando Beautiful Soup.

def listings(url):

    proxy = get_proxy()
    proxy_options = {
        "proxy": {
            "http": f"http://{proxy}",
            "https": f"http://{proxy}",
            "no_proxy": "localhost,127.0.0.1",
        }
    }

    chrome_options = Options()
    chrome_options.add_argument("--headless")
  

    s = Service(
        "C:/Path_To_Your_WebDriver"
    )  # Sustituir por su ruta a ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Ajustar en función del tiempo de carga del sitio web

    soup = BeautifulSoup(driver.page_source, "lxml")

    driver.quit()

Aquí, empezamos seleccionando un proxy aleatorio y configurando las opciones del proxy. Estas opciones se utilizarán para configurar el webdriver para utilizar el servidor proxy. A continuación, configuramos las opciones de Chrome. Añade el argumento --headless para ejecutar el navegador en modo headless, lo que significa que el navegador se ejecutará en segundo plano sin interfaz gráfica de usuario.

A continuación, inicialice el webdriver con el servicio, las opciones de seleniumwire y las opciones de Chrome. El webdriver se utiliza entonces para navegar a la URL dada. Añadimos un tiempo de espera de 8 segundos para permitir que la página se cargue completamente, y luego analizamos el HTML devuelto utilizando Beautiful Soup. Una vez finalizado el análisis, se cierra el controlador web.

Paso 7: Buscar y extraer los datos del listado

Una vez obtenido el contenido HTML, el siguiente paso es extraer los datos relevantes de cada anuncio. Con BeautifulSoup, podemos navegar fácilmente por la estructura HTML y localizar los elementos que contienen la información del anuncio.

Extracción de elementos del listado

En primer lugar, identificamos todos los elementos del anuncio en la página. Estos elementos contienen los datos que nos interesan, como la URL del anuncio, el título, la descripción, la valoración, el precio e información adicional.

listing_elements = soup.find_all("div", class_="g1qv1ctd")
for listing_element in listing_elements:

Este código utiliza el método find_all() de BeautifulSoup para localizar todos los elementos div con la clase "g1qv1ctd". Estos elementos representan anuncios individuales en la página de Airbnb. A continuación, realiza un bucle a través de cada uno de estos elementos para extraer los datos pertinentes.

Extracción de la URL del listado

Para cada elemento de listado encontrado, extraemos la URL del listado.

URL_element = soup.find("a", class_="rfexzly")
listing_data["Listing URL"] = (
    "https://www.airbnb.com" + URL_element["href"] if URL_element else ""
)

Aquí, buscamos dentro de nuestro objeto "soup" una etiqueta de anclaje con la clase "rfexzly". Si encuentra este elemento, extrae el atributo "href" (que contiene la URL relativa) y lo añade a la URL base para crear la URL completa del listado. Si no encuentra el elemento, le asigna una cadena vacía para evitar errores.

Extraer el título del anuncio

En primer lugar, extraeremos la URL de cada anuncio. Esto nos permitirá visitar las páginas individuales de los listados más tarde si es necesario.

title_element = listing_element.find("div", class_="t1jojoys")
listing_data["Title"] = (
    title_element.get_text(strip=True) if title_element else ""
)

El título está contenido en un elemento "div" de clase "t1jojoys". Recuperamos el contenido de texto de este elemento, eliminando cualquier espacio en blanco inicial o final. Si no se encuentra el elemento, se almacena una cadena vacía.

Extracción de la descripción del anuncio

Description_element = listing_element.find("span", class_="t6mzqp7")
listing_data["Description"] = (
    Description_element.get_text(strip=True) if Description_element else ""
)

De forma similar a la extracción del título, este código encuentra un elemento span con la clase "t6mzqp7". A continuación, extraemos y limpiamos el contenido de texto de este elemento, que contiene una breve descripción del anuncio.

Extracción de la valoración del listado

rating_element = listing_element.find("span", class_="ru0q88m")
listing_data["Rating"] = (
    rating_element.get_text(strip=True) if rating_element else ""
)

Como se ve en el código anterior, un elemento span con la clase "ru0q88m" contiene el valor de la calificación. Extraemos este valor, asegurándonos de eliminar cualquier espacio en blanco innecesario.

Extraer el precio de venta

Por último, extraemos el precio del anuncio.

price_element = listing_element.select_one("._1y74zjx")
listing_data["Price"] = (
    f"{price_element.get_text(strip=True)} per night" if price_element else ""
)

Este código localiza el elemento con la clase "_1y74zjx" dentro del elemento_listado actual. Si se encuentra este elemento, que normalmente contiene la información sobre el precio, se extrae su contenido de texto, se limpia y se le añade "por noche" para formar una cadena de precios más informativa.

Extraer información adicional del listado

Algunos listados pueden contener información adicional que podemos extraer.

listing_info_element = listing_element.find("span", {"aria-hidden": "true"})
listing_data["Additional Listing information"] = (
    listing_info_element.get_text(strip=True) if listing_info_element else ""
)

Buscamos un elemento span con el atributo aria-hidden="true" para encontrar cualquier información adicional sobre el anuncio. Una vez extraídos todos los datos relevantes de cada elemento del anuncio, los añadimos a una lista de anuncios.

listings.append(listing_data)

Una vez procesados todos los listados, devolvemos la lista de listados, cada uno representado como un diccionario que contiene los datos extraídos.

return listings

Paso 8: Escribir los datos en un archivo CSV

Después de extraer con éxito los datos de las páginas de listados de Airbnb, el siguiente paso importante es almacenar esta valiosa información para futuros análisis y referencias. Para ello utilizamos la biblioteca csv. Abrimos un archivo CSV en modo de escritura y creamos un objeto csv.DictWriter. A continuación, escribimos la cabecera y los datos en el archivo.

airbnb_listings = listings(url)

csv_file_path = "proxy_web_listings_output.csv"

with open(csv_file_path, "w", encoding="utf-8", newline="") as csv_file:
    fieldnames = [
        "Listing URL",
        "Title",
        "Description",
        "Rating",
        "Price",
        "Additional Listing information",
    ]
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    for listing in airbnb_listings:
        writer.writerow(listing)

print(f"Data has been exported to {csv_file_path}")

Aquí está el código completo que utilizamos para este tutorial:

from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
import csv
import random

# Lista de proxies
proxies = [ 
 "username:password@Your_proxy_IP_Address:Your_proxy_port1",
 "username:password@Your_proxy_IP_Address:Your_proxy_port2",
 "username:password@Your_proxy_IP_Address:Your_proxy_port3",
 "username:password@Your_proxy_IP_Address:Your_proxy_port4",
 "username:password@Your_proxy_IP_Address:Your_proxy_port5",
]

def get_proxy():
    return random.choice(proxies)


def listings(url):

    proxy = get_proxy()
    proxy_options = {
        "proxy": {
            "http": f"http://{proxy}",
            "https": f"http://{proxy}",
            "no_proxy": "localhost,127.0.0.1",
        }
    }

    chrome_options = Options()
    chrome_options.add_argument("--headless")
  

    s = Service(
        "C:/Path_To_Your_WebDriver"
    )  # Sustitúyalo por su ruta a ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Ajuste basado en el tiempo de carga del sitio web

    soup = BeautifulSoup(driver.page_source, "lxml")

    driver.quit()

    listings = []

    # Encontrar todos los elementos del listado en la página
    listing_elements = soup.find_all("div", class_="g1qv1ctd")

    for listing_element in listing_elements:
        # Extraer datos de cada elemento del listado
        listing_data = {}

        # Listado URL
        URL_element = soup.find("a", class_="rfexzly")
        listing_data["Listing URL"] = (
            "https://www.airbnb.com" + URL_element["href"] if URL_element else ""
        )

        # Título
        title_element = listing_element.find("div", class_="t1jojoys")
        listing_data["Title"] = (
            title_element.get_text(strip=True) if title_element else ""
        )

        # Descripción
        Description_element = listing_element.find("span", class_="t6mzqp7")
        listing_data["Description"] = (
            Description_element.get_text(strip=True) if Description_element else ""
        )

        # Calificación
        rating_element = listing_element.find("span", class_="ru0q88m")
        listing_data["Rating"] = (
            rating_element.get_text(strip=True) if rating_element else ""
        )

        # Precio
        price_element = listing_element.select_one("._1y74zjx")
        listing_data["Price"] = (
            f"{price_element.get_text(strip=True)} per night" if price_element else ""
        )

        # Additional listing info
        listing_info_element = listing_element.find("span", {"aria-hidden": "true"})
        listing_data["Additional Listing information"] = (
            listing_info_element.get_text(strip=True) if listing_info_element else ""
        )

        # Añade los datos del listado a la lista
        listings.append(listing_data)

    return listings


url = "https://www.airbnb.com/s/London--United-Kingdom/homes?tab_id=home_tab&refinement_paths%5B%5D=%2Fhomes&flexible_trip_lengths%5B%5D=one_week&monthly_start_date=2024-01-01&monthly_length=3&price_filter_input_type=0&channel=EXPLORE&query=London%2C%20United%20Kingdom&place_id=ChIJdd4hrwug2EcRmSrV3Vo6llI&date_picker_type=calendar&source=structured_search_input_header&search_type=autocomplete_click"


airbnb_listings = listings(url)

csv_file_path = "proxy_web_listings_output.csv"

with open(csv_file_path, "w", encoding="utf-8", newline="") as csv_file:
    fieldnames = [
        "Listing URL",
        "Title",
        "Description",
        "Rating",
        "Price",
        "Additional Listing information",
    ]
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    for listing in airbnb_listings:
        writer.writerow(listing)

print(f"Data has been exported to {csv_file_path}")

Esta parte del código garantiza que los datos obtenidos se almacenen en un archivo CSV denominado "proxy_web_listings_output.csv".

Resultados

Los resultados de nuestro scraper se guardan en un archivo CSV llamado "proxy_web_listings_output.csv" como se ve a continuación.

5.jpg

Esta guía explica eficazmente cómo extraer datos de los listados de Airbnb utilizando Python, lo que permite extraer detalles clave como precios, disponibilidad y opiniones. Destaca la importancia de utilizar proxies y rotarlos para evitar ser bloqueado por las medidas anti-bot de Airbnb.

Comentarios:

0 Comentarios