Des millions d'entreprises locales fonctionnent encore sans site web, se reposant uniquement sur Google Business Profile, Yelp ou Facebook. Ce sont des prospects de choix pour les agences de conception web, les services de référencement local et le marketing numérique. Ce tutoriel utilise les données SERP pour identifier les entreprises qui n'apparaissent que dans les annuaires mais qui ne possèdent pas leur propre domaine. Chaque recherche coûte $0.005 et révèle généralement 3 à 5 entreprises sans site web par requête.
Prérequis
- Python 3.9+ installé
- bibliothèque requests installée
- Une clé API Scavio depuis scavio.dev
Parcours
Étape 1: Rechercher des entreprises locales et classer les résultats
Recherchez une catégorie d'entreprise et un lieu, puis classez chaque résultat comme ayant son propre site web ou apparaissant uniquement sur des annuaires.
import requests, os, re
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
DIRECTORY_DOMAINS = {
'yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org',
'angi.com', 'homeadvisor.com', 'thumbtack.com', 'mapquest.com',
'manta.com', 'chamberofcommerce.com', 'google.com',
'nextdoor.com', 'bark.com', 'expertise.com'
}
def classify_result(result: dict) -> str:
link = result.get('link', '')
domain = link.split('/')[2] if '/' in link else ''
base = '.'.join(domain.split('.')[-2:]) # e.g., yelp.com
if base in DIRECTORY_DOMAINS:
return 'directory'
return 'own_website'
def find_no_website(category: str, location: str) -> list:
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})
results = resp.json().get('organic_results', [])
directory_only = []
for r in results:
if classify_result(r) == 'directory':
# Extract business name from directory listing title
name = r['title'].split(' - ')[0].split(' | ')[0].strip()
directory_only.append({
'name': name, 'listing_url': r['link'],
'directory': r['link'].split('/')[2],
'snippet': r.get('snippet', ''),
'category': category, 'location': location
})
return directory_only
prospects = find_no_website('plumber', 'Austin TX')
print(f'Found {len(prospects)} businesses without websites')
for p in prospects[:5]:
print(f' {p["name"]} (via {p["directory"]})')Étape 2: Vérifier que les entreprises n'ont vraiment pas de site web
Vérifiez en recherchant directement chaque nom d'entreprise. Si aucun domaine propre n'apparaît dans les résultats, ils n'ont probablement pas de site web.
import time
def verify_no_website(business_name: str, location: str) -> dict:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{business_name} {location}',
'country_code': 'us', 'num_results': 5})
results = resp.json().get('organic_results', [])
for r in results:
if classify_result(r) == 'own_website':
return {'has_website': True, 'website': r['link']}
return {'has_website': False, 'website': None}
# Verify top prospects
verified_prospects = []
for p in prospects[:5]:
check = verify_no_website(p['name'], p['location'])
p['verified_no_website'] = not check['has_website']
p['found_website'] = check['website']
if not check['has_website']:
verified_prospects.append(p)
status = 'NO WEBSITE' if not check['has_website'] else f'Has: {check["website"]}'
print(f' {p["name"]}: {status}')
time.sleep(0.3)
print(f'\nVerified {len(verified_prospects)} businesses without websites')Étape 3: Passer à l'échelle sur plusieurs lieux et exporter
Exécutez le pipeline sur de nombreuses paires lieu-catégorie et exportez les prospects vérifiés.
import csv
def pipeline(categories: list, locations: list) -> list:
all_prospects = []
queries = 0
for loc in locations:
for cat in categories:
prospects = find_no_website(cat, loc)
queries += 1
for p in prospects[:3]: # verify top 3 per query
check = verify_no_website(p['name'], p['location'])
queries += 1
if not check['has_website']:
all_prospects.append(p)
time.sleep(0.3)
print(f'Queries used: {queries} (${queries * 0.005:.3f})')
return all_prospects
categories = ['plumber', 'electrician']
locations = ['Austin TX', 'Denver CO']
prospects = pipeline(categories, locations)
if prospects:
with open('no_website_leads.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'directory', 'listing_url',
'category', 'location'])
writer.writeheader()
for p in prospects:
writer.writerow({k: p[k] for k in writer.fieldnames})
print(f'Exported {len(prospects)} leads to no_website_leads.csv')Exemple Python
import requests, os
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
DIRS = {'yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org', 'angi.com'}
def find_no_website(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})
prospects = []
for r in resp.json().get('organic_results', []):
domain = r['link'].split('/')[2] if '/' in r['link'] else ''
base = '.'.join(domain.split('.')[-2:])
if base in DIRS:
prospects.append({'name': r['title'].split(' - ')[0], 'directory': base})
return prospects
for p in find_no_website('plumber', 'Austin TX'):
print(f'{p["name"]} (via {p["directory"]})')Exemple JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const DIRS = new Set(['yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org', 'angi.com']);
async function findNoWebsite(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.split('.').slice(-2).join('.');
return DIRS.has(domain);
}).map(r => ({ name: r.title.split(' - ')[0], directory: new URL(r.link).hostname }));
}
findNoWebsite('plumber', 'Austin TX').then(p => p.forEach(x => console.log(`${x.name} (${x.directory})`)));Sortie attendue
Found 5 businesses without websites
Joe's Plumbing (via yelp.com)
Reliable Plumbing Services (via yellowpages.com)
Quick Fix Plumbing (via facebook.com)
Joe's Plumbing: NO WEBSITE
Reliable Plumbing Services: Has: reliableplumbingaustin.com
Quick Fix Plumbing: NO WEBSITE
Verified 3 businesses without websites
Queries used: 10 ($0.050)
Exported 8 leads to no_website_leads.csv