Google local pack results contain ready-made B2B leads: business name, address, phone number, rating, and review count. Extracting this data through a SERP API at $0.005 per query produces qualified local business leads at a fraction of the cost of manual prospecting or dedicated lead databases. This pipeline generates local leads by category and location.
Prerequisites
- Python 3.8+
- requests library
- A Scavio API key from scavio.dev
- Target business categories and locations
Walkthrough
Step 1: Search for local businesses by category
Query Google for local pack results in a target category and location.
import os, requests, json, csv
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
def search_local(category, location):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': f'{category} in {location}', 'country_code': 'us'}).json()
local = data.get('local_results', [])
leads = []
for r in local:
leads.append({
'name': r.get('title', r.get('name', '')),
'address': r.get('address', ''),
'phone': r.get('phone', ''),
'rating': r.get('rating', 'N/A'),
'reviews': r.get('reviews', 0),
'category': category,
'location': location
})
print(f'{category} in {location}: {len(leads)} local results')
return leads
leads = search_local('plumbers', 'Austin TX')
for l in leads[:3]:
print(f' {l["name"]} | {l["rating"]} ({l["reviews"]} reviews) | {l["phone"]}')Step 2: Expand to multiple categories and locations
Scale the search across multiple verticals and cities.
CATEGORIES = ['plumbers', 'electricians', 'hvac contractors', 'roofers']
LOCATIONS = ['Austin TX', 'Dallas TX', 'Houston TX']
def batch_local_search(categories, locations):
all_leads = []
queries = 0
for cat in categories:
for loc in locations:
leads = search_local(cat, loc)
all_leads.extend(leads)
queries += 1
cost = queries * 0.005
print(f'\nTotal: {len(all_leads)} leads from {queries} queries. Cost: ${cost:.3f}')
return all_leads
all_leads = batch_local_search(CATEGORIES, LOCATIONS)
# Deduplicate by name
seen = set()
unique = []
for lead in all_leads:
key = lead['name'].lower().strip()
if key not in seen:
seen.add(key)
unique.append(lead)
print(f'Unique leads: {len(unique)} (removed {len(all_leads) - len(unique)} duplicates)')Step 3: Score and qualify leads
Rank leads by quality signals: rating, reviews, and completeness.
def score_lead(lead):
score = 0
rating = float(lead.get('rating', 0)) if lead.get('rating') != 'N/A' else 0
reviews = int(lead.get('reviews', 0))
if rating >= 4.5: score += 30
elif rating >= 4.0: score += 20
elif rating >= 3.5: score += 10
if reviews >= 100: score += 25
elif reviews >= 50: score += 20
elif reviews >= 20: score += 10
if lead.get('phone'): score += 20
if lead.get('address'): score += 15
if lead.get('website'): score += 10
return score
for lead in unique:
lead['score'] = score_lead(lead)
unique.sort(key=lambda x: x['score'], reverse=True)
print(f'\nTop qualified leads:')
for l in unique[:10]:
print(f' [{l["score"]:3}] {l["name"]:30} | {l["rating"]} ({l["reviews"]} reviews) | {l["category"]}')Step 4: Export leads to CSV
Save qualified leads to CSV for import into your CRM.
def export_csv(leads, filename='local_leads.csv', min_score=30):
qualified = [l for l in leads if l.get('score', 0) >= min_score]
with open(filename, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'category', 'location',
'rating', 'reviews', 'phone', 'address', 'score'])
writer.writeheader()
for l in qualified:
writer.writerow({k: l.get(k, '') for k in writer.fieldnames})
total_queries = len(CATEGORIES) * len(LOCATIONS)
cost = total_queries * 0.005
print(f'\nExported {len(qualified)} qualified leads to {filename}')
print(f' Filtered from {len(leads)} total (min score: {min_score})')
print(f' Total cost: ${cost:.3f}')
print(f' Cost per lead: ${cost/len(qualified):.4f}' if qualified else ' No qualified leads')
export_csv(unique)Python Example
import os, requests
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def local_leads(category, location):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': f'{category} in {location}', 'country_code': 'us'}).json()
for r in data.get('local_results', [])[:5]:
print(f'{r.get("title","")} | {r.get("rating","N/A")} | {r.get("phone","N/A")}')
print(f'Cost: $0.005')
local_leads('plumbers', 'Austin TX')JavaScript Example
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function localLeads(category, location) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: `${category} in ${location}`, country_code: 'us' })
}).then(r => r.json());
(data.local_results || []).slice(0, 5).forEach(r =>
console.log(`${r.title || r.name} | ${r.rating || 'N/A'} | ${r.phone || 'N/A'}`)
);
}
localLeads('plumbers', 'Austin TX').catch(console.error);Expected Output
plumbers in Austin TX: 8 local results
ABC Plumbing | 4.8 (234 reviews) | (512) 555-0123
Radiant Plumbing | 4.9 (1,456 reviews) | (512) 555-0456
Mr. Rooter | 4.5 (89 reviews) | (512) 555-0789
Total: 48 leads from 12 queries. Cost: $0.060
Unique leads: 42 (removed 6 duplicates)
Top qualified leads:
[ 90] Radiant Plumbing | 4.9 (1456 reviews) | plumbers
[ 75] ABC Plumbing | 4.8 (234 reviews) | plumbers
Exported 35 qualified leads to local_leads.csv
Cost per lead: $0.0017