Cómo extraer reseñas de productos de Amazon usando Selenium + Python

Cómo extraer reseñas de productos de Amazon usando Selenium + Python

Python

Durante el trabajo en un proyecto, necesitaba algunos datos de prueba para trabajar. Básicamente, necesitaba reseñas: cortas y largas, positivas y negativas, con estrellas y todas esas cosas agradables. No quería usar datos aleatorios ya que no serían realistas. Así que decidí tomar prestados rápidamente algunos datos de Amazon.

Como no quería pasar demasiado tiempo en esto, mi primer pensamiento fue buscar en Google algunas soluciones o bibliotecas existentes. Encontré docenas de repositorios en GitHub, pero la mayoría estaban desactualizados o no funcionaban en absoluto. También probé la biblioteca Scrapy, pero parece que Amazon tiene alguna protección contra ella y te obliga a iniciar sesión en cada movimiento.

Me rendí y decidí escribir un simple script en Python usando Selenium WebDriver. No es la mejor solución, pero funciona (al menos en 2024), es simple y fácil de entender.

Instalación

Primero, crea un entorno virtual y actívalo:

python -m venv .venv
source .venv/bin/activate

Segundo, instala los paquetes requeridos desde el archivo requirements.txt:

pip install -r requirements.txt

El archivo de requisitos contiene los siguientes paquetes:

selenium
pandas

Necesitamos Selenium para interactuar con el navegador y extraer los datos, y Pandas para almacenar los datos en un DataFrame y en un archivo JSON después.

Script

Aquí está el script que extrae las reseñas de productos de Amazon:

import random
import time
from typing import List
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
import pandas as pd

# URL base del sitio web de Amazon.
base_url = "https://www.amazon.com"
# ASINs de los productos para extraer reseñas.
asins = ['B01N5IB20Q']
# Número de páginas para extraer reseñas. Establece a 0 para extraer todas las reseñas.
pages = 10
# Lista de resultados para almacenar las reseñas extraídas.
result = []

driver = webdriver.Firefox()
driver.maximize_window()
try:
    for asin in asins:
        url = f"{base_url}/product-reviews/{asin}"
        print(f"Extrayendo reseñas para ASIN: {asin}, URL: {url}...")
        driver.get(url)
        page = 1
        
        while page <= pages or pages == 0:
            try:
                # espera aleatoria para comportarse más como un humano
                time.sleep(random.randint(2, 5))
                review_elements: List[WebElement] = driver.find_elements(By.CSS_SELECTOR, "#cm_cr-review_list div.review")
                for review_element in review_elements:
                    verifiedBadgeCnt = len(review_element.find_elements(By.CSS_SELECTOR, "span[data-hook=avp-badge]"))
                    ratingElem = review_element.find_elements(By.CSS_SELECTOR, "*[data-hook=review-star-rating]>span")
                    reviewTitleElem = review_element.find_elements(By.CSS_SELECTOR, "*[data-hook=review-title]>span")
                    reviewLinkElem = review_element.find_elements(By.CSS_SELECTOR, "a[data-hook=review-title]")
                    authorElem = review_element.find_elements(By.CSS_SELECTOR, "span.a-profile-name")
                    locDateElem = review_element.find_elements(By.CSS_SELECTOR, "span[data-hook=review-date]")
                    item = {
                        'asin': asin,
                        'title': reviewTitleElem[1].text if len(reviewTitleElem) > 1 else None,
                        'text': "".join(map(lambda x: x.text, review_element.find_elements(By.CSS_SELECTOR, "span[data-hook=review-body]"))).strip(),
                        'rating': ratingElem[0].get_attribute("textContent") if ratingElem else None,
                        'location_and_date': locDateElem[0].text if locDateElem else None,
                        'verified': bool(verifiedBadgeCnt > 0),
                        'author': authorElem[0].text if authorElem else None,
                        'link': reviewLinkElem[0].get_attribute("href") if reviewLinkElem else None,
                    }
                    result.append(item)
                page += 1
                next_page_element = driver.find_elements(By.CSS_SELECTOR, ".a-pagination .a-last a")
                if next_page_element:
                    next = next_page_element[0]
                    href = next.get_attribute("href")
                    print(f"Haciendo clic en la siguiente página [{href}]")
                    next.click()
            except Exception as e:
                print(f"Error al extraer la página {page} para ASIN {asin}.")
                print(f"Error: {e}")

    print(f"Total de reseñas extraídas: {len(result)}")
    df = pd.DataFrame.from_records(result, columns=['asin', 'title', 'text', 'rating', 'location_and_date', 'verified', 'author', 'link'])
    filename = f"review_{time.strftime('%Y%m%d%H%M%S')}.json"
    df.to_json(filename, orient='records')
    print(f"Guardado en {filename}")
finally:
    driver.quit() 

El script es bastante simple. Extrae reseñas para los ASINs especificados y las guarda en un archivo JSON. Puedes ajustar la lista asins para extraer reseñas de diferentes productos. La variable pages controla el número de páginas de las que se extraerán reseñas. Establécela a 0 para extraer todas las reseñas.

Para ejecutar el script, ejecuta el siguiente comando:

python scrape_amazon_reviews.py

Conclusión

Ahora tienes un simple script en Python para tomar prestadas algunas reseñas de productos de Amazon. Puedes usar estos datos para pruebas, prototipado o fines educativos. Ten en cuenta que extraer datos de sitios web puede ir en contra de sus términos de servicio, así que úsalo responsablemente y no abuses de él. ¡Feliz extracción codificación!