Elige la región
Sigue Google.de desde Europa, Yandex desde la CEI y Baidu desde China. World MIX cubre el resto y trae los pools más grandes.
Los buscadores muestran resultados por región, así que un rank checker necesita una IP del país adecuado para cada tanda de consultas. Resi Core da una dirección doméstica de cualquiera de más de 200 países directamente en la cadena de conexión, mientras que los paquetes ilimitados con filtro de país cubren las listas grandes de palabras clave. Una sección aparte trata el seguimiento de las respuestas de IA de Google, que también dependen del país y la ciudad.
Las posiciones dependen de dónde sale la consulta. El pool tiene que resolver eso primero.
Direcciones del país que sigues
Resi Core: el país va en el usuario; en los paquetes, una columna de país en el CSV exportado
Una IP nueva para cada tanda de consultas
Resi Core cambia la dirección en cada petición, y los paquetes renuevan cerca de un tercio de las direcciones cada día
Consultas en paralelo para una lista grande de palabras clave
Sin límite de hilos en Resi, de 500 a 5000 hilos en los paquetes
Funciona con el checker que ya usas
Resi con usuario y contraseña en la cadena, los paquetes por IP; A-Parser, Key Collector y Rank Tracker aceptan HTTP y SOCKS5
Una página de resultados pesa poco, así que un gigabyte cubre miles de consultas. El precio por GB baja con el tamaño del pedido.
| Tamaño del pedido | Resi Core | Resi Prime |
|---|---|---|
| 1 GB+ | $0.85 | $2.29 |
| 10 GB+ahorra un 7% | $0.79 | $2.09 |
| 50 GB+ | $0.72 | $1.95 |
| 100 GB+ | $0.65 | $1.75 |
| 500 GB+ | $0.57 | $1.55 |
| 1000 GB+ | $0.49 | $1.39 |
Precios en dólares estadounidenses por 1 GB. Se compran gigabytes enteros, a partir de uno.
Pool
Ahorras un 7% ($1.50) frente al precio de 1 GB+
Añade 25 GB y cada gigabyte baja a $0.72
Comprar esta cantidadPuedes usar los gigabytes durante 3 meses desde la compra; lo que quede después se da de baja.
Sigue Google.de desde Europa, Yandex desde la CEI y Baidu desde China. World MIX cubre el resto y trae los pools más grandes.
Toma la exportación CSV y quédate con las filas cuya columna de país coincida con el mercado que sigues; el generador listo te escribe un archivo ip:port por país.
Los rank checkers aceptan un archivo de proxies o una URL. Programa la recarga cada 10 minutos y tendrás siempre la lista fresca.
Fija DOMAIN y COUNTRY y pon tus palabras clave en keywords.txt. El script consulta el buscador a través de un proxy de ese país y escribe la posición de tu dominio en un CSV. Dale un pool limpio del comprobador de proxies.
#!/usr/bin/env python3
"""Search-position checker for Advanced.name proxies.
Reads the CSV proxy export, keeps one country, then asks a search engine for each
keyword through a proxy from that country and reports where your domain sits in
the results. Standard library only. Edit CONFIG and run: python3 rank.py
"""
# ================================ CONFIG ====================================
CSV_URL = "https://get.advanced.name/YOUR_LIST_ID.csv" # CSV export link from your dashboard
COUNTRY = "DE" # ISO 3166-1 alpha-2: positions are read from this country
MIN_SPEED = 3 # keep proxies with speed >= this value
DOMAIN = "example.com" # the domain whose position you track
KEYWORDS_FILE = "keywords.txt" # one keyword per line
SEARCH_URL = "https://www.bing.com/search?q={q}&count=50&setlang={cc}" # {q}=keyword, {cc}=country
OUT_FILE = "positions.csv" # keyword;position;proxy is written here
TIMEOUT = 20
# ============================================================================
import csv
import io
import re
import sys
import urllib.parse
import urllib.request
COL_IP, COL_PORT, COL_COUNTRY, COL_SPEED = 0, 1, 2, 3
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0 Safari/537.36"
HREF = re.compile(r'href="https?://([^/"]+)', re.I)
def load_proxies():
raw = urllib.request.urlopen(CSV_URL, timeout=30).read().decode("utf-8", "replace")
pool = []
for row in csv.reader(io.StringIO(raw), delimiter=";"):
if len(row) <= COL_SPEED or not row[COL_PORT].strip().isdigit():
continue
if COUNTRY and row[COL_COUNTRY].strip().upper() != COUNTRY.upper():
continue
if int(row[COL_SPEED] or 0) < MIN_SPEED:
continue
pool.append(row[COL_IP].strip() + ":" + row[COL_PORT].strip())
return pool
def position(html, domain):
"""First place the domain shows up among the result links, or 0 if absent."""
rank, seen = 0, set()
for host in HREF.findall(html):
host = host.lower()
if "bing.com" in host or "microsoft.com" in host or host in seen:
continue
seen.add(host)
rank += 1
if host == domain or host.endswith("." + domain):
return rank
return 0
def main():
proxies = load_proxies()
if not proxies:
sys.exit("No proxies for COUNTRY=%r." % COUNTRY)
with open(KEYWORDS_FILE, encoding="utf-8") as fh:
keywords = [line.strip() for line in fh if line.strip()]
print("proxies: %d (%s), keywords: %d" % (len(proxies), COUNTRY, len(keywords)))
with open(OUT_FILE, "w", encoding="utf-8", newline="") as out:
writer = csv.writer(out, delimiter=";")
writer.writerow(["keyword", "position", "proxy"])
for i, keyword in enumerate(keywords):
proxy = proxies[i % len(proxies)]
url = SEARCH_URL.format(q=urllib.parse.quote(keyword), cc=COUNTRY.lower())
handler = urllib.request.ProxyHandler({"http": "http://" + proxy, "https": "http://" + proxy})
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": COUNTRY.lower()})
try:
html = urllib.request.build_opener(handler).open(req, timeout=TIMEOUT).read().decode("utf-8", "replace")
pos = position(html, DOMAIN.lower())
except Exception as exc:
pos = "err: %s" % exc.__class__.__name__
writer.writerow([keyword, pos, proxy])
print("%-40s %s" % (keyword[:40], pos))
print("written %s" % OUT_FILE)
if __name__ == "__main__":
main()
Pega una línea Resi de tu panel, fija DOMAIN y pon las palabras clave en keywords.txt. El script abre los resultados en un Chromium real a través del proxy, espera a que el bloque de IA termine de cargar y escribe en CSV si el bloque está, qué dominios cita y si el tuyo está entre ellos. Cierra solo el banner de cookies de la UE y marca un captcha o un error del proxy en una línea aparte. Google cambia su marcado, así que el encabezado del bloque vive en LABELS.
#!/usr/bin/env python3
"""AI Overview tracker for Advanced.name residential proxies.
Opens Google results for every keyword through a Resi Core or Resi Prime line
in a real Chromium, because the AI block is drawn by JavaScript. Records
whether the page shows the AI block and which domains it cites.
Setup: pip install playwright && python -m playwright install chromium
"""
# ================================ CONFIG ====================================
PROXY = "res.advanced.name:9000:USER-type-residential-country-us:PASS" # host:port:login:password line from your dashboard
DOMAIN = "example.com" # the domain you want to see among the cited sources
KEYWORDS_FILE = "keywords.txt" # one keyword per line
SEARCH_URL = "https://www.google.com/search?q={q}&hl={hl}&gl={gl}" # {q}=keyword
HL = "en" # interface language of the results page
GL = "us" # country of the results, keep it equal to the country in the login
LABELS = "AI Overview|AI Mode" # heading text of the AI block, separated by |
CONSENT = "Reject all|Accept all" # cookie banner buttons in EU countries, in the HL language
OUT_FILE = "ai_overview.csv" # keyword;ai_block;cited;your_domain is written here
WAIT_MS = 4000 # time for the AI block to finish drawing
HEADLESS = True # set False to watch the browser
# ============================================================================
import csv
import sys
import urllib.parse
from playwright.sync_api import sync_playwright
FIND_BLOCK = """(labels) => {
const heads = [...document.querySelectorAll('h1,h2,h3,div,span')]
.filter(e => e.children.length === 0 && labels.includes(e.textContent.trim()));
if (!heads.length) return null;
let box = heads[0];
for (let i = 0; i < 8 && box.parentElement; i++) {
box = box.parentElement;
const links = [...box.querySelectorAll('a[href^="http"]')];
if (links.length >= 2 && box.innerText.length > 200) return links.map(a => new URL(a.href).hostname);
}
return [];
}"""
def proxy_of(line):
host, port, user, password = line.strip().split(":", 3)
return {"server": "http://%s:%s" % (host, port), "username": user, "password": password}
def bare(host):
host = host.lower()
return host[4:] if host.startswith("www.") else host
def main():
keywords = [k.strip() for k in open(KEYWORDS_FILE, encoding="utf-8") if k.strip()]
labels = [x.strip() for x in LABELS.split("|") if x.strip()]
consent = [x.strip() for x in CONSENT.split("|") if x.strip()]
rows = []
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=HEADLESS, proxy=proxy_of(PROXY))
page = browser.new_page(locale=HL)
for kw in keywords:
url = SEARCH_URL.format(q=urllib.parse.quote_plus(kw), hl=HL, gl=GL)
try:
resp = page.goto(url, wait_until="domcontentloaded", timeout=60000)
if resp is None or resp.status >= 400:
status = "http %s" % (resp.status if resp else "none")
print("%-40s %s" % (kw[:40], status), file=sys.stderr)
rows.append([kw, status, "", ""])
continue
for name in consent:
button = page.get_by_role("button", name=name)
if button.count():
button.first.click()
page.wait_for_load_state("domcontentloaded")
break
if "/sorry/" in page.url:
print("%-40s captcha: change the session id in the login" % kw[:40], file=sys.stderr)
rows.append([kw, "captcha", "", ""])
continue
page.wait_for_timeout(WAIT_MS)
hosts = page.evaluate(FIND_BLOCK, labels)
except Exception as exc:
print("%-40s error: %s" % (kw[:40], str(exc).splitlines()[0]), file=sys.stderr)
rows.append([kw, "error", "", ""])
continue
if hosts is None:
print("%-40s no AI block" % kw[:40])
rows.append([kw, "no", "", ""])
continue
cited = sorted({bare(h) for h in hosts if "google." not in h})
mine = any(h == DOMAIN or h.endswith("." + DOMAIN) for h in cited)
print("%-40s AI block, %d sources, %s %s" % (kw[:40], len(cited), DOMAIN, "cited" if mine else "not cited"))
rows.append([kw, "yes", " ".join(cited), "yes" if mine else "no"])
browser.close()
with open(OUT_FILE, "w", encoding="utf-8", newline="") as f:
out = csv.writer(f, delimiter=";")
out.writerow(["keyword", "ai_block", "cited", "your_domain"])
out.writerows(rows)
print("saved", OUT_FILE)
if __name__ == "__main__":
main()
En A-Parser y Key Collector pega la lista ip:port en el campo de proxies y fija el intervalo de comprobación para que una palabra clave pase por una dirección como mucho una vez al día. Rank Tracker y programas de escritorio parecidos leen un archivo de proxies; apúntalos a la lista que el generador escribe por país.
Las posiciones dependen de dónde sale la consulta, así que lleva una lista aparte por mercado: una instancia del tracker por país y, en cada una, solo direcciones de ese país.
El script de arriba consulta el buscador con un proxy del país y anota el puesto de tu dominio. Envía los parámetros de idioma y región del buscador junto con el proxy: la dirección fija el país y los parámetros, la ciudad.
Revisa el pool antes de cada pasada con el comprobador de proxies; para una prueba manual ligera sirve la lista de proxies gratis. Una introducción a las SERP regionales estará en los artículos.
Cada vez más a menudo Google pone un bloque de IA encima de los resultados normales: una respuesta corta con enlaces a fuentes. Parte de los clics se va ahí, así que necesitas saber si tu sitio entró en las fuentes y qué consultas no muestran el bloque. El bloque se construye según la ubicación del usuario: para una misma consulta, Berlín y Múnich pueden ver fuentes distintas.
Un scraper de resultados normal nunca ve este bloque: Google lo dibuja con JavaScript después de cargar la página. Necesitas un navegador real, como Chromium con Playwright, y una IP doméstica del país adecuado. Las direcciones de lista suelen toparse con captcha en estos resultados, y por eso aquí trabajan Resi Core y Resi Prime.
Para el seguimiento por país basta Resi Core con el código de país en el usuario. Cuando al cliente le importa una ciudad, toma Resi Prime con la ciudad en la cadena y una sesión fija por tanda de consultas: así toda la tanda sale desde una dirección de esa ciudad.
Pasa la lista de palabras clave una vez al día o una vez a la semana: el bloque de IA cambia más despacio que las posiciones normales. Para cada consulta anota la fecha, el país o la ciudad, si el bloque está, qué dominios cita y si el tuyo está entre ellos. Al cabo de un mes verás qué páginas toma la IA para su respuesta y cuáles se cayeron.
El segundo script de arriba escribe justo esos campos en CSV. El primer script sigue las posiciones normales en el mismo país, así que los dos informes cuadran por consulta.

Sigue los resultados por país con Resi Core y por ciudad con Resi Prime, y pasa las listas grandes de palabras clave cada día con un paquete ilimitado por menos.
Resultados por paísLa mejor opción
Una IP doméstica del país adecuado en cada petición. Una página de resultados pesa poco, así que un gigabyte cubre miles de consultas.
desde $0.49 por GB1 GB por $0.85
Resultados por ciudad
La ciudad y la región en la cadena de conexión dan los resultados que ve un usuario de esa ciudad.
desde $1.39 por GB1 GB por $2.29
Listas grandes de palabras clave
Decenas de miles de consultas al día sin contador de tráfico. El país del mercado lo eliges por la columna del CSV exportado.
$378 al meso $2.10 por hora
Toma 1 GB de Resi Core, fija el país en la cadena y pon el checker sobre direcciones vivas.