Deeper · 04.A
The scraper, end to end.
Browser-based, headless, single profile, large viewport. Anything else gets you flagged.
The setup
One AdsPower profile (k1abvi20 for CTP work). Logged into the founder's Google account so the Maps results match what a real user would see. Connection to AdsPower over CDP via Playwright. All browser automation runs headless with viewport ≥ 1920×1080 — small viewports hide the Maps panels we need to scrape.
Never run two browser agents in parallel. Maps fingerprints collisions instantly. Sequential only.
The query loop
- 01Navigate to maps.google.comLogged-in session means real personalised results.
- 02Search "service in city"Match the same exact query the customer would type.
- 03Wait for the side panel to loadUp to 4s. Don't race the DOM.
- 04Scroll the side panel to bottomLazy-loaded results. Each scroll triggers more rows.
- 05Extract per businessName, phone, website, rating, review count, address, vertical hints.
- 06DeduplicateBy phone first, by name+address second. Cross-vertical duplicates exist.
- 07Tag with vertical and cityStored in Provider Finder data with timestamps.
Quality filter
Below 4-star average and below 50 reviews → killed. No website → killed unless the vertical doesn't need one (street food, local fixers). Verifiable phone number is mandatory. The scraped row is provisional until a human eyeballs it once.
What it looks like
The Provider Finder dashboard groups scraped providers per site. For each provider: a wa.me link with a pre-filled, manually-reviewable message. The founder clicks one link at a time, sends from personal WhatsApp. Each click is a decision. No mass-send button exists. By design.