Los rastreadores de clasificación empresarial cobran entre 50 y 200 dólares al mes por monitorear un puñado de palabras clave. Con la API de búsqueda de Scavio a $0,005/crédito, puede realizar un seguimiento de 50 palabras clave diariamente por $0,035/semana, menos de $2/año. Este tutorial crea un rastreador de clasificación completo con almacenamiento SQLite, programación cron diaria y alertas de cambio de posición.
Requisitos previos
- Python 3.11+
- Una clave API de Scavio de https://scavio.dev
- SQLite3 (incluido con Python)
- Un programador cron o programador de tareas para ejecuciones diarias
Guia paso a paso
Paso 1: Configurar la base de datos SQLite y la lista de palabras clave
Cree una base de datos SQLite para almacenar instantáneas de clasificación diaria. Cada fila registra la palabra clave, la posición del dominio de destino, la fecha y la URL que clasificó.
import sqlite3
from pathlib import Path
DB_PATH = Path("rank_tracker.db")
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS rankings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT NOT NULL,
position INTEGER,
url TEXT,
checked_at TEXT NOT NULL,
domain TEXT NOT NULL
)
""")
conn.execute("""
CREATE INDEX IF NOT EXISTS idx_keyword_date
ON rankings(keyword, checked_at)
""")
conn.commit()
conn.close()
KEYWORDS = [
"best API for web scraping 2026",
"cheap search API for agents",
"MCP server search tool",
# ... add up to 50 keywords
]
TARGET_DOMAIN = "scavio.dev"
init_db()Paso 2: Verifique las clasificaciones a través de la API de búsqueda de Scavio
Para cada palabra clave, busque y encuentre la posición de su dominio objetivo en los resultados. Almacene la posición (o nula si no se encuentra en los resultados principales) en la base de datos.
import httpx
from datetime import date
SCAVIO_API_KEY = "your-api-key"
async def check_ranking(client: httpx.AsyncClient, keyword: str) -> dict:
resp = await client.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": SCAVIO_API_KEY},
json={"query": keyword, "num_results": 10}
)
resp.raise_for_status()
results = resp.json().get("results", [])
for i, r in enumerate(results):
url = r.get("url", "")
if TARGET_DOMAIN in url:
return {"position": i + 1, "url": url}
return {"position": None, "url": None}
async def check_all_keywords():
conn = sqlite3.connect(DB_PATH)
today = date.today().isoformat()
async with httpx.AsyncClient(timeout=15) as client:
for keyword in KEYWORDS:
result = await check_ranking(client, keyword)
conn.execute(
"INSERT INTO rankings (keyword, position, url, checked_at, domain) VALUES (?, ?, ?, ?, ?)",
(keyword, result["position"], result["url"], today, TARGET_DOMAIN)
)
conn.commit()
conn.close()Paso 3: Detectar cambios de posición y generar alertas
Compare las clasificaciones de hoy con las de ayer. Marque cualquier palabra clave que se haya movido 3 o más posiciones en cualquier dirección.
def get_position_changes(threshold: int = 3) -> list[dict]:
conn = sqlite3.connect(DB_PATH)
rows = conn.execute("""
SELECT
r1.keyword,
r2.position AS prev_position,
r1.position AS curr_position,
r1.url,
r1.checked_at
FROM rankings r1
JOIN rankings r2
ON r1.keyword = r2.keyword
AND r1.domain = r2.domain
AND r2.checked_at = date(r1.checked_at, '-1 day')
WHERE r1.checked_at = date('now')
AND r1.position IS NOT NULL
AND r2.position IS NOT NULL
AND ABS(r1.position - r2.position) >= ?
ORDER BY ABS(r1.position - r2.position) DESC
""", (threshold,)).fetchall()
conn.close()
changes = []
for keyword, prev, curr, url, checked in rows:
direction = "up" if curr < prev else "down"
changes.append({
"keyword": keyword,
"previous": prev,
"current": curr,
"change": prev - curr,
"direction": direction,
"url": url
})
return changesPaso 4: Generar un costo diario y un informe resumido
Imprima un resumen que muestre el total de palabras clave rastreadas, los créditos utilizados, el costo y cualquier cambio de posición significativo. Programe este script con cron para la automatización diaria.
import asyncio
async def daily_report():
await check_all_keywords()
credits_used = len(KEYWORDS) # 1 credit per search
cost = credits_used * 0.005
weekly_cost = cost * 7
changes = get_position_changes(threshold=3)
print(f"Rank Tracker Report - {date.today().isoformat()}")
print(f"Keywords tracked: {len(KEYWORDS)}")
print(f"Credits used: {credits_used}")
print(f"Daily cost: {cost:.3f}")
print(f"Weekly cost: {weekly_cost:.3f}")
print(f"Position changes (3+): {len(changes)}")
for c in changes:
arrow = "improved" if c["direction"] == "up" else "dropped"
print(f" {c['keyword']}: #{c['previous']} -> #{c['current']} ({arrow} by {abs(c['change'])})")
asyncio.run(daily_report())
# Cron: 0 8 * * * cd /path/to/tracker && python rank_tracker.pyEjemplo en Python
import asyncio
import sqlite3
import httpx
from datetime import date
from pathlib import Path
SCAVIO_API_KEY = "your-api-key"
TARGET_DOMAIN = "scavio.dev"
DB_PATH = Path("rank_tracker.db")
KEYWORDS = [
"best API for web scraping 2026",
"cheap search API for agents",
"MCP server search tool",
]
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS rankings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT, position INTEGER, url TEXT,
checked_at TEXT, domain TEXT
)
""")
conn.commit()
conn.close()
async def check_ranking(client, keyword):
resp = await client.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": SCAVIO_API_KEY},
json={"query": keyword, "num_results": 10}
)
resp.raise_for_status()
for i, r in enumerate(resp.json().get("results", [])):
if TARGET_DOMAIN in r.get("url", ""):
return i + 1, r["url"]
return None, None
async def main():
init_db()
conn = sqlite3.connect(DB_PATH)
today = date.today().isoformat()
async with httpx.AsyncClient(timeout=15) as client:
for kw in KEYWORDS:
pos, url = await check_ranking(client, kw)
conn.execute(
"INSERT INTO rankings VALUES (NULL,?,?,?,?,?)",
(kw, pos, url, today, TARGET_DOMAIN)
)
conn.commit()
cost = len(KEYWORDS) * 0.005
print(f"Tracked {len(KEYWORDS)} keywords | Cost: {cost:.3f} | Weekly: {cost * 7:.3f}")
conn.close()
asyncio.run(main())Ejemplo en JavaScript
const SCAVIO_API_KEY = "your-api-key";
const TARGET_DOMAIN = "scavio.dev";
const KEYWORDS = [
"best API for web scraping 2026",
"cheap search API for agents",
"MCP server search tool"
];
async function checkRanking(keyword) {
const resp = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST",
headers: { "x-api-key": SCAVIO_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query: keyword, num_results: 10 })
});
const data = await resp.json();
const results = data.results || [];
for (let i = 0; i < results.length; i++) {
if ((results[i].url || "").includes(TARGET_DOMAIN)) {
return { position: i + 1, url: results[i].url };
}
}
return { position: null, url: null };
}
async function main() {
const rankings = [];
for (const kw of KEYWORDS) {
const rank = await checkRanking(kw);
rankings.push({ keyword: kw, ...rank });
}
const cost = KEYWORDS.length * 0.005;
console.log("Rankings:", JSON.stringify(rankings, null, 2));
console.log("Daily cost: $" + cost.toFixed(3));
console.log("Weekly cost: $" + (cost * 7).toFixed(3));
}
main();Salida esperada
Tracked 3 keywords | Cost: $0.015 | Weekly: $0.105