La mayoría de los rastreadores de clasificación están construidos sobre frágiles raspadores que se rompen cada vez que Google cambia su HTML. Al utilizar la API de Scavio como capa de datos, puede crear un rastreador de clasificación que devuelva datos de posición estructurados sin mantener servidores proxy ni analizadores. Este tutorial crea una API Flask liviana que acepta entradas de palabras clave y dominios, verifica las posiciones de Google a través de Scavio, almacena los resultados en SQLite y expone datos de clasificación históricos a través de un punto final REST.
Requisitos previos
- Python 3.10 o superior
- matraz de solicitudes de instalación de pip
- Una clave API de Scavio
- Comprensión básica del diseño de API REST
Guia paso a paso
Paso 1: Configurar la base de datos SQLite
Cree una tabla simple para almacenar palabras clave, dominio, posición y marca de tiempo para cada verificación.
import sqlite3
def init_db(path: str = "rankings.db") -> None:
conn = sqlite3.connect(path)
conn.execute("""
CREATE TABLE IF NOT EXISTS rankings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT NOT NULL,
domain TEXT NOT NULL,
position INTEGER,
checked_at TEXT DEFAULT (datetime('now'))
)
""")
conn.commit()
conn.close()Paso 2: Consultar rango a través de Scavio
Consulta Google a través de la API de Scavio y escanea los resultados para el dominio de destino. Devuelve la posición o Ninguno.
import requests
def check_rank(keyword: str, domain: str) -> int | None:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"query": keyword, "country_code": "us"}
)
r.raise_for_status()
for result in r.json().get("organic_results", []):
if domain in result.get("link", ""):
return result["position"]
return NonePaso 3: Almacenar y recuperar clasificaciones
Guarde cada verificación de clasificación en SQLite y proporcione una función para consultar datos históricos.
def save_rank(keyword: str, domain: str, position: int | None) -> None:
conn = sqlite3.connect("rankings.db")
conn.execute("INSERT INTO rankings (keyword, domain, position) VALUES (?, ?, ?)",
(keyword, domain, position))
conn.commit()
conn.close()
def get_history(keyword: str, domain: str, days: int = 30) -> list[dict]:
conn = sqlite3.connect("rankings.db")
rows = conn.execute(
"SELECT position, checked_at FROM rankings WHERE keyword=? AND domain=? ORDER BY checked_at DESC LIMIT ?",
(keyword, domain, days)
).fetchall()
conn.close()
return [{"position": r[0], "date": r[1]} for r in rows]Paso 4: Exponer como API de Flask
Cree dos puntos finales: POST /check para activar una verificación de clasificación y GET /history para recuperar posiciones almacenadas.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/check", methods=["POST"])
def check():
data = request.json
pos = check_rank(data["keyword"], data["domain"])
save_rank(data["keyword"], data["domain"], pos)
return jsonify({"keyword": data["keyword"], "domain": data["domain"], "position": pos})
@app.route("/history")
def history():
kw = request.args["keyword"]
domain = request.args["domain"]
return jsonify(get_history(kw, domain))Ejemplo en Python
import os
import sqlite3
import requests
from flask import Flask, request, jsonify
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
DB = "rankings.db"
def init_db():
conn = sqlite3.connect(DB)
conn.execute("CREATE TABLE IF NOT EXISTS rankings (id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT, domain TEXT, position INTEGER, checked_at TEXT DEFAULT (datetime('now')))")
conn.commit()
conn.close()
def check_rank(keyword: str, domain: str) -> int | None:
r = requests.post(ENDPOINT, headers={"x-api-key": API_KEY},
json={"query": keyword, "country_code": "us"})
r.raise_for_status()
for res in r.json().get("organic_results", []):
if domain in res.get("link", ""):
return res["position"]
return None
app = Flask(__name__)
@app.route("/check", methods=["POST"])
def check():
d = request.json
pos = check_rank(d["keyword"], d["domain"])
conn = sqlite3.connect(DB)
conn.execute("INSERT INTO rankings (keyword, domain, position) VALUES (?, ?, ?)", (d["keyword"], d["domain"], pos))
conn.commit()
conn.close()
return jsonify({"keyword": d["keyword"], "position": pos})
if __name__ == "__main__":
init_db()
app.run(port=5000)Ejemplo en JavaScript
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";
async function checkRank(keyword, domain) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query: keyword, country_code: "us" })
});
const data = await res.json();
const match = (data.organic_results || []).find(r => r.link.includes(domain));
return match ? match.position : null;
}
async function main() {
const keywords = ["python api tutorial", "rest api guide"];
const domain = "mysite.com";
for (const kw of keywords) {
const pos = await checkRank(kw, domain);
console.log(`${kw}: ${pos ? "#" + pos : "not ranked"}`);
}
}
main().catch(console.error);Salida esperada
POST /check {"keyword": "python api tutorial", "domain": "mysite.com"}
=> {"keyword": "python api tutorial", "position": 6}
GET /history?keyword=python+api+tutorial&domain=mysite.com
=> [{"position": 6, "date": "2026-04-19"}, {"position": 7, "date": "2026-04-18"}]