Ahora es posible realizar un seguimiento de las clasificaciones de búsqueda local sin hacks de parámetros UULE a través de API de búsqueda con orientación geográfica que manejan la simulación de ubicación en el lado del servidor. Los parámetros UULE (las cadenas de ubicación codificadas adjuntas a las URL de búsqueda de Google) son frágiles, no están documentadas y se rompen cuando Google cambia su formato. La API de búsqueda de Scavio acepta un campo de ubicación junto con su consulta, devolviendo SERP tal como aparecen en esa ciudad o región específica sin ninguna codificación UULE del lado del cliente. Este tutorial crea un rastreador de clasificación local que monitorea las posiciones de las palabras clave en múltiples ubicaciones y detecta diferencias de clasificación entre ciudades.
Requisitos previos
- Python 3.8 o superior instalado
- solicita biblioteca instalada (solicitudes de instalación de pip)
- Una clave API de Scavio de scavio.dev
- Orientar palabras clave y ubicaciones para realizar un seguimiento
Guia paso a paso
Paso 1: Definir palabras clave y ubicaciones de destino
Cree una configuración que asigne palabras clave a las ubicaciones que desea rastrear. Cada ubicación es una cadena de ciudad o región que la API utiliza para la orientación geográfica. Incluya su propio dominio para rastrear su posición.
TRACKING_CONFIG = {
'keywords': [
'plumber near me',
'emergency plumbing service',
'water heater repair'
],
'locations': [
'Austin, Texas, United States',
'Dallas, Texas, United States',
'Houston, Texas, United States',
'San Antonio, Texas, United States'
],
'my_domain': 'austinplumbingpros.com'
}Paso 2: Obtener resultados de búsqueda orientados geográficamente
PUBLICAR en la API de Scavio con el campo de ubicación configurado en la ciudad de destino. La API devuelve SERP vistas desde esa ubicación, incluidos resultados de paquetes locales, posiciones orgánicas y listados de mapas.
import requests
import os
API_KEY = os.environ.get('SCAVIO_API_KEY', 'your_scavio_api_key')
def fetch_local_serp(query: str, location: str) -> dict:
response = requests.post(
'https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY},
json={
'query': query,
'country_code': 'us',
'location': location
}
)
response.raise_for_status()
return response.json()Paso 3: Extraer posición para su dominio
Busque los resultados orgánicos y el paquete local para su dominio. Devuelve la posición si se encuentra, o Ninguno si su dominio no aparece en los primeros resultados para esa ubicación.
def find_domain_position(data: dict, domain: str) -> dict:
result = {'organic_position': None, 'local_pack_position': None}
for r in data.get('organic_results', []):
if domain in r.get('link', ''):
result['organic_position'] = r.get('position')
break
for i, r in enumerate(data.get('local_pack', []), 1):
if domain in r.get('link', '') or domain in r.get('website', ''):
result['local_pack_position'] = i
break
return resultPaso 4: Ejecute el rastreador en todos los pares de palabras clave-ubicación
Itere todas las combinaciones de palabras clave y ubicaciones, obtenga resultados, extraiga posiciones e imprima una tabla comparativa que muestre cómo las clasificaciones difieren según la ciudad.
from datetime import datetime
import json
from pathlib import Path
def run_local_tracker():
results = []
config = TRACKING_CONFIG
print(f'Local Rank Tracker - {datetime.now().strftime("%Y-%m-%d %H:%M")}')
print(f'{"Keyword":<30} {"Location":<35} {"Organic":<10} {"Local Pack"}')
print('-' * 90)
for keyword in config['keywords']:
for location in config['locations']:
data = fetch_local_serp(keyword, location)
pos = find_domain_position(data, config['my_domain'])
organic = str(pos['organic_position']) if pos['organic_position'] else '--'
local_pack = str(pos['local_pack_position']) if pos['local_pack_position'] else '--'
print(f'{keyword:<30} {location:<35} {organic:<10} {local_pack}')
results.append({
'keyword': keyword, 'location': location,
'organic': pos['organic_position'],
'local_pack': pos['local_pack_position'],
'timestamp': datetime.now().isoformat()
})
Path('local_rankings.json').write_text(json.dumps(results, indent=2))
print(f'\nSaved {len(results)} data points to local_rankings.json')
run_local_tracker()Ejemplo en Python
import os
import json
import requests
from pathlib import Path
from datetime import datetime
API_KEY = os.environ.get('SCAVIO_API_KEY', 'your_scavio_api_key')
ENDPOINT = 'https://api.scavio.dev/api/v1/search'
TRACKING_CONFIG = {
'keywords': ['plumber near me', 'emergency plumbing service', 'water heater repair'],
'locations': [
'Austin, Texas, United States',
'Dallas, Texas, United States',
'Houston, Texas, United States',
'San Antonio, Texas, United States'
],
'my_domain': 'austinplumbingpros.com'
}
def fetch_local_serp(query: str, location: str) -> dict:
response = requests.post(
ENDPOINT,
headers={'x-api-key': API_KEY},
json={'query': query, 'country_code': 'us', 'location': location}
)
response.raise_for_status()
return response.json()
def find_domain_position(data: dict, domain: str) -> dict:
result = {'organic_position': None, 'local_pack_position': None}
for r in data.get('organic_results', []):
if domain in r.get('link', ''):
result['organic_position'] = r.get('position')
break
for i, r in enumerate(data.get('local_pack', []), 1):
if domain in r.get('link', '') or domain in r.get('website', ''):
result['local_pack_position'] = i
break
return result
def run_local_tracker():
config = TRACKING_CONFIG
results = []
print(f'Local Rank Tracker - {datetime.now().strftime("%Y-%m-%d %H:%M")}')
print(f'{"Keyword":<30} {"Location":<35} {"Organic":<10} {"Local Pack"}')
print('-' * 90)
for keyword in config['keywords']:
for location in config['locations']:
data = fetch_local_serp(keyword, location)
pos = find_domain_position(data, config['my_domain'])
organic = str(pos['organic_position']) if pos['organic_position'] else '--'
local_pack = str(pos['local_pack_position']) if pos['local_pack_position'] else '--'
print(f'{keyword:<30} {location:<35} {organic:<10} {local_pack}')
results.append({
'keyword': keyword, 'location': location,
'organic': pos['organic_position'],
'local_pack': pos['local_pack_position'],
'timestamp': datetime.now().isoformat()
})
Path('local_rankings.json').write_text(json.dumps(results, indent=2))
print(f'\nSaved {len(results)} data points to local_rankings.json')
if __name__ == '__main__':
run_local_tracker()Ejemplo en JavaScript
const API_KEY = process.env.SCAVIO_API_KEY || 'your_scavio_api_key';
const ENDPOINT = 'https://api.scavio.dev/api/v1/search';
const fs = require('fs');
const TRACKING_CONFIG = {
keywords: ['plumber near me', 'emergency plumbing service', 'water heater repair'],
locations: [
'Austin, Texas, United States',
'Dallas, Texas, United States',
'Houston, Texas, United States',
'San Antonio, Texas, United States'
],
myDomain: 'austinplumbingpros.com'
};
async function fetchLocalSerp(query, location) {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', location })
});
if (!response.ok) throw new Error('HTTP ' + response.status);
return response.json();
}
function findDomainPosition(data, domain) {
const result = { organicPosition: null, localPackPosition: null };
for (const r of (data.organic_results || [])) {
if ((r.link || '').includes(domain)) {
result.organicPosition = r.position;
break;
}
}
(data.local_pack || []).forEach((r, i) => {
if ((r.link || '').includes(domain) || (r.website || '').includes(domain)) {
if (!result.localPackPosition) result.localPackPosition = i + 1;
}
});
return result;
}
async function main() {
const config = TRACKING_CONFIG;
const results = [];
console.log('Local Rank Tracker - ' + new Date().toISOString().slice(0, 16));
for (const keyword of config.keywords) {
for (const location of config.locations) {
const data = await fetchLocalSerp(keyword, location);
const pos = findDomainPosition(data, config.myDomain);
const organic = pos.organicPosition !== null ? String(pos.organicPosition) : '--';
const localPack = pos.localPackPosition !== null ? String(pos.localPackPosition) : '--';
console.log(keyword.padEnd(30) + location.padEnd(35) + organic.padEnd(10) + localPack);
results.push({ keyword, location, organic: pos.organicPosition, localPack: pos.localPackPosition, timestamp: new Date().toISOString() });
}
}
fs.writeFileSync('local_rankings.json', JSON.stringify(results, null, 2));
console.log('Saved ' + results.length + ' data points');
}
main().catch(console.error);Salida esperada
Local Rank Tracker - 2026-05-12 14:30
Keyword Location Organic Local Pack
------------------------------------------------------------------------------------------
plumber near me Austin, Texas, United States 3 1
plumber near me Dallas, Texas, United States -- --
plumber near me Houston, Texas, United States -- --
plumber near me San Antonio, Texas, United States 12 --
emergency plumbing service Austin, Texas, United States 2 1
emergency plumbing service Dallas, Texas, United States -- --
Saved 12 data points to local_rankings.json