Google Maps Scraper GitHub: How to Extract Business Data with Python
If you are searching for a Google Maps scraper GitHub repository that extracts business listings with Python, the short answer is: yes, the open-source scrape-google-maps repository provides a starting point for collecting business names, phones, websites, addresses, ratings, reviews, opening hours, and coordinates from publicly visible Maps results. This article is for developers, lead generation agencies, local SEO specialists, and data engineers who want to control the scraping pipeline themselves rather than pay per record to a managed API.
You will see exactly what the repository covers, which fields you can extract, how to wire up a Python environment to run it, what output to expect, the tradeoffs versus commercial Google Maps APIs, and where to extend the workflow with related repositories in the same organization.
Quick Answer (TL;DR)
The scrape-google-maps repository on GitHub is an open-source Python toolkit for pulling business listings from Google Maps search results. Supply a query like "plumbers in Austin, TX," and receive structured records with name, phone, website, address, rating, review count, hours, and geographic coordinates. Pair it with the yellow-pages-scraper to cross-check a market against a directory source. Browse the data-scrape GitHub organization for the full inventory.
Why Google Maps Data Is Hard to Pull Consistently
Google Maps is the largest business directory on the public web. It is also one of the hardest sources to scrape reliably. Three structural challenges explain the difficulty:
-
Pagination is not based on a simple
?page=parameter. Results are split across "search this area" actions, infinite-scroll feeds, and cluster expansions. A naive script that requests one URL once will see only the first 20-40 results. - Field visibility is gated by interactions. Ratings, review counts, phone numbers, and opening hours live inside expandable panels. Click events must be simulated to expose the full record.
- Anti-bot defenses evolve continuously. Google fingerprint browsers, IP ranges, request headers, and interaction timing. A scraper that runs today may fail tomorrow without a config update.
This is exactly why an open-source, Pythonic implementation with documented configuration is more valuable than a one-off script. You can read the source, follow the change log, and adapt to upstream changes.
What the scrape-google-maps Repository Covers
The scrape-google-maps repository automates Google Maps search-result extraction in Python. Based on its README, it can collect business name, phone, website, category, rating, review count, address, opening hours, latitude and longitude, place ID (where exposed), and image URLs. The repository introduces both self-hosted scraping approaches and pointers to production-ready APIs for engineers who outgrow a self-hosted run. Verify the exact field set in the latest README — it can change with each release.
If your goal also involves directory data, the companion yellow-pages-scraper covers business name, phone, address, category, ratings, reviews, social links, and hours of operation. The two together form a useful cross-source validation pair when deduplicating or enriching Maps-only leads.
Step-by-Step Setup
Prerequisites
- Python 3.10 or higher
- A virtual environment tool (
venv,uv, orconda) - A network path to Google Maps (some regions and IP ranges get blocked more aggressively than others; a residential proxy may be required at scale)
- Familiarity with environment variable configuration
Install
git clone https://github.com/data-scrape/scrape-google-maps.git
cd scrape-google-maps
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Always read the requirements.txt file shipped with the repository to confirm the exact dependency versions. The snippet above is generic; the actual file may pin specific package versions.
Environment Configuration
Create a .env file in the project root:
QUERY=Plumbers in Austin, TX
MAX_RECORDS=200
OUTPUT_PATH=./output/austin_plumbers.json
PROXY_URL= # Optional: leave empty for first run
USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
LOG_LEVEL=INFO
Never hard-code credentials, proxies, or production search terms in source. Use environment variables and rotate them through your deployment or CI pipeline.
Runnable Python Example
The following is a generic, runnable client for a hypothetical Scraper class shipped by the repository. Adapt the import path and configuration knobs to match the version you cloned. The example demonstrates the standard pattern: load config from the environment, run a search, and write structured output to disk.
import json
import os
from pathlib import Path
# Replace with the actual entry point exported by scrape-google-maps
# in the version you have cloned. The import path below is illustrative.
from scraper import Scraper # type: ignore
QUERY = os.environ.get("QUERY", "Plumbers in Austin, TX")
MAX_RECORDS = int(os.environ.get("MAX_RECORDS", "200"))
OUTPUT_PATH = Path(os.environ.get("OUTPUT_PATH", "./output/results.json"))
PROXY_URL = os.environ.get("PROXY_URL") or None
def load_config():
return {
"query": QUERY,
"max_records": MAX_RECORDS,
"proxy": PROXY_URL,
"lang": "en",
"region": "US",
"headless": True,
}
def normalize(record: dict) -> dict:
"""Trim whitespace and drop None values for cleaner downstream storage."""
return {k: (v.strip() if isinstance(v, str) else v) for k, v in record.items() if v not in (None, "", [])}
def main():
config = load_config()
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
scraper = Scraper(proxy=config["proxy"], headless=config["headless"])
records = []
try:
for record in scraper.search(
query=config["query"],
max_records=config["max_records"],
lang=config["lang"],
region=config["region"],
):
records.append(normalize(record))
print(f"Collected: {record.get('name', '<unknown>')}")
finally:
scraper.close()
with OUTPUT_PATH.open("w", encoding="utf-8") as f:
json.dump(records, f, indent=2, ensure_ascii=False)
print(f"Wrote {len(records)} records to {OUTPUT_PATH}")
if __name__ == "__main__":
main()
What This Script Does
- Reads every knob from the environment, including the search query, output path, and optional proxy.
- Initializes the scraper with a proxy if one is configured; omit it for low-volume first runs.
- Streams results from the scraper as they arrive, normalizes whitespace and empties, and prints a progress line per record.
- Writes the collected records to JSON, which is the simplest format for piping into pandas, DuckDB, or a CRM webhook.
-
Closes the scraper in a
finallyblock so browser resources are released even on error.
If the actual repository exposes a different API surface (for example, an async client or CLI wrapper), prefer the README's quick-start command first, then graduate to a typed configuration like the one above.
Expected Output Fields
A normalized output record typically looks like this (illustrative example; verify against the current schema in the repository):
{
"name": "Example Plumbing Co.",
"phone": "+1 512-555-0142",
"website": "https://example-plumbing.com",
"category": "Plumber",
"rating": 4.7,
"review_count": 213,
"address": "123 Main St, Austin, TX 78701, USA",
"opening_hours": ["Mon-Fri 08:00-18:00", "Sat 09:00-14:00"],
"latitude": 30.2711,
"longitude": -97.7437,
"place_id": "ChIJ_example_placeholder",
"source_query": "Plumbers in Austin, TX"
}
Treat this as a structural reference, not a contract. Field names and types can change with the implementation. Always inspect the first few records you collect and write a schema validation step before trusting the output.
Business Use Cases
Google Maps data underpins several commercial workflows:
- Local lead generation. Build targeted B2B lists by industry and geography for outbound sales teams. Cross-reference with the yellow-pages-scraper to catch businesses that are present in directories but absent from Maps.
- Local SEO and citation audits. Compare NAP (Name, Address, Phone) consistency across directories, identify duplicate listings, and surface inconsistent categories.
- Market sizing. Count businesses by category and city to estimate addressable market size before launching a new service in a region.
- Competitive mapping. Identify chains, franchises, and independents in a territory; collect ratings and review counts to benchmark service quality.
- Enrichment for AI agents. Feed structured business records into RAG pipelines that answer location-aware questions ("which HVAC companies are open right now in zip 78701?").
Build vs Buy: Open-Source Scraper vs. Managed API
Neither path is universally better. Use the same dimensions to compare for any Google Maps data project:
| Dimension | Open-Source Scraper (this repo) | Managed Google Maps API |
|---|---|---|
| Best for | Teams with Python skills who want full control and tolerate maintenance | Teams that need SLA-backed uptime and minimal DevOps |
| Setup model | Clone the repo, install Python deps, supply proxy and config | Subscribe, obtain an API key, send REST requests |
| Data coverage | Whatever the open-source scraper currently collects from public result pages | Whatever the API endpoint exposes; verify against current docs |
| Output format | JSON/CSV you control; pipe to any storage | JSON over HTTP, structured to the API's schema |
| Maintenance burden | You monitor upstream changes and update selectors when pages change | Provider handles upstream changes |
| Quota considerations | Limited by your infrastructure and proxy capacity | Per-request quota; verify current numbers with the provider |
| Pricing verification | Verify VPS and proxy costs with your providers | Confirm current pricing on the provider's official pricing page |
The open-source route is often cheaper at scale. A managed API is faster to integrate. Many teams prototype with the open-source scraper, then graduate to an API once the workflow is validated.
Limitations, Compliance, and Maintenance
Running a Google Maps scraper in production is a sustained engineering investment:
- Terms of service and legal posture. Review Google's terms and the laws in your jurisdiction before running any scraper at scale. Publicly visible data collected for internal analysis is generally treated differently from data sold or republished. This article is not legal advice; consult counsel for your specific use.
- Selector drift. Google Maps markup changes periodically. Any field may disappear or rename without notice. Build a validation layer that checks for the presence of each expected field and alerts when collection rates drop.
- Rate limiting and pagination. Aggressive request patterns can trigger throttling or IP blocks. Add jitter between requests, cap concurrency, and respect any site-specific limits you observe.
- Phone and email extraction. Publicly listed phone numbers are usually present in Maps results. Emails are rarer and typically require a downstream lookup against the business's own website.
- Geographic coverage. Some countries and languages have weaker data coverage, different field availability, and stricter anti-bot defenses. Test against your target region before committing to a long-running pipeline.
- Storage and PII. Business contact data may be subject to data-protection rules depending on jurisdiction. Document a retention policy and provide an opt-out path.
-
Anti-bot detection. Headless browsers are detectable. The
--disable-blink-features=AutomationControlledflag and a realistic user agent reduce — but do not eliminate — flagging. Residential proxies and human-paced interaction are essential for high-volume targets.
FAQ
Is there an official Google Maps scraper GitHub project maintained by Google?
No. Google publishes the Places API for programmatic access; it does not maintain an open-source Google Maps scraper. The scrape-google-maps repository is a community-built Python project.
What data fields does it extract?
Typical fields include business name, phone, website, category, rating, review count, address, opening hours, latitude, longitude, and place ID. Confirm the exact list against the current README and validate with a sample run.
Can this scale to 100,000 records?
Scale is a function of infrastructure, proxy quality, and pacing discipline. Most teams start with batches of a few thousand records, observe how Google responds, and then increase cadence. Plan for queue-based concurrency control rather than parallel-for-loop blasting.
How is this different from the yellow-pages-scraper?
The yellow-pages-scraper targets Yellow Pages directory listings, which carry a different category taxonomy and may surface businesses missing from Google Maps. Using both gives you a cross-source view of a local market.
Does it handle reviews, not just listings?
The repository is positioned around listings extraction; full review-content scraping is a separate workflow with additional legal and ToS considerations. Treat any review-content pipeline as a distinct project with its own compliance review.
What happens when Google changes the page layout?
Field names and CSS hooks can change without warning. The expected response is to detect missing fields, update the repository or your selectors, redeploy, and rerun. Long-running pipelines need a continuous monitoring story.
Can I pipe the output into an AI agent or RAG pipeline?
Yes. JSON output loads cleanly into pandas, DuckDB, or a vector store. For agents that answer questions like "find plumbers rated above 4.5 in zip 78701 that are open right now", combine this scraper with a geocoder and a freshness check on opening hours.
Next Steps and Repository Links
Start by cloning the scrape-google-maps repository, installing its dependencies, and running a small batch against a single search query. Once the output schema matches your storage, scale up with proxy rotation and validate a steady cadence.
If your workflow depends on directory data, evaluate the yellow-pages-scraper for cross-source coverage. For a broader inventory of platform-specific scrapers covering YouTube, Zillow, Instagram, TikTok, and other sources, browse the data-scrape GitHub organization. Each repository follows the same configuration pattern: environment-based secrets, JSON output, and documented limits.
Top comments (0)