Scraping de datos de Google Maps: listados de negocios y reseñas

Aprende cómo raspar Google Maps para datos de negocios incluyendo nombres, direcciones, calificaciones y reseñas. Cubre la comparación API vs, estrategias proxy y ejemplos de código en Python y Node.js.

Scraping de datos de Google Maps: listados de negocios y reseñas

¿Por qué Scrape Google Maps Data?

Google Maps contiene la base de datos más completa de negocios locales en el mundo. Con más de 200 millones de empresas enumeradas, incluye nombres, direcciones, números de teléfono, sitios web, calificaciones, reseñas, horas de funcionamiento y fotos — todo estructurado y verificable.

Extracting this data programmatically enables valuable business applications:

  • Generación líder: Crear listas específicas de empresas por industria y ubicación
  • Análisis competitivo: Mapa ubicaciones de competidores, puntuaciones, y ver el sentimiento
  • Investigación del mercado: Comprender densidad de negocio, patrones de precios y cobertura de servicios por área
  • Auditoría local SEO: Verifique los listados de su negocio y compare contra los competidores
  • Enriquecimiento de datos: Suplemento de datos CRM con información de negocios fresca

Esta guía cubre los enfoques técnicos para extraer los datos de Google Maps usando proxies. Para estrategias más amplias de raspado SERP, vea nuestra completo SERP raspado con guía proxies.

Google Places API vs Scraping

Antes de construir un rascador, considere si la API oficial de Google Places satisface sus necesidades.

Google Places API vs Scraping
FactorLugares APIScraping
Costo17 dólares por cada 1.000 solicitudes (después de la tarifa gratuita)Proxy ancho de banda sólo (~$0.10-0.50 por 1.000 páginas)
Campos de datosJSON estructurado, 20+ camposTodos los datos visibles incluyendo el texto de los comentarios
Tasa límiteLímites estrictos por segundo y diarioLimitado por tamaño de la piscina proxy
Texto de revisiónHasta 5 exámenes más relevantesTodas las opiniones (con paginación)
ConfiabilidadPuntos finales oficiales y establesRequiere mantenimiento de parser
Términos de servicioTotalmente compatibleRevisar ToS y regulaciones locales
EscalaGastos a escalaCosto-eficaz en volúmenes altos
La API Places es la mejor opción para aplicaciones de pequeña escala y crítica de producción. Scraping es más rentable cuando necesita grandes conjuntos de datos, texto de revisión completa, o cuando los costos de API se vuelven prohibitivos.

Google Maps URL Estructura

Comprender los patrones URL de Google Maps es esencial para construir un rascador. Hay dos puntos de entrada principales:

Resultados de la búsqueda

Los resultados de búsqueda de Google Maps se pueden acceder a través de:

# Browser URL format
https://www.google.com/maps/search/restaurants+near+new+york
# URL parameters for search
https://www.google.com/maps/search/{query}/@{lat},{lng},{zoom}z

Detalles del lugar

Las páginas de negocio individuales siguen este patrón:

# Place detail URL
https://www.google.com/maps/place/{business+name}/@{lat},{lng},{zoom}z/data=!{place_id}

Construyendo un Google Maps Scraper

Google Maps es una aplicación JavaScript-heavy. A diferencia de la búsqueda regular de Google, las solicitudes HTTP simples a menudo regresan datos incompletos. Hay dos enfoques: analizar los datos JSON incrustados de la fuente de página, o utilizar un navegador sin cabeza.

Enfoque 1: Parsing Embedded JSON (Faster)

Las páginas de Google Maps contienen datos estructurados incrustados en la fuente HTML. Aquí está cómo extraerlo:

import requests
import json
import re
import time
import random
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def search_google_maps(query, location="us"):
    """Search Google Maps and extract business listings."""
    proxies = {"http": PROXY_URL, "https": PROXY_URL}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "text/html,application/xhtml+xml",
    }
    # Use the search URL format
    search_url = f"https://www.google.com/maps/search/{query.replace(' ', '+')}"
    response = requests.get(
        search_url,
        headers=headers,
        proxies=proxies,
        timeout=20,
    )
    response.raise_for_status()
    # Extract embedded JSON data from the page
    # Google Maps embeds data in a specific pattern
    businesses = []
    # Look for business data patterns in the response
    # The data is typically in a JavaScript variable
    patterns = re.findall(r'\["([^"]+)",null,null,null,null,null,null,null,"([^"]*)"', response.text)
    # Alternative: parse the structured search results
    # Google Maps returns data in protobuf-like JSON arrays
    json_matches = re.findall(r'null,\["([^"]{5,80})"[^]]*?"([^"]*?(?:St|Ave|Rd|Blvd|Dr|Ln)[^"]*?)"', response.text)
    for match in json_matches[:20]:
        businesses.append({
            "name": match[0],
            "address": match[1] if len(match) > 1 else "",
        })
    return businesses
results = search_google_maps("restaurants near Times Square New York")
for b in results:
    print(f"{b['name']} - {b['address']}")

Enfoque 2: Navegador sin cabeza (Más fiable)

Para una extracción más fiable, utilice un navegador sin cabeza que renderice JavaScript:

from playwright.sync_api import sync_playwright
import json
import time
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def scrape_maps_with_browser(query):
    """Use Playwright to scrape Google Maps with full JS rendering."""
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=True,
            proxy={
                "server": "http://gate.proxyhat.com:8080",
                "username": "USERNAME",
                "password": "PASSWORD",
            },
        )
        page = browser.new_page()
        page.set_extra_http_headers({
            "Accept-Language": "en-US,en;q=0.9",
        })
        # Navigate to Google Maps search
        search_url = f"https://www.google.com/maps/search/{query.replace(' ', '+')}"
        page.goto(search_url, wait_until="networkidle", timeout=30000)
        # Wait for results to load
        page.wait_for_selector('div[role="feed"]', timeout=10000)
        # Scroll to load more results
        feed = page.query_selector('div[role="feed"]')
        for _ in range(5):
            feed.evaluate("el => el.scrollBy(0, 1000)")
            time.sleep(1.5)
        # Extract business data from the results
        businesses = []
        items = page.query_selector_all('div[role="feed"] > div > div > a')
        for item in items:
            name = item.get_attribute("aria-label")
            href = item.get_attribute("href")
            if name and href:
                businesses.append({
                    "name": name,
                    "url": href,
                })
        browser.close()
        return businesses
results = scrape_maps_with_browser("coffee shops in San Francisco")
for b in results:
    print(f"{b['name']}")
    print(f"  {b['url'][:80]}...")
    print()

Extracting Business Details

Una vez que tenga una lista de URLs de negocio, extraiga información detallada de cada listado:

import requests
import re
import json
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def extract_business_details(maps_url):
    """Extract detailed business info from a Google Maps place page."""
    proxies = {"http": PROXY_URL, "https": PROXY_URL}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
    }
    response = requests.get(maps_url, headers=headers, proxies=proxies, timeout=20)
    text = response.text
    business = {}
    # Extract business name
    name_match = re.search(r'

Estrategia Proxy para Google Maps

Google Maps tiene sus propias protecciones antibot que requieren una estrategia proxy personalizada.

¿Por qué se requieren los proxies residenciales

Google Maps es particularmente agresivo acerca de bloquear IPs de centro de datos. La aplicación carga datos a través de múltiples llamadas API, y Google hace referencias a la IP en todas estas solicitudes. Proxies residenciales de ProxyHat son esenciales porque:

  • Pasan cheques de reputación IP que Maps API llama hacer cumplir
  • Apoyan el geo-objetivo a nivel de la ciudad para búsquedas específicas de ubicación
  • Ellos mantienen el comportamiento de sesión consistente que Maps espera

Gestión del período de sesiones

A diferencia del raspado SERP regular donde gira IPs por solicitud, Google Maps funciona mejor con sesiones pegajosas:

# For Google Maps, use sticky sessions (same IP for a business detail page)
# ProxyHat supports session-based rotation via the proxy URL
# See docs.proxyhat.com for session configuration
# Rotating IP (for search listings)
ROTATING_PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
# Sticky session (for individual place pages)
# Same session ID = same IP for the session duration
STICKY_PROXY = "http://USERNAME-session-maps123:PASSWORD@gate.proxyhat.com:8080"

Tasa de limitación

Google Maps es más sensible a las solicitudes rápidas que la búsqueda regular de Google. Siga estas directrices:

  • Espera 5-10 segundos entre las páginas de resultados de búsqueda
  • Espera 3-5 segundos entre las cargas individuales de la página de lugar
  • Limitar las solicitudes simultáneas para evitar patrones de explosión
  • Use demoras más largas para la paginación de revisión (8-15 segundos entre páginas)

Node.js Implementation

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
async function searchGoogleMaps(query) {
  const searchUrl = `https://www.google.com/maps/search/${encodeURIComponent(query)}`;
  const { data } = await axios.get(searchUrl, {
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      'Accept-Language': 'en-US,en;q=0.9',
    },
    httpsAgent: agent,
    timeout: 20000,
  });
  // Extract business names from the response
  const businesses = [];
  const namePattern = /\["([^"]{3,80})",null,null,null,null,null,null,null/g;
  let match;
  while ((match = namePattern.exec(data)) !== null) {
    businesses.push({ name: match[1] });
  }
  return businesses;
}
async function main() {
  const results = await searchGoogleMaps('plumbers in Chicago');
  console.log(`Found ${results.length} businesses:`);
  results.forEach((b, i) => console.log(`${i + 1}. ${b.name}`));
}
main().catch(console.error);

Exámenes de Extracción en Escala

Las reseñas de Google Maps son uno de los puntos de datos más valiosos. Cada revisión incluye el nombre del revisor, calificación, texto, fecha y a veces fotos.

import requests
import re
import json
import time
import random
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def extract_reviews(place_id, num_reviews=50):
    """Extract reviews for a Google Maps place using the internal API."""
    proxies = {"http": PROXY_URL, "https": PROXY_URL}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
    }
    reviews = []
    # Google Maps loads reviews via AJAX with pagination tokens
    # The first page is loaded with the place page
    maps_url = f"https://www.google.com/maps/place/?q=place_id:{place_id}"
    response = requests.get(maps_url, headers=headers, proxies=proxies, timeout=20)
    # Extract review data from embedded JSON
    # Reviews are typically in arrays with rating, text, and author
    review_pattern = re.findall(
        r'"(\d)","([^"]{10,500})"[^]]*?"([^"]{2,50})"',
        response.text
    )
    for match in review_pattern[:num_reviews]:
        reviews.append({
            "rating": int(match[0]),
            "text": match[1],
            "author": match[2],
        })
    return reviews
# Example: extract reviews
reviews = extract_reviews("ChIJN1t_tDeuEmsRUsoyG83frY4")  # Example place ID
for r in reviews[:5]:
    print(f"{'*' * r['rating']} by {r['author']}")
    print(f"  {r['text'][:100]}...")
    print()

Data Structuring and Storage

Organize scraped Google Maps data into a structured format for analysis:

import json
import csv
from datetime import datetime
def save_businesses(businesses, output_format="json"):
    """Save scraped business data in structured format."""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    if output_format == "json":
        filename = f"maps_data_{timestamp}.json"
        with open(filename, "w") as f:
            json.dump(businesses, f, indent=2, ensure_ascii=False)
    elif output_format == "csv":
        filename = f"maps_data_{timestamp}.csv"
        if businesses:
            keys = businesses[0].keys()
            with open(filename, "w", newline="", encoding="utf-8") as f:
                writer = csv.DictWriter(f, fieldnames=keys)
                writer.writeheader()
                writer.writerows(businesses)
    print(f"Saved {len(businesses)} businesses to {filename}")
    return filename

Consideraciones jurídicas y éticas

Los datos de Google Maps plantean importantes cuestiones jurídicas y éticas:

  • Términos de servicio de Google: El ToS de Google prohíbe el raspado automático. Considere el uso de la API oficial Places para aplicaciones de producción
  • Protección de datos: Los datos comerciales como números de teléfono y direcciones pueden estar sujetos a normas de protección de datos en algunas jurisdicciones
  • Tasa límite: Incluso con proxies, sean respetuosos con la infraestructura de Google. Excesivo raspado afecta la calidad del servicio
  • Frescura de datos: Siempre contemplen sus datos y refresquenlo regularmente, ya que la información de negocios cambia con frecuencia
Para aplicaciones críticas de la misión, considere la posibilidad de combinar la API oficial de Lugares para datos básicos con raspado selectivo para campos complementarios como texto de revisión. Este enfoque híbrido equilibra el cumplimiento de la integridad de los datos.

Para más información sobre las mejores prácticas de la web, vea nuestra guía completa de proxies de raspado web, y aprender sobre evitar bloques en nuestro Guía antibloqueoConsultar Documentación de ProxyHat para detalles de configuración proxy.

¿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