Cómo scrapear reseñas de productos a escala con proxies

Aprende a raspar reseñas de productos de Amazon y otras plataformas a escala. Código Python y Node.js para la colección de revisión multiplataforma, manejo de paginaciones y preparación de análisis de sentimientos.

Cómo scrapear reseñas de productos a escala con proxies

¿Por qué Scrape Comentarios de Productos en Scale?

Las reseñas de productos son una de las fuentes de datos más valiosas del comercio electrónico. Ellos revelan el sentimiento del cliente, problemas de calidad de producto, solicitudes de características y posicionamiento competitivo - información que ninguna otra fuente de datos puede proporcionar. A escala, los datos de revisión permiten:

  • Análisis de la sensibilidad: Seguimiento de cómo se sienten los clientes sobre sus productos y productos de los competidores con el tiempo.
  • Desarrollo de productos: Identificar quejas recurrentes y presentar peticiones en miles de exámenes.
  • Inteligencia competitiva: Comprender las fortalezas y debilidades de los competidores de sus propias palabras.
  • Investigación del mercado: Descubra las necesidades no satisfechas y las tendencias emergentes analizando patrones de revisión en distintas categorías.
  • Supervisión de calidad: Detectar problemas de calidad de los productos rápidamente mediante la vigilancia de las tendencias sentimentales de revisión.

El reto es que los datos de revisión se difunden a través de múltiples plataformas (Amazon, Walmart, Best Buy, Trustpilot, Google), cada una con diferentes estructuras y protecciones antibot. Los exámenes a escala requieren estrategias específicas de plataforma e infraestructura proxy robusta. Para patrones de raspado de comercio electrónico fundamental, vea nuestra Guía de intercambio electrónico de datos.

Review Data Structure Across Platforms

Review Data Structure Across Platforms
PlataformaReview FieldsPaginationAnti-Bot Level
AmazonValoración, título, texto, fecha, verificado, votos útilesPage-based (10/page)Alto
WalmartValoración, título, texto, fecha, fuente de presentaciónAPI basada en activosMediana
Mejor compraValoración, título, texto, fecha, útil/sin ayudaAPI basada en la páginaMediana
TrustpilotValoración, título, texto, fecha, respuestaBasado en la páginaLow-Medium
Google ShoppingValoración, texto, fecha, fuenteScroll-basedAlto

Configuración proxy para el cambio de revisión

El desguace de la revisión implica la navegación paginada, lo que significa mantener sesiones a través de múltiples solicitudes. Las sesiones pegajosas de ProxyHat son ideales para este patrón.

Configuración ProxyHat

# Per-request rotation for initial product lookups
http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# Sticky session for paginating through reviews of one product
http://USERNAME-session-rev001:PASSWORD@gate.proxyhat.com:8080
# Geo-targeted for region-specific review pages
http://USERNAME-country-US:PASSWORD@gate.proxyhat.com:8080

Para revisar el desguace, utilice sesiones pegajosas al paginar a través de todas las opiniones para un solo producto, y la rotación por solicitud al moverse entre diferentes productos. Este imita el comportamiento de navegación natural donde un usuario lee múltiples páginas de reseñas para un producto antes de moverse a la siguiente.

Python Implementation

Aquí hay un raspador de revisión multiplataforma utilizando El SDK Python de ProxyHat.

Amazon Review Scraper

import requests
from bs4 import BeautifulSoup
import json
import time
import random
from dataclasses import dataclass
from datetime import datetime
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
]
@dataclass
class Review:
    platform: str
    product_id: str
    rating: float
    title: str
    text: str
    date: str
    author: str
    verified: bool
    helpful_votes: int
def scrape_amazon_reviews(asin, max_pages=10):
    """Scrape all reviews for an Amazon product."""
    reviews = []
    session_id = f"rev-{asin}-{random.randint(1000, 9999)}"
    proxy = f"http://USERNAME-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
    session = requests.Session()
    session.proxies = {"http": proxy, "https": proxy}
    session.headers.update({
        "User-Agent": random.choice(USER_AGENTS),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    })
    for page in range(1, max_pages + 1):
        url = (f"https://www.amazon.com/product-reviews/{asin}"
               f"?pageNumber={page}&sortBy=recent")
        try:
            response = session.get(url, timeout=30)
            if response.status_code != 200:
                break
            if "captcha" in response.text.lower():
                print(f"CAPTCHA on page {page}, switching session")
                break
            soup = BeautifulSoup(response.text, "html.parser")
            review_divs = soup.find_all("div", {"data-hook": "review"})
            if not review_divs:
                break
            for div in review_divs:
                review = parse_amazon_review(div, asin)
                if review:
                    reviews.append(review)
            print(f"Page {page}: {len(review_divs)} reviews (total: {len(reviews)})")
            time.sleep(random.uniform(2, 5))
        except requests.RequestException as e:
            print(f"Error on page {page}: {e}")
            break
    return reviews
def parse_amazon_review(div, asin):
    """Parse a single Amazon review element."""
    try:
        rating_el = div.find("i", {"data-hook": "review-star-rating"})
        rating = float(rating_el.get_text().split(" ")[0]) if rating_el else None
        title_el = div.find("a", {"data-hook": "review-title"})
        title = title_el.get_text(strip=True) if title_el else ""
        body_el = div.find("span", {"data-hook": "review-body"})
        text = body_el.get_text(strip=True) if body_el else ""
        date_el = div.find("span", {"data-hook": "review-date"})
        date_str = date_el.get_text(strip=True) if date_el else ""
        author_el = div.find("span", {"class": "a-profile-name"})
        author = author_el.get_text(strip=True) if author_el else ""
        verified = bool(div.find("span", {"data-hook": "avp-badge"}))
        helpful_el = div.find("span", {"data-hook": "helpful-vote-statement"})
        helpful = 0
        if helpful_el:
            text_h = helpful_el.get_text()
            if "one" in text_h.lower():
                helpful = 1
            else:
                nums = [int(s) for s in text_h.split() if s.isdigit()]
                helpful = nums[0] if nums else 0
        return Review(
            platform="amazon",
            product_id=asin,
            rating=rating,
            title=title,
            text=text,
            date=date_str,
            author=author,
            verified=verified,
            helpful_votes=helpful,
        )
    except Exception:
        return None

Multi-Platform Review Collector

class ReviewCollector:
    """Collect reviews from multiple platforms for a product."""
    def __init__(self):
        self.scrapers = {
            "amazon": scrape_amazon_reviews,
        }
    def collect_all(self, product_ids: dict) -> list[Review]:
        """
        Collect reviews from all platforms.
        product_ids: {"amazon": "B0CHX3QBCH", "walmart": "12345"}
        """
        all_reviews = []
        for platform, product_id in product_ids.items():
            if platform in self.scrapers:
                print(f"\nScraping {platform} reviews for {product_id}")
                reviews = self.scrapers[platform](product_id)
                all_reviews.extend(reviews)
                print(f"Collected {len(reviews)} reviews from {platform}")
                time.sleep(random.uniform(5, 10))
        return all_reviews
    def to_dataframe(self, reviews: list[Review]):
        """Convert reviews to a pandas DataFrame for analysis."""
        import pandas as pd
        return pd.DataFrame([vars(r) for r in reviews])
# Usage
collector = ReviewCollector()
reviews = collector.collect_all({
    "amazon": "B0CHX3QBCH",
})
print(f"\nTotal reviews collected: {len(reviews)}")

Node.js Implementation

Un raspador de revisión Node.js utilizando Nodo de ProxyHat SDK.

const axios = require("axios");
const cheerio = require("cheerio");
const { HttpsProxyAgent } = require("https-proxy-agent");
function getProxy(sessionId = null) {
  if (sessionId) {
    return `http://USERNAME-session-${sessionId}:PASSWORD@gate.proxyhat.com:8080`;
  }
  return "http://USERNAME:PASSWORD@gate.proxyhat.com:8080";
}
async function scrapeAmazonReviews(asin, maxPages = 10) {
  const reviews = [];
  const sessionId = `rev-${asin}-${Math.floor(Math.random() * 9000 + 1000)}`;
  const agent = new HttpsProxyAgent(getProxy(sessionId));
  for (let page = 1; page <= maxPages; page++) {
    const url = `https://www.amazon.com/product-reviews/${asin}?pageNumber=${page}&sortBy=recent`;
    try {
      const { data } = await axios.get(url, {
        httpsAgent: agent,
        headers: {
          "User-Agent":
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
          "Accept-Language": "en-US,en;q=0.9",
        },
        timeout: 30000,
      });
      if (data.toLowerCase().includes("captcha")) {
        console.log(`CAPTCHA on page ${page}`);
        break;
      }
      const $ = cheerio.load(data);
      const reviewDivs = $('[data-hook="review"]');
      if (reviewDivs.length === 0) break;
      reviewDivs.each((_, el) => {
        const $el = $(el);
        const ratingText = $el.find('[data-hook="review-star-rating"]').text();
        const rating = parseFloat(ratingText.split(" ")[0]) || null;
        reviews.push({
          platform: "amazon",
          productId: asin,
          rating,
          title: $el.find('[data-hook="review-title"]').text().trim(),
          text: $el.find('[data-hook="review-body"]').text().trim(),
          date: $el.find('[data-hook="review-date"]').text().trim(),
          author: $el.find(".a-profile-name").text().trim(),
          verified: $el.find('[data-hook="avp-badge"]').length > 0,
        });
      });
      console.log(`Page ${page}: ${reviewDivs.length} reviews (total: ${reviews.length})`);
      await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));
    } catch (err) {
      console.error(`Error page ${page}: ${err.message}`);
      break;
    }
  }
  return reviews;
}
// Usage
scrapeAmazonReviews("B0CHX3QBCH", 5).then((reviews) => {
  console.log(`Collected ${reviews.length} reviews`);
  console.log(JSON.stringify(reviews.slice(0, 2), null, 2));
});

Paginación de manipulación en escala

La paginación de revisión es uno de los mayores desafíos en el raspado de revisión a gran escala.

Amazon Pagination Strategy

Amazon limita las páginas de revisión a 10 reseñas cada una y normalmente muestra hasta 500 páginas (5.000 reseñas). Para productos con más opiniones, utilice parámetros de filtro a segmento:

# Filter by star rating to get more reviews
star_filters = [
    "one_star", "two_star", "three_star",
    "four_star", "five_star"
]
for star in star_filters:
    url = (f"https://www.amazon.com/product-reviews/{asin}"
           f"?filterByStar={star}&pageNumber={page}")
    # This lets you access more reviews per product

Session Management for Pagination

La paginación de revisión de cada producto debe usar su propia sesión pegajosa. Cuando termine un producto y se mueva a la siguiente, cree una nueva sesión con una IP diferente.

Session Management for Pagination
FaseProxy StrategyRazón
Encontrar productosRotación por vehículoConsultas independientes, no es necesario celebrar un período de sesiones
Opiniones de pacientesSesión pegajosa por productoEl mismo IP en páginas se ve natural
Entre productosNuevo período de sesiones/IPIdentidad fresca para cada producto

Preparación de datos para el análisis de la sensibilidad

El texto de revisión cruda necesita preprocesamiento antes del análisis de sentimientos.

import re
from collections import Counter
def clean_review_text(text):
    """Clean review text for analysis."""
    # Remove HTML entities
    text = re.sub(r'&\w+;', ' ', text)
    # Remove excessive whitespace
    text = re.sub(r'\s+', ' ', text).strip()
    # Remove very short reviews (likely not useful)
    if len(text) < 20:
        return None
    return text
def extract_key_phrases(reviews, min_frequency=3):
    """Extract frequently mentioned phrases from reviews."""
    from collections import Counter
    import re
    words = []
    for review in reviews:
        if review.text:
            # Simple bigram extraction
            tokens = re.findall(r'\b\w+\b', review.text.lower())
            for i in range(len(tokens) - 1):
                bigram = f"{tokens[i]} {tokens[i+1]}"
                words.append(bigram)
    return Counter(words).most_common(50)
def aggregate_sentiment(reviews):
    """Calculate aggregate sentiment metrics."""
    if not reviews:
        return {}
    ratings = [r.rating for r in reviews if r.rating]
    return {
        "total_reviews": len(reviews),
        "avg_rating": sum(ratings) / len(ratings) if ratings else 0,
        "rating_distribution": {
            str(i): len([r for r in reviews if r.rating == i])
            for i in range(1, 6)
        },
        "verified_pct": (
            len([r for r in reviews if r.verified]) / len(reviews) * 100
            if reviews else 0
        ),
    }

Escalando a Millones de Comentarios

Cuando su lista de destino crece a miles de productos en múltiples plataformas, la arquitectura importa.

Arquitectura basada en la cola

  • Utilice una cola de mensaje (Redis, RabbitMQ) para gestionar la lista de productos y distribuir trabajo a través de los trabajadores.
  • Cada trabajador maneja un producto a la vez: paginar a través de todas las opiniones, almacenar resultados, pasar al siguiente producto.
  • Separar colas por plataforma para respetar diferentes límites de tarifas.

Estrategia de almacenamiento

  • Almacene HTML crudo en almacenamiento de objetos (S3) para reprocesar cuando los analizadores cambian.
  • Almacene opiniones analizadas en PostgreSQL con búsqueda de texto completo para el análisis.
  • Utilice la deduplicación basada en ID de revisión o hash para evitar almacenar duplicados en re-scrapes.

Incremental Scraping

Para el monitoreo continuo, usted no necesita re-scrape todas las críticas cada vez. Ordenar por más reciente y parar cuando usted golpeó una revisión que ya ha recogido. Esto reduce drásticamente el uso proxy y acelera la colección.

Key takeaway: Sort reviews by newest first and stop scraping when you hit previously collected content. Esto convierte una recuperación completa en una actualización incremental.

Buenas prácticas

  • Use sesiones pegajosas para la paginación: Mantenga la misma IP en las páginas de revisión para un solo producto para evitar la detección de antibots.
  • Limitaciones de la tasa de respeto: 2-5 segundos retrasos entre páginas, demoras más largas entre productos. Las diferentes plataformas tienen diferentes tolerancias.
  • Paginas vacías: Una página de revisión vacía significa que has llegado al final. No siga intentando más páginas.
  • Valorar la calidad de los datos: Compruebe las páginas de CAPTCHA, el contenido vacío y duplicar las reseñas en su oleoducto.
  • Uso proxies residenciales: Esencial para Amazon y otras plataformas fuertemente protegidas.
  • Store incrementalmente: Procesar y almacenar las reseñas mientras las raspa, no en un lote al final.

Key Takeaways

  • Los datos de revisión proporcionan una inteligencia competitiva única que ninguna otra fuente de datos ofrece.
  • Las diferentes plataformas requieren diferentes estrategias de raspado: construir raspadores modulares por plataforma.
  • Use sesiones pegajosas para revisar paginación y rotación por solicitud entre productos.
  • Ordenar por más reciente primero y parar en revisiones previamente recolectadas para un correcto raspado incremental.
  • Revisión previa del texto para el análisis de sentimientos: limpio, deduplicado y extraer frases clave.
  • Uso Los proxies residenciales de ProxyHat con geo-targeting para el acceso confiable a las páginas de revisión en todas las plataformas.

¿Listo para empezar a recopilar datos de revisión? Vea nuestro Amazon scraping guide para detalles específicos de plataforma y nuestros Guía de intercambio electrónico de datos para la estrategia completa. Check usando proxies en Python y usando proxies en Node.js para las pautas de aplicación.

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog