Cómo raspar Yelp con Python

Comentarios: 0

El scraping de datos de Yelp puede proporcionar información valiosa sobre los restaurantes locales, incluyendo detalles como el nombre, URL, cocinas y calificaciones. Usando las librerías requests y lxml de Python, este tutorial mostrará cómo raspar los resultados de búsqueda de Yelp. Se cubrirán varias técnicas incluyendo el uso de proxies, el manejo de cabeceras y la extracción de datos con XPath.

Paso 1: Configuración del entorno

Antes de comenzar el proceso de scraping, asegúrate de tener instalado Python y las librerías necesarias:

pip install requests
pip install lxml

Estas librerías nos ayudarán a enviar peticiones HTTP a Yelp, analizar el contenido HTML y extraer los datos que necesitamos.

Paso 2: Enviar una petición a Yelp

En primer lugar, tenemos que enviar una solicitud GET a la página de resultados de búsqueda de Yelp para obtener el contenido HTML. He aquí cómo hacerlo:

import requests

# URL de la página de búsqueda de Yelp
url = "https://www.yelp.com/search?find_desc=restaurants&find_loc=San+Francisco%2C+CA"

# Enviar una solicitud GET para obtener el contenido HTML
response = requests.get(url)

# Comprobar si la solicitud se ha realizado correctamente
if response.status_code == 200:
    print("Successfully fetched the page content")
else:
    print("Failed to retrieve the page content")

Entender las cabeceras HTTP

Cuando se realizan peticiones a un sitio web, es esencial incluir las cabeceras HTTP adecuadas. Las cabeceras pueden contener metadatos sobre la solicitud, como el agente de usuario, que identifica el navegador o la herramienta que realiza la solicitud. Incluir estas cabeceras puede ayudar a evitar el bloqueo o estrangulamiento por parte del sitio web de destino.

A continuación te explicamos cómo puedes configurar las cabeceras:

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': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
    '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/127.0.0.0 Safari/537.36',
}

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

Implementación de la rotación de proxy

Cuando se raspa un gran volumen de páginas, existe el riesgo de que su dirección IP sea bloqueada por el sitio de destino. Para evitarlo, se recomienda utilizar servidores proxy. Para esta guía, es aconsejable utilizar servidores proxy dinámicos con rotación automática. De esta manera, sólo tendrá que configurar los ajustes del servidor proxy una vez, y la rotación ayudará a mantener el acceso cambiando periódicamente la dirección IP, reduciendo la probabilidad de ser bloqueado.

proxies = {
    'http': 'http://username:password@proxy-server:port',
    'https': 'https://username:password@proxy-server:port'
}

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

Paso 3: analizar el contenido HTML con lxml

Una vez que tenemos el contenido HTML, el siguiente paso es parsearlo y extraer los datos relevantes. Para ello utilizaremos la librería lxml.

from lxml import html

# Analiza el contenido HTML con lxml
parser = html.fromstring(response.content)

Identificación de los elementos a raspar

Necesitamos apuntar a los listados individuales de restaurantes en la página de resultados de búsqueda. Estos elementos pueden ser identificados usando expresiones XPath. Para Yelp, los listados suelen estar envueltos en un elemento div con un atributo data-testid específico.

# Extraer elementos individuales del restaurante
elements = parser.xpath('//div[@data-testid="serp-ia-card"]')[2:-1]

Uso de XPath para la extracción de datos

XPath es una potente herramienta para navegar y seleccionar nodos de un documento HTML. En este tutorial, utilizaremos expresiones XPath para extraer el nombre del restaurante, la URL, las cocinas y la puntuación de cada elemento restaurante.

Aquí están los XPaths específicos para cada punto de datos:

  1. Nombre del restaurante: .//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/text()
  2. URL del restaurante: .//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/@href
  3. Cocina: .//div[@class="priceCategory__09f24___4Wsg iaPriceCategory__09f24__x9YrM y-css-2hdccn"]/div/div/div/a/button/span/text()
  4. Clasificación: .//div[@class="y-css-9tnml4"]/@aria-label

Paso 4: Extraer los datos de cada listado de restaurantes

Ahora que tenemos el contenido HTML y hemos manejado el posible bloqueo de IP, podemos extraer los datos necesarios de cada listado de restaurantes.

restaurants_data = []

# Iterar sobre cada elemento del restaurante
for element in elements:
    # Extraer el nombre del restaurante
    name = element.xpath('.//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/text()')[0]

    # Extraer la URL del restaurante
    url = element.xpath('.//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/@href')[0]

    # Extraer las cocinas
    cuisines = element.xpath('.//div[@class="priceCategory__09f24___4Wsg iaPriceCategory__09f24__x9YrM y-css-2hdccn"]/div/div/div/a/button/span/text()')

    # Extraer la clasificación
    rating = element.xpath('.//div[@class="y-css-9tnml4"]/@aria-label')[0]

    # Crear un diccionario para almacenar los datos
    restaurant_info = {
        "name": name,
        "url": url,
        "cuisines": cuisines,
        "rating": rating
    }

    # Añadir la información del restaurante a la lista
    restaurants_data.append(restaurant_info)

Paso 5: Guardar los datos como JSON

Después de extraer los datos, necesitamos guardarlos en un formato estructurado. JSON es un formato muy utilizado para este propósito.

import json

# Guardar los datos en un archivo JSON
with open('yelp_restaurants.json', 'w') as f:
    json.dump(restaurants_data, f, indent=4)

print("Data extraction complete. Saved to yelp_restaurants.json")

Código completo

import requests
from lxml import html
import json

# URL de la página de búsqueda de Yelp
url = "https://www.yelp.com/search?find_desc=restaurants&find_loc=San+Francisco%2C+CA"

# Configurar cabeceras para imitar la petición de un navegador
headers = {
    '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',
    'Accept-Language': 'en-US,en;q=0.5'
}

# Configurar proxies si es necesario
proxies = {
    'http': 'http://username:password@proxy-server:port',
    'https': 'https://username:password@proxy-server:port'
}

# Enviar una solicitud GET para obtener el contenido HTML
response = requests.get(url, headers=headers, proxies=proxies)

# Comprobar si la solicitud se ha realizado correctamente
if response.status_code == 200:
    print("Successfully fetched the page content")
else:
    print("Failed to retrieve the page content")

# Analiza el contenido HTML con lxml
parser = html.fromstring(response.content)

# Extraer elementos individuales del restaurante
elements = parser.xpath('//div[@data-testid="serp-ia-card"]')[2:-1]

# Inicializar una lista para contener los datos extraídos
restaurants_data = []

# Iterar sobre cada elemento del restaurante
for element in elements:
    # Extraer el nombre del restaurante
    name = element.xpath('.//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/text()')[0]

    # Extraer la URL del restaurante
    url = element.xpath('.//div[@class="businessName__09f24__HG_pC y-css-ohs7lg"]/div/h3/a/@href')[0]

    # Extraer las cocinas
    cuisines = element.xpath('.//div[@class="priceCategory__09f24___4Wsg iaPriceCategory__09f24__x9YrM y-css-2hdccn"]/div/div/div/a/button/span/text()')

    # Extraer la clasificación
    rating = element.xpath('.//div[@class="y-css-9tnml4"]/@aria-label')[0]

    # Crear un diccionario para almacenar los datos
    restaurant_info = {
        "name": name,
        "url": url,
        "cuisines": cuisines,
        "rating": rating
    }

    # Añadir la información del restaurante a la lista
    restaurants_data.append(restaurant_info)

# Guardar los datos en un archivo JSON
with open('yelp_restaurants.json', 'w') as f:
    json.dump(restaurants_data, f, indent=4)

print("Data extraction complete. Saved to yelp_restaurants.json")

Es fundamental que los usuarios configuren correctamente las cabeceras HTTP y utilicen proxies para eludir las restricciones y evitar el bloqueo. Para una experiencia de scraping optimizada y más segura, considere la posibilidad de automatizar la rotación de IP. El empleo de proxies dinámicos residenciales o móviles puede mejorar significativamente este proceso, reduciendo la probabilidad de ser detectado y bloqueado.

Comentarios:

0 Comentarios