Scrape verified US business leads from Google Maps by niche. Returns name, phone, website, email, rating, and GPS coordinates. Live progress, duplicate-free multi-query runs. US-only, zero personal info.
Maps navigation retry on Apify — on Page.goto timeout, reinitialize browser and retry once (core/navigation.py).
Fixes multi-query failures (e.g. nail salon query 2/3 on build 2.0.2).
Data quality
Phone from listing cards — extract from phone button aria-label, data-item-id tel:, and tel: links in card JS.
Two-pass place URL phone enrichment on Apify — collect all listing cards first, then visit place URLs for missing phones (salons hide phone until full place view).
core/phone_extraction.py + tests.
Verified (build 2.1.3)
Salons: 3/3 queries, 60 leads (was 2/3 on 2.0.2).
Phones: plumbers 3/3; salons 2/5 on smoke test (was 0/40).
[2.0] - 2026-07-12
Speed (Apify fast path)
Skip Playwright email fallback on Apify — aiohttp only; avoids extra tabs + ~10–30s/query.
Tighter listing extraction — 8s → 6s timeout per card on Apify (5s regressed on frozen DOM).
Circuit breaker — stop after 3 consecutive listing timeouts when leads already collected.
Health check aborts frozen page — don't burn full run budget timing out every card.
Fewer email HTTP paths + shorter aiohttp budget on Apify.
Faster scroll — shorter settle/pause; max 2 scrolls on Apify.
Cap listings processed — at most max_results + 3 cards per query.
Close stray browser tabs between queries (fixes multi-query nav failures).
core/performance.py + tests/test_performance.py.
Verified (salons cohort, build 2.0.2)
40 leads in ~140s (was 7 leads / 344s on 1.9.1; 0 leads / 547s on 2.0.1).
[1.9] - 2026-07-12
Fix — salons / use_proxy cohort (0 results)
Skip browser proxy for Google Maps on Apify — datacenter proxy caused Page.goto 20s timeouts on every query; emails already use direct aiohttp.
Apify proxy for use_proxy on cloud — free public proxies broke Google Maps (0 results on LA salons cohort). Now uses Actor.create_proxy_configuration() on Apify; free-list proxies remain local-only.
Deadline-aware multi-query scheduling — core/run_scheduling.py skips remaining queries and Playwright email fallback when run budget is too low (Pattern C/E).
Regression tests — tests/test_run_scheduling.py, tests/conftest.py for legacy google_maps_scraper imports.
Visible-text-only extraction — strips <script>, <style>, HTML comments, and ALL HTML tags before regex matching. Eliminates false positives from JS code, CSS, CDN URLs, and HTML attributes
mailto: link extraction — extracts emails from href="mailto:..." attributes (highest confidence source)
Domain-matching preference — emails whose domain matches the website domain are preferred over random matches
Obfuscation detection — catches info [at] domain.com, info(at)domain.com, info AT domain.com patterns
Checks 5 paths per website: /, /contact, /contact-us, /about, /about-us
No proxy needed — direct HTTP with gzip encoding
~75% email hit rate on reachable sites
Address enrichment — parses city/state from search query (e.g. "plumbers in New York, NY") and appends to partial street addresses from listing cards
Word-boundary street suffix detection — fixes false positives where business names containing "Plumbing", "Drive", "Court" etc. were misidentified as addresses
Uses \b regex boundaries instead of substring matching
Requires at least one digit in address text (street numbers)
Phone regex updated — now matches +1 XXX-XXX-XXXX international format shown in Google Maps cards
Test Results (local)
Query
Leads
Time
RAM
Phones
Addresses
Emails
plumbers in New York, NY
10/10
18s
249MB
10/10
10/10
3/10
dentists in Austin, TX
10/10
23s
329MB
0/10*
10/10
0/10*
*Dentist listing cards don't show phone/website in Google Maps card view
Memory
Default memory reduced from 1024MB back to 512MB
Peak RAM: 249-329MB — well within 512MB limit
Version bumped to 1.2
[1.1] - 2026-03-12
Memory Optimization (fits in 512MB!)
Reduced default memory from 2048MB to 512MB (min 512MB, max 2048MB)
Peak RAM: ~245MB (full process tree incl. Chromium) — well under 512MB
Removed --single-process Chromium flag (increases memory with Playwright)