Scraping de Dados do Google Maps: Listagens e Avaliacoes de Negocios

Aprenda a fazer scraping do Google Maps para dados de negocios incluindo nomes, enderecos, avaliacoes e reviews. Aborda comparacao API vs scraping, estrategias de proxy e exemplos de codigo em Python e Node.js.

Scraping de Dados do Google Maps: Listagens e Avaliacoes de Negocios

Why Scrape Google Maps Data?

Google Maps contains the most comprehensive database of local businesses in the world. With over 200 million businesses listed, it includes names, addresses, phone numbers, websites, ratings, reviews, operating hours, and photos — all structured and searchable.

Extracting this data programmatically enables valuable business applications:

  • Lead generation: Build targeted lists of businesses by industry and location
  • Competitive analysis: Map competitor locations, ratings, and review sentiment
  • Market research: Understand business density, pricing patterns, and service coverage by area
  • Local SEO auditing: Verify your business listings and compare against competitors
  • Data enrichment: Supplement CRM data with fresh business information

This guide covers the technical approaches to extracting Google Maps data using proxies. For broader SERP scraping strategies, see our complete SERP scraping with proxies guide.

Google Places API vs Scraping

Before building a scraper, consider whether the official Google Places API meets your needs.

FactorPlaces APIScraping
Cost$17 per 1,000 requests (after free tier)Proxy bandwidth only (~$0.10-0.50 per 1,000 pages)
Data fieldsStructured JSON, 20+ fieldsAll visible data including reviews text
Rate limitsStrict per-second and daily limitsLimited by proxy pool size
Review textUp to 5 most relevant reviewsAll reviews (with pagination)
ReliabilityOfficial, stable endpointsRequires parser maintenance
Terms of ServiceFully compliantCheck ToS and local regulations
ScaleExpensive at scaleCost-effective at high volumes
The Places API is the best choice for small-scale, production-critical applications. Scraping is more cost-effective when you need large datasets, full review text, or when API costs become prohibitive.

Google Maps URL Structure

Understanding Google Maps URL patterns is essential for building a scraper. There are two main entry points:

Search Results

Google Maps search results can be accessed via:

# 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

Place Details

Individual business pages follow this pattern:

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

Building a Google Maps Scraper

Google Maps is a JavaScript-heavy application. Unlike regular Google Search, simple HTTP requests often return incomplete data. There are two approaches: parsing the embedded JSON data from page source, or using a headless browser.

Approach 1: Parsing Embedded JSON (Faster)

Google Maps pages contain structured data embedded in the HTML source. Here is how to extract it:

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']}")

Approach 2: Headless Browser (More Reliable)

For more reliable extraction, use a headless browser that renders 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

Once you have a list of business URLs, extract detailed information from each listing:

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'

Proxy Strategy for Google Maps

Google Maps has its own anti-bot protections that require a tailored proxy strategy.

Why Residential Proxies Are Required

Google Maps is particularly aggressive about blocking datacenter IPs. The application loads data through multiple API calls, and Google cross-references the IP across all these requests. Residential proxies from ProxyHat are essential because:

  • They pass IP reputation checks that Maps API calls enforce
  • They support city-level geo-targeting for location-specific searches
  • They maintain the consistent session behavior that Maps expects

Session Management

Unlike regular SERP scraping where you rotate IPs per request, Google Maps works better with sticky sessions:

# 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"

Rate Limiting

Google Maps is more sensitive to rapid requests than regular Google Search. Follow these guidelines:

  • Wait 5-10 seconds between search result pages
  • Wait 3-5 seconds between individual place page loads
  • Limit concurrent requests to avoid burst patterns
  • Use longer delays for review pagination (8-15 seconds between pages)

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);

Extracting Reviews at Scale

Google Maps reviews are among the most valuable data points. Each review includes the reviewer name, rating, text, date, and sometimes photos.

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

Legal and Ethical Considerations

Scraping Google Maps data raises important legal and ethical questions:

  • Google Terms of Service: Google's ToS prohibit automated scraping. Consider using the official Places API for production applications
  • Data protection: Business data like phone numbers and addresses may be subject to data protection regulations in some jurisdictions
  • Rate limiting: Even with proxies, be respectful of Google's infrastructure. Excessive scraping affects service quality
  • Data freshness: Always timestamp your data and refresh it regularly, as business information changes frequently
For mission-critical applications, consider combining the official Places API for core data with targeted scraping for supplementary fields like review text. This hybrid approach balances compliance with data completeness.

For more on web scraping best practices, see our complete guide to web scraping proxies, and learn about avoiding blocks in our anti-blocking guide. Consult the ProxyHat documentation for proxy configuration details.

Pronto para começar?

Acesse mais de 50M de IPs residenciais em mais de 148 países com filtragem por IA.

Ver preçosProxies residenciais
← Voltar ao Blog