La generación de leads locales a escala requiere buscar empresas por tipo y ubicación, extraer información de contacto y calificar leads. Este tutorial crea una canalización que busca empresas locales utilizando datos SERP, extrae sitios web, correos electrónicos y números de teléfono de los resultados y califica cada cliente potencial. Una búsqueda cuesta $0,005 y un escaneo típico de categoría de ciudad de 20 consultas cuesta $0,10.
Requisitos previos
- Python 3.9+ instalado
- solicita biblioteca instalada
- Una clave API de Scavio de scavio.dev
Guia paso a paso
Paso 1: Definir ubicaciones de destino y categorías comerciales
Configure las ciudades y los tipos de negocios para buscar. Cada combinación se convierte en una consulta de búsqueda.
locations = [
'Austin TX', 'Denver CO', 'Portland OR',
'Nashville TN', 'Raleigh NC'
]
categories = [
'plumber', 'electrician', 'HVAC contractor',
'roofing company'
]
total_queries = len(locations) * len(categories)
cost = total_queries * 0.005
print(f'{len(locations)} cities x {len(categories)} categories = {total_queries} queries')
print(f'Estimated cost: ${cost:.2f}')Paso 2: Buscar empresas locales
Ejecute consultas de búsqueda para cada par de ubicación-categoría y recopile las listas de empresas de los resultados SERP.
import requests, os, time, re
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def search_local(category: str, location: str) -> list:
query = f'{category} in {location}'
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 10})
resp.raise_for_status()
results = resp.json().get('organic_results', [])
leads = []
for r in results:
domain = r['link'].split('/')[2] if '/' in r['link'] else ''
# Skip aggregator sites
if any(agg in domain for agg in ['yelp.com', 'yellowpages.com',
'homeadvisor.com', 'angi.com', 'thumbtack.com', 'bbb.org']):
continue
leads.append({
'business_name': r['title'].split(' - ')[0].split(' | ')[0].strip(),
'website': r['link'],
'domain': domain,
'snippet': r.get('snippet', ''),
'category': category,
'location': location
})
return leads
# Test one query
leads = search_local('plumber', 'Austin TX')
print(f'Found {len(leads)} leads for plumber in Austin TX')
for l in leads[:3]:
print(f' {l["business_name"]}: {l["domain"]}')Paso 3: Extraer información de contacto de fragmentos
Analice números de teléfono, correos electrónicos y direcciones de fragmentos de SERP. Muchas listas de empresas locales incluyen información de contacto directamente.
def extract_contacts(lead: dict) -> dict:
text = lead.get('snippet', '') + ' ' + lead.get('business_name', '')
# Phone numbers
phones = re.findall(r'\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}', text)
# Email patterns
emails = re.findall(r'[\w.+-]+@[\w-]+\.[\w.-]+', text)
# Rating patterns (e.g., "4.8 stars", "4.8/5")
ratings = re.findall(r'(\d\.\d)\s*(?:stars?|/5|rating)', text.lower())
lead['phone'] = phones[0] if phones else ''
lead['email'] = emails[0] if emails else ''
lead['rating'] = float(ratings[0]) if ratings else 0.0
return lead
# Enrich existing leads
enriched = [extract_contacts(l) for l in leads]
for l in enriched[:3]:
print(f' {l["business_name"]}: phone={l["phone"] or "N/A"}, '
f'rating={l["rating"] or "N/A"}')Paso 4: Ejecute todo el proceso y exporte los resultados
Escanee todas las combinaciones de ubicación y categoría, enriquezca clientes potenciales, elimine duplicados por dominio y exporte a CSV.
import csv
def run_pipeline(locations: list, categories: list) -> list:
all_leads = []
seen_domains = set()
for location in locations:
for category in categories:
leads = search_local(category, location)
for lead in leads:
if lead['domain'] not in seen_domains:
seen_domains.add(lead['domain'])
all_leads.append(extract_contacts(lead))
time.sleep(0.3)
return all_leads
leads = run_pipeline(locations[:2], categories[:2]) # small test
print(f'Total unique leads: {len(leads)}')
# Export to CSV
if leads:
with open('local_leads.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['business_name', 'domain',
'phone', 'email', 'rating', 'category', 'location', 'website'])
writer.writeheader()
writer.writerows(leads)
print(f'Exported to local_leads.csv')
queries_used = len(locations[:2]) * len(categories[:2])
print(f'Cost: {queries_used} queries = ${queries_used * 0.005:.3f}')Ejemplo en Python
import requests, os, re, time, csv
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def find_leads(category, location):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{category} in {location}', 'country_code': 'us', 'num_results': 10})
leads = []
for r in resp.json().get('organic_results', []):
domain = r['link'].split('/')[2] if '/' in r['link'] else ''
if not any(a in domain for a in ['yelp.com', 'yellowpages.com', 'angi.com']):
phones = re.findall(r'\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}', r.get('snippet', ''))
leads.append({'name': r['title'].split(' - ')[0], 'domain': domain,
'phone': phones[0] if phones else ''})
return leads
leads = find_leads('plumber', 'Austin TX')
for l in leads[:5]:
print(f'{l["name"]}: {l["domain"]} {l["phone"]}')Ejemplo en JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function findLeads(category, location) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `${category} in ${location}`, country_code: 'us', num_results: 10 })
});
const data = await resp.json();
return (data.organic_results || []).filter(r => {
const domain = new URL(r.link).hostname;
return !['yelp.com', 'yellowpages.com', 'angi.com'].some(a => domain.includes(a));
}).map(r => ({
name: r.title.split(' - ')[0],
link: r.link,
phone: (r.snippet || '').match(/\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/)?.[0] || ''
}));
}
findLeads('plumber', 'Austin TX').then(leads => leads.forEach(l => console.log(`${l.name}: ${l.phone}`)));Salida esperada
5 cities x 4 categories = 20 queries
Estimated cost: $0.10
Found 7 leads for plumber in Austin TX
Radiant Plumbing: radiantplumbing.com
ABC Home Services: abchomeservices.com
Mr Rooter Plumbing: mrrooter.com
Total unique leads: 24
Exported to local_leads.csv
Cost: 4 queries = $0.020