Skip to content

Repository files navigation

google-maps-email-scraper

A free, three-stage pipeline for turning Google Maps business listings into a verified cold-email lead list. Zero API cost for the scraping stage. Runs on Python stdlib plus requests.

Full story + context: Apollo returned 0 leads. Python and regex returned 647.

What this is

I was building an outbound lead list for a client in a niche home service vertical with around 1,000 national operators. Apollo.io — the industry default for B2B contact enrichment — returned zero contacts on 672 companies after burning 520 credits, because owner-operated micro-businesses do not live on LinkedIn and Apollo's contact graph is LinkedIn-shaped.

Then I noticed every target company had its contact email printed in plain text on its own website. This repo is what replaced the Apollo stage: a simple pipeline that pulls businesses from Google Maps via Apify, scrapes emails directly from their websites with requests + regex across seven common contact-page paths, and verifies the results with Million Verifier before cold outreach.

The original run produced 647 verified leads from 672 companies in one afternoon.

Pipeline

Apify Google Maps  →  scrape_emails.py  →  verify_emails.py  →  Google Sheet / CSV
  (paid, ~$2)         (free, ~6 min)      (~$0.50 / 1k emails)
Stage Tool Cost Output
1. Pull businesses Apify compass/crawler-google-places ~$0.004 per result CSV of companies with websites
2. Scrape emails scrape_emails.py (this repo) Free CSV with emails_found column
3. Verify emails verify_emails.py (this repo) ~$0.0008 per check CSV with quality column

Quick start

# 1. Install (one dependency)
pip install -r requirements.txt

# 2. Run Apify Google Maps (see apify_input.example.json for the actor config)
#    Save the resulting CSV with at minimum a 'website' column.

# 3. Scrape emails from the websites
python scrape_emails.py input.csv scraped.csv

# 4. Verify emails with Million Verifier
export MV_API_KEY=your_million_verifier_key
python verify_emails.py scraped.csv verified.csv

How the email scraper works

Seven pages per domain. Most scrapers hit the homepage and quit. Roughly half the companies in the original run had their email on /contact or /about instead of the root. scrape_emails.py hits seven common paths per domain:

PAGES = ["", "contact", "about", "contact-us", "about-us", "team", "our-story"]

This is the single biggest reason the hit rate is 50% and not 20%.

All emails, not the first. Returns every unique address found per domain as a "; "-joined string. Contact pages often list multiple addresses (owner, scheduling, billing); the verifier sorts quality downstream.

Junk filter. Twenty-two patterns learned the hard way from a single afternoon of scraping. Wix-built sites spray garbage addresses like sentry@wixpress.com, latofonts@, and image.png@cdn that match the naive regex. The filter is load-bearing.

Incremental writes. Results are flushed to the output CSV after every row, so a Ctrl-C or crash preserves progress. Important on flaky networks across 500+ domains.

20 workers, 8-second timeout. The defaults from the production run. Tune with --workers and --timeout.

Apify config (the critical parameter)

From apify_input.example.json:

{
  "searchStringsArray": ["your niche service term near Seattle, WA"],
  "maxCrawledPlacesPerSearch": 5,
  "language": "en",
  "countryCode": "us",
  "skipClosedPlaces": true
}

maxCrawledPlacesPerSearch: 5 is the setting that keeps Apify from turning a $3 test run into a $40 surprise. A previous version used 20 and triggered a 20,000-page overnight crawl before it aborted. Five is the cap to use for niche-vertical work. Always dry-run one query first, then fan out.

Cost breakdown

For the original 672-company run:

Item Cost
Apify Google Maps (~500 results @ $0.004) ~$2.00
Email scraping $0.00
Million Verifier (647 checks @ $0.0008) ~$0.52
Total ~$2.52

Compared to Apollo's 520 wasted credits returning zero contacts.

When this will NOT work

This pipeline is built for niche verticals where the total national universe of operators is small enough to fit on a spreadsheet tab and Apollo/ZoomInfo/Clay don't have the data. If your TAM is 50,000 SaaS decision-makers, Apollo is still the right answer and this repo is a waste of time. If your TAM is 1,000 owner-operators in a vertical the premium databases ignore, this is what works.

It also assumes:

  • Targets have websites (most do; a few hundred per state won't, and you'll need phone-based outreach for those)
  • Targets put their email in plain text on their site (most micro-businesses do; Fortune 500s don't)
  • You have a sending domain warmed up and ready for cold email

Legal

Scraping publicly accessible web pages for business contact information is generally permissible in the US under current case law (see hiQ Labs v. LinkedIn, 2022). That said:

  • Respect robots.txt on sites that publish one
  • Don't hammer rate-limited endpoints
  • Send cold email responsibly: CAN-SPAM compliance, one-click unsubscribe, no dark patterns
  • Don't use this to scrape personal emails from non-business contexts

You are responsible for how you use the tool.

Maintenance posture

This is the code from a blog post. I'm not actively maintaining it as a project. It's here for reference, for you to read, and for you to steal. PRs with genuine bug fixes welcome but I may be slow to review. If you build something interesting with it, I want to hear about it — find me at dylan.md.

License

MIT. See LICENSE. Do whatever you want with this.

About

Free Python pipeline: Google Maps → email scrape → Million Verifier → verified cold-email leads.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages