Choisissez la région
Suivez Google.de via l'Europe, Yandex via la CEI, Baidu via la Chine. World MIX couvre le reste et offre les plus gros pools.
Les moteurs de recherche affichent des résultats par région, donc un outil de suivi des positions a besoin d'une IP du bon pays pour chaque lot de requêtes. Resi Core donne une adresse résidentielle dans n'importe lequel des 200+ pays directement dans la chaîne de connexion, tandis que les packs illimités avec filtre par pays couvrent les grandes listes de mots-clés. Une section à part traite du suivi des réponses IA de Google, qui dépendent aussi du pays et de la ville.
Les positions dépendent de l'origine de la requête. Le pool doit d'abord répondre à cette question.
Des adresses du pays que vous suivez
Resi Core : le pays va dans le login ; sur les packs, une colonne pays dans l'export CSV
Une IP neuve pour chaque lot de requêtes
Resi Core change d'adresse à chaque requête, et les packs remplacent environ un tiers des adresses chaque jour
Assez de requêtes parallèles pour une grosse liste de mots-clés
Pas de limite de threads sur Resi, de 500 à 5000 threads sur les packs
Compatible avec l'outil que vous utilisez déjà
Resi par login et mot de passe dans la chaîne, les packs par IP ; A-Parser, Key Collector et Rank Tracker acceptent HTTP et SOCKS5
Une page de résultats pèse peu, donc un gigaoctet couvre des milliers de requêtes. Le prix au Go baisse avec la taille de la commande.
| Taille de la commande | Resi Core | Resi Prime |
|---|---|---|
| 1 Go+ | $0.85 | $2.29 |
| 10 Go+−7 % | $0.79 | $2.09 |
| 50 Go+ | $0.72 | $1.95 |
| 100 Go+ | $0.65 | $1.75 |
| 500 Go+ | $0.57 | $1.55 |
| 1000 Go+ | $0.49 | $1.39 |
Prix en dollars américains pour 1 Go. Vous achetez des gigaoctets entiers, à partir d'un seul.
Pool
Vous économisez 7 % ($1.50) par rapport au prix pour 1 Go et plus
Ajoutez 25 Go et chaque gigaoctet descend à $0.72
Acheter cette quantitéVous pouvez utiliser les gigaoctets pendant 3 mois à compter de l'achat ; ce qui reste ensuite est annulé.
Suivez Google.de via l'Europe, Yandex via la CEI, Baidu via la Chine. World MIX couvre le reste et offre les plus gros pools.
Prenez l'export CSV et gardez les lignes dont la colonne pays correspond au marché suivi ; le script prêt écrit pour vous un fichier ip:port par pays.
Les rank checkers acceptent un fichier de proxies ou une URL. Réglez le rafraîchissement sur 10 minutes et la liste reste à jour d'elle-même.
Réglez DOMAIN et COUNTRY, placez vos mots-clés dans keywords.txt. Le script interroge le moteur via un proxy de ce pays et écrit la position de votre domaine dans un CSV. Donnez-lui un pool propre issu du vérificateur 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()
Collez une ligne Resi de votre tableau de bord, fixez DOMAIN et mettez les mots-clés dans keywords.txt. Le script ouvre les résultats dans un vrai Chromium via le proxy, attend la fin du chargement du bloc IA et écrit en CSV si le bloc est là, quels domaines il cite et si le vôtre en fait partie. Il ferme lui-même la bannière cookies de l'UE et signale sur une ligne à part un captcha ou une erreur de proxy. Google change son balisage, donc le titre du bloc se trouve dans 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()
Dans A-Parser et Key Collector, collez la liste ip:port dans le champ proxy et réglez l'intervalle pour qu'un mot-clé passe par une adresse au plus une fois par jour. Rank Tracker et les logiciels de bureau du même genre lisent un fichier de proxies ; pointez-les vers la liste que le script écrit par pays.
Les positions dépendent de l'origine de la requête, gardez donc une liste par marché : une instance de l'outil par pays, chacune avec les seules adresses de ce pays.
Le script ci-dessus interroge le moteur via un proxy du pays et note la place de votre domaine. Envoyez les paramètres de langue et de région du moteur avec le proxy : l'adresse fixe le pays, les paramètres fixent la ville.
Vérifiez le pool avant chaque passage avec le vérificateur de proxies ; pour un test manuel léger, la liste de proxies gratuits fait l'affaire. Une introduction aux SERP régionales paraîtra dans les articles.
Google place de plus en plus souvent un bloc IA au-dessus des résultats classiques : une réponse courte avec des liens vers des sources. Une partie des clics va là, il faut donc savoir si votre site figure parmi les sources et quelles requêtes n'affichent aucun bloc. Le bloc est construit selon la position de l'utilisateur : pour une même requête, Berlin et Munich peuvent voir des sources différentes.
Un scraper de résultats classique ne voit jamais ce bloc : Google le dessine en JavaScript après le chargement de la page. Il faut un vrai navigateur, comme Chromium via Playwright, et une IP résidentielle du bon pays. Les adresses des listes tombent souvent sur un captcha sur ces résultats, c'est pourquoi Resi Core et Resi Prime font le travail ici.
Pour un suivi au niveau du pays, Resi Core avec le code pays dans le login suffit. Quand le client tient à une ville, prenez Resi Prime avec la ville dans la chaîne et une session fixe par lot de requêtes : tout le lot part alors d'une seule adresse dans cette ville.
Passez la liste de mots-clés une fois par jour ou une fois par semaine : le bloc IA change plus lentement que les positions classiques. Pour chaque requête, notez la date, le pays ou la ville, la présence du bloc, les domaines qu'il cite et si le vôtre en fait partie. Au bout d'un mois, vous voyez quelles pages l'IA reprend dans sa réponse et lesquelles en sont sorties.
Le deuxième script ci-dessus écrit exactement ces champs en CSV. Le premier script suit les positions classiques dans le même pays, donc les deux rapports s'alignent par requête.

Suivez les résultats par pays via Resi Core et par ville via Resi Prime, et passez les grandes listes de mots-clés chaque jour sur un pack illimité pour moins cher.
Résultats par paysLe meilleur choix
Une IP résidentielle du bon pays à chaque requête. Une page de résultats pèse peu, donc un gigaoctet couvre des milliers de requêtes.
dès $0.49 le Go1 Go pour $0.85
Résultats par ville
La ville et la région dans la chaîne de connexion donnent les résultats que voit un utilisateur de cette ville.
dès $1.39 le Go1 Go pour $2.29
Grandes listes de mots-clés
Des dizaines de milliers de requêtes par jour sans compteur de trafic. Vous choisissez le pays du marché par la colonne de l'export CSV.
$378 par moisou $2.10 de l'heure
Prenez 1 Go de Resi Core, fixez le pays dans la chaîne et lancez l'outil sur des adresses vivantes.