As a data engineer, I’ve built numerous lead-generation pipelines. One reality has always remained constant: paying premium prices for local business databases is almost always unnecessary. Most commercial tools simply repackage cloud-based scrapers that anyone can run for free.
If you need clean, localized B2B data, you can build a highly resilient automated extraction pipeline using free-tier cloud infrastructure. Here is how I configure these pipelines to run on a $0 budget.
The Modern Cloud Scraper Stack
Instead of writing custom Playwright or Selenium scripts from scratch and immediately burning your local IP, the most efficient approach is to utilize managed cloud scraping actors. Platforms like Apify provide $5 in free monthly platform credits (yielding roughly 10,000 to 20,000 listings), while Outscraper offers 500 free enriched records monthly.
Using cloud-based templates keeps your local system safe. These platforms run headless browser instances on distributed servers, handling initial browser fingerprinting and proxy rotation out of the box.
Bypassing the 120-Result Limit via Grid Search
Google Maps hard-caps search results at 120 listings per query. If you search for "restaurants in Chicago," you will only get 120 pins, even though thousands exist.
To bypass this programmatically, I segment the target metropolitan area into a localized grid using ZIP codes or sub-neighborhoods:
- Acquire target coordinates: Compile a list of postal codes for your target area.
-
Generate granular queries: Format your search input array programmatically (e.g.,
[Niche] in [ZIP_Code]). - Execute sequential queries: Feed this list into your cloud scraper.
If a city has 50 ZIP codes, running 50 micro-queries bypasses the global cap, scaling your potential harvest from a flat 120 listings to up to 6,000 highly targeted records.
# Conceptual query generation
niches = ["dentist", "orthodontist"]
zip_codes = ["90210", "90211", "90212"]
queries = [f"{niche} in {zip}" for niche in niches for zip in zip_codes]
Evading Bot Detection
Even in the cloud, scraping too rapidly triggers Google's anti-bot defenses, resulting in HTTP 429 errors or CAPTCHAs. When configuring your cloud scraper, always apply these defensive parameters:
- Limit Concurrency: Set your scraper's maximum parallel workers to a conservative range (2 to 5 concurrent pages).
- Throttle Requests: Introduce randomized delays of 2 to 7 seconds between navigation actions.
- Smart Proxies: Use rotating proxy pools. If you face persistent blocks, switch from datacenter proxies to residential proxies.
Data Post-Processing & Normalization
A geographic grid search inherently produces duplicates because businesses near boundaries will appear in multiple ZIP code queries.
Once the extraction finishes, export the data as a CSV. I use a simple Python script with pandas to clean the dataset before pushing it to a CRM:
import pandas as pd
# Load raw scrape results
df = pd.read_csv("scraped_leads.csv")
# 1. Deduplicate based on Google's unique Place ID
df.drop_duplicates(subset=["placeId"], inplace=True)
# 2. Filter out dead leads (listings without websites)
df = df[df["website"].notna()]
# 3. Standardize phone formatting
df["phone"] = df["phone"].str.replace(r"[\s\-\(\)]", "", regex=True)
df.to_csv("cleaned_leads.csv", index=False)
When to Migrate to Dedicated APIs
While utilizing free cloud tiers is perfect for bootstrapping or monthly outreach under 20,000 leads, it becomes an operational bottleneck at scale.
If you are building SaaS applications, tracking local rankings daily, or processing millions of records, managing multiple free tiers becomes inefficient. At that point, transitioning to structured search APIs (like SerpApi or ScaleSerp) allows you to pull clean JSON payloads directly, offloading proxy management and browser maintenance entirely.
Originally published at How to scrape Google Maps business data for free
Top comments (0)