clientscout
A repeatable Python pipeline for local business prospect research.
the problem and my contribution
Repeated Maps searches produce inconsistent fields and duplicate businesses. I built a Python pipeline that turns those records into a prioritized prospect CSV with stable IDs and campaign history.
My work covers orchestration, normalization, deduplication, activity checks, and exports using Python's standard library. Collection uses a third-party Docker scraper; processing is rule-based.
prospect research pipeline
Raw records stay intact. Filtered businesses remain in the full dataset for traceability.
recorded campaign results
| Campaign | Raw records | Deduplicated | Prospects |
|---|---|---|---|
| Fredericksburg / StaffordSep 3 · 8 queries | 181 | 170 | 31 |
| Virginia dental / aestheticsSep 9 · 128 queries | 1,900 | 1,471 | 59 |
| Virginia contractors / home servicesSep 9 · 256 queries | 4,615 | 4,263 | 362 |
Row counts from each campaign's raw.csv, all-businesses.csv, and prospects.csv. Prospects are exported records for review, not sales outcomes; campaigns may overlap.
engineering decisions
- In-process orchestration
- Resolve configuration once and pass it through all three stages. Campaign identity and settings stay consistent.
src/build.py · excerpt; logging omitted cfg = get_runtime_config(sys.argv[1:]) queries.run(cfg) scrape.run(cfg) process.run(cfg)- Identity-aware deduplication
- Match by place ID, custom domain, phone, then name and city. Restrict domain matching to custom sites so shared social platforms do not merge unrelated businesses.
src/process.py · domain-match excerpt dom = domain_key(lead["website"]) if dom and lead["website_type"] == "custom" and dom in domain_idx: merge_into(domain_idx[dom], lead) continue- Bounded failure handling
- Review lookups use timeouts, limited concurrency, and cached results; failures retain an unverified status. Scraper shutdown is bounded, and processing requires output from the current run.
repeatable runs
python src/build.py --campaign plumbers-fxbg \
--location "Fredericksburg VA" --category "plumber"
python src/process.py --campaign plumbers-fxbgCampaign folders protect existing output. Reprocess saved records without scraping again; stable IDs support repeat imports into outreach tools.
source limits
Maps links and review dates are signals, not proof of website need or business closure. The undocumented review endpoint can fail; uncertain records stay eligible for human review. Outreach happens outside ClientScout.