DEV Community

agenthustler
agenthustler

Posted on

How to Scrape Google Maps Business Data in 2026 (API vs Scraping)

Google Maps is the richest public source of local business data on the planet — over 200 million businesses indexed with names, addresses, phone numbers, ratings, reviews, and operating hours. Whether you're building a lead generation pipeline, doing market research, or analyzing competitors, getting this data programmatically is a common need.

But Google doesn't make it cheap or easy. Let's break down the realistic options in 2026.

Google Maps Places API: The Official (Expensive) Route

Google's Places API is the sanctioned way to access business data. The pricing as of 2026:

  • Place Search: ~$17 per 1,000 requests
  • Place Details: ~$17 per 1,000 requests
  • Autocomplete: ~$2.83 per 1,000 requests

To get full business details (name, address, phone, rating, reviews, hours), you need at minimum a search request + a details request per business. That's $34 per 1,000 businesses.

If you're scraping 50,000 businesses for a market research project, that's $1,700 just for the API calls. For many use cases — especially startups, freelancers, and small agencies — that's prohibitive.

# Official API example (for reference)
import requests

API_KEY = "your-google-api-key"
url = "https://maps.googleapis.com/maps/api/place/textsearch/json"

params = {
    "query": "coffee shops in Austin TX",
    "key": API_KEY
}

response = requests.get(url, params=params)
results = response.json().get("results", [])

for place in results:
    print(f"Name: {place['name']}")
    print(f"Address: {place.get('formatted_address', 'N/A')}")
    print(f"Rating: {place.get('rating', 'N/A')}")
    print(f"Total Reviews: {place.get('user_ratings_total', 0)}")
    print("---")
Enter fullscreen mode Exit fullscreen mode

This works but gets expensive fast. And Google enforces strict rate limits, usage caps, and terms of service.

Scraping Google Maps Directly: What You're Up Against

Scraping Google Maps in 2026 is significantly harder than it was a few years ago. Here's what you'll encounter:

Dynamic Rendering: Google Maps is a JavaScript-heavy SPA. The business data you see isn't in the initial HTML — it's loaded dynamically via XHR requests that return protocol buffer (protobuf) encoded data, not clean JSON.

Anti-Bot Detection: Google uses sophisticated fingerprinting. They check browser headers, TLS fingerprints, mouse movement patterns, and request timing. A naive requests.get() to maps.google.com will get you blocked almost immediately.

CAPTCHAs: After a few requests from the same IP, you'll hit reCAPTCHA challenges that are nearly impossible to solve programmatically.

Rate Limiting: Even with residential proxies, Google throttles aggressively if your request patterns look automated.

A Practical Approach: Scraping Google Maps Search Results

Instead of hitting maps.google.com directly, one reliable approach is to scrape Google Search results for Maps data. When you search Google for local businesses, the search results contain structured business data that's easier to parse.

import requests
from urllib.parse import quote_plus
import re
import json

def scrape_google_maps_data(query, location="Austin, TX"):
    search_query = f"{query} in {location}"
    url = f"https://www.google.com/search?q={quote_plus(search_query)}&tbm=lcl"

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/120.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "text/html,application/xhtml+xml",
    }

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

    if response.status_code != 200:
        print(f"Request failed: {response.status_code}")
        return []

    return parse_local_results(response.text)


def parse_local_results(html):
    businesses = []

    # Parse business names from Google's local pack
    name_pattern = re.findall(
        r'class="[^"]*dbg0pd[^"]*"[^>]*>([^<]+)', html
    )

    rating_pattern = re.findall(
        r'(\d\.\d)\s*\((\d[\d,]*)\)', html
    )

    address_pattern = re.findall(
        r'class="[^"]*rllt__details[^"]*"[^>]*>.*?<span>([^<]+)</span>',
        html, re.DOTALL
    )

    for i, name in enumerate(name_pattern):
        biz = {"name": name.strip()}

        if i < len(rating_pattern):
            biz["rating"] = float(rating_pattern[i][0])
            biz["review_count"] = int(
                rating_pattern[i][1].replace(",", "")
            )

        if i < len(address_pattern):
            biz["address"] = address_pattern[i].strip()

        businesses.append(biz)

    return businesses


# Usage
results = scrape_google_maps_data("plumbers", "Denver, CO")
for biz in results:
    print(json.dumps(biz, indent=2))
Enter fullscreen mode Exit fullscreen mode

Important caveat: This approach works for small-scale data collection, but Google will block your IP after a modest number of requests. For anything beyond a handful of queries, you need a proxy solution.

Getting Phone Numbers and Hours

The search results page gives you names, ratings, and addresses. For phone numbers and business hours, you need to hit the individual business details — either through the API or by making additional requests.

def get_business_details(place_name, address):
    query = f"{place_name} {address} phone hours"
    url = f"https://www.google.com/search?q={quote_plus(query)}"

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/120.0.0.0 Safari/537.36",
    }

    response = requests.get(url, headers=headers, timeout=15)
    html = response.text
    details = {}

    # Extract phone number
    phone_match = re.search(
        r'\(\d{3}\)\s*\d{3}[-.]\'+'?\d{4}|\d{3}[-.]\'+'?\d{3}[-.]\'+'?\d{4}',
        html
    )
    if phone_match:
        details["phone"] = phone_match.group()

    # Extract hours
    hours_match = re.search(
        r'((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)[^<]*(?:AM|PM))',
        html
    )
    if hours_match:
        details["hours_sample"] = hours_match.group()

    return details
Enter fullscreen mode Exit fullscreen mode

Scaling Up: Handling Proxies and Anti-Bot Protection

For any real-world project, you need to rotate proxies and handle Google's anti-bot measures. Here's what a production setup looks like:

import random

PROXY_POOL = [
    "http://user:pass@proxy1:8080",
    "http://user:pass@proxy2:8080",
]

def make_request_with_proxy(url, headers):
    proxy = random.choice(PROXY_POOL)
    proxies = {"http": proxy, "https": proxy}

    try:
        response = requests.get(
            url, headers=headers,
            proxies=proxies, timeout=20
        )
        return response
    except requests.exceptions.RequestException as e:
        print(f"Proxy failed: {e}")
        return None
Enter fullscreen mode Exit fullscreen mode

Managing your own proxy infrastructure is painful — you need hundreds of residential IPs, rotation logic, retry handling, and CAPTCHA solving. A more practical approach is using a proxy API service like ScraperAPI that handles all of this for you. You just prepend their endpoint to your target URL and they manage the proxy rotation, browser fingerprinting, and CAPTCHA solving:

# Using ScraperAPI to handle proxies and anti-bot
SCRAPER_API_KEY = "your-scraperapi-key"

def scrape_with_proxy_api(target_url):
    api_url = "https://api.scraperapi.com"
    params = {
        "api_key": SCRAPER_API_KEY,
        "url": target_url,
        "render": "true",  # JavaScript rendering
        "country_code": "us"
    }
    response = requests.get(api_url, params=params, timeout=60)
    return response
Enter fullscreen mode Exit fullscreen mode

This removes the biggest operational headache — you don't need to maintain proxy lists or deal with IP bans.

Real-World Use Cases

Lead Generation: Sales teams scrape Google Maps to build prospect lists. A plumbing company in Dallas wants to reach out to every restaurant within 10 miles — Google Maps has that data.

Market Research: Want to know how many coffee shops operate in a metro area? Their average rating? Whether chains dominate or independents thrive? Google Maps is the dataset.

Competitor Analysis: Track how competitors' ratings change over time, monitor new reviews, see when new locations open.

Data Enrichment: Enrich your existing CRM data with phone numbers, business hours, and review counts from Google Maps.

What to Watch Out For

  1. Terms of Service: Google's ToS prohibits automated scraping. Understand the legal landscape in your jurisdiction. Many businesses use this data, but do your own risk assessment.

  2. Data Freshness: Business data changes. Hours get updated, businesses close, phone numbers change. Build in refresh cycles.

  3. Data Quality: Parsing HTML is fragile. Google changes their markup regularly, which breaks scrapers. Expect maintenance overhead.

  4. Rate Limiting: Even with proxies, be respectful. Hammering Google with thousands of requests per minute will get your proxies burned fast. Add delays between requests (2-5 seconds minimum).

import time
import random

def polite_scrape(urls, min_delay=2, max_delay=5):
    results = []
    for url in urls:
        time.sleep(random.uniform(min_delay, max_delay))
        result = scrape_with_proxy_api(url)
        if result:
            results.append(result)
    return results
Enter fullscreen mode Exit fullscreen mode

Conclusion

Scraping Google Maps in 2026 is a balance between cost and complexity. The official API is clean but expensive at $17+ per 1,000 requests. Direct scraping is cheap but technically challenging due to Google's aggressive anti-bot measures.

For small projects (under 1,000 businesses), the API is probably your best bet. For larger-scale data collection, a scraping approach with proper proxy infrastructure — whether self-managed or through a service like ScraperAPI — is more cost-effective.

The key is to start small, validate that the data you're getting is useful for your specific use case, and then scale up the approach that works.


Have questions about scraping Google Maps or working with location data? Drop a comment below.

Top comments (0)