Best Practices per Scraping SERP Geo-Targetato: Guida per Sviluppatori

Scopri come implementare scraping SERP geo-targetato con precisione a livello città usando parametri uule, gl, hl e proxy residenziali. Esempi Python e curl pronti all'uso.

Geo-Targeted SERP Scraping Best Practices for Local SEO Data
In questo articolo

Best Practices per Scraping SERP Geo-Targetato: Perché la Posizione Cambia Tutto

Se hai mai cercato la stessa keyword da due città diverse e ottenuto risultati completamente differenti, hai già sperimentato il problema centrale del scraping SERP geo-targetato. Google personalizza i risultati in base alla posizione geografica dell'utente: un'azienda di pizzerie a Milano appare nei risultati locali per "pizza" cercato da Roma solo se ha una sede lì, e il local pack (le tre mappe in cima) cambia radicalmente tra quartieri della stessa città.

Per i team SEO e i rank tracker, questo significa che raccogliere SERP senza specificare una località precisa produce dati inutilizzabili. Il targeting a livello paese non basta: "caffè a Roma" e "caffè a Napoli" generano SERP diverse, e anche dentro Roma i risultati del centro storico differiscono da quelli della periferia. Le best practices per scraping SERP geo-targetato richiedono precisione a livello città, parametri di localizzazione coerenti e IP residenziali allineati al mercato target.

Perché la Stessa Query Restituisce Risultati Diversi per Località

Google utilizza almeno tre segnali per localizzare i risultati di ricerca:

  • Geolocalizzazione IP: Google deduce la posizione approssimativa dall'indirizzo IP del richiedente. Un IP statunitense produce risultati US, un IP italiano risultati IT.
  • Parametri URL: gl, hl, google_domain, uule e pws comunicano esplicitamente la regione, la lingua e la città desiderate.
  • Account e cookie: lo storico di ricerca e le impostazioni dell'account influenzano la personalizzazione — ma per scraping impersonale si usa pws=0 per disattivarla.

Il problema è che Google cross-controlla questi segnali. Se invii gl=US ma il tuo IP è in Francia, Google può ignorare il parametro o mostrare risultati ibridi. Per risultati affidabili e riproducibili, IP e parametri URL devono concordare. Per approfondire il funzionamento dei parametri di localizzazione, consulta la documentazione ufficiale di Google.

Perché il Targeting a Livello Paese Non È Sufficiente

Il local pack — quel blocco di tre risultati con mappa che appare per query con intento locale — è sensibile alla posizione fino al livello di quartiere. Un'azienda di idraulici a Brooklyn non appare nel local pack per "idraulico" cercato da Manhattan, anche se entrambe sono a New York City. Per il rank tracking locale serve precisione a livello città o distretto, non solo paese.

Secondo le impostazioni di regione di Google, la localizzazione influisce su ordinamento, local pack, suggerimenti e persino le featured snippets. Ignorare questo significa raccogliere dati SERP che non riflettono ciò che vedono gli utenti reali nel mercato target.

Parametri di Localizzazione Core: gl, hl, google_domain, lr, uule, pws

Ecco i parametri essenziali per il scraping SERP geo-targetato, con la loro funzione e valori comuni:

ParametroFunzioneEsempio
glCodice paese (ISO 3166-1 alpha-2)gl=us, gl=it
hlLingua interfaccia (ISO 639-1)hl=it, hl=en
google_domainDominio Google regionalegoogle_domain=google.it
lrFiltro lingua dei risultatilang_it, lang_en
uuleLocalità precisa (città/distretto)uule=w+CAIQICI...
pwsPersonalizzazione (0 = off)pws=0

Costruire il Parametro uule

Il parametro uule è il più critico e meno documentato. Permette di specificare una località precisa a livello città. Il formato è:

uule = "w+CAIQICI" + base64(canonical_place_name)

Dove canonical_place_name è una stringa nel formato "Città,Regione,Paese" (in inglese canonico). Ad esempio:

  • "Rome,Lazio,Italy" per Roma
  • "Milan,Lombardy,Italy" per Milano
  • "Brooklyn,New York,United States" per Brooklyn, NYC

La regola d'oro: aggiungi sempre pws=0 per ottenere un baseline non personalizzato, riproducibile tra esecuzioni. Senza pws=0, Google può iniettare risultati personalizzati basati su segnali dell'IP, rendendo i dati non riproducibili.

Allineamento IP-Parametri: Perché Serve un Proxy Residenziale

Se i tuoi parametri URL dicono gl=US&uule=...New York ma il tuo IP è in Germania, Google rileva l'incongruenza. I datacenter IP sono inoltre facilmente identificabili e spesso bloccati. La soluzione è routare le richieste attraverso proxy residenziali localizzati nella stessa area geografica dei parametri.

Con ProxyHat, puoi specificare paese e città direttamente nel username del proxy:

http://user-country-US-city-newyork:password@gate.proxyhat.com:8080

Questo garantisce che ogni richiesta arrivi da un IP residenziale statunitense localizzato a New York, allineato con gl=us e uule=...New York. Consulta tutte le locazioni disponibili per verificare la copertura e il piano tariffario più adatto al tuo volume.

Implementazione Pratica: Esempi di Codice

1. Costruire uule e Inviare una Richiesta SERP con curl

#!/bin/bash
# Costruisce uule per Rome, Italy e invia una richiesta SERP tramite proxy residenziale ProxyHat

UULE=$(echo -n "Rome,Lazio,Italy" | base64)
QUERY="pizzeria"
URL="https://www.google.com/search?q=${QUERY}&gl=it&hl=it&google_domain=google.it&pws=0&uule=w+CAIQICI${UULE}&num=20"

curl -sS \
  --proxy "http://user-country-IT-city-rome:password@gate.proxyhat.com:8080" \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" \
  -H "Accept-Language: it-IT,it;q=0.9,en;q=0.8" \
  "$URL" -o serp_rome.html

2. Python requests con Proxy Residenziale e uule (Raw Proxy)

import base64
import requests
from urllib.parse import urlencode

def build_uule(canonical_name: str) -> str:
    """Costruisce il parametro uule di Google per targeting a livello città."""
    prefix = "w+CAIQICI"
    encoded = base64.b64encode(canonical_name.encode("utf-8")).decode("ascii")
    return prefix + encoded

def scrape_serp_raw(
    query: str,
    country: str,
    lang: str,
    google_domain: str,
    canonical_place: str,
    proxy_country: str,
    proxy_city: str,
    proxy_pass: str,
    num: int = 20,
) -> str:
    """Scraping SERP geo-targetato con proxy residenziale raw."""
    uule = build_uule(canonical_place)
    params = {
        "q": query,
        "gl": country,
        "hl": lang,
        "google_domain": google_domain,
        "uule": uule,
        "pws": "0",
        "num": str(num),
    }
    url = f"https://www.google.{google_domain.split('.')[-1]}/search?" + urlencode(params)

    proxy_url = f"http://user-country-{proxy_country}-city-{proxy_city}:{proxy_pass}@gate.proxyhat.com:8080"
    proxies = {"http": proxy_url, "https": proxy_url}

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": f"{lang}-{country.upper()},{lang};q=0.9,en;q=0.8",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    }

    resp = requests.get(url, proxies=proxies, headers=headers, timeout=30)
    resp.raise_for_status()
    return resp.text

# Esempio: SERP per "pizzeria" a Roma
html = scrape_serp_raw(
    query="pizzeria",
    country="it",
    lang="it",
    google_domain="google.it",
    canonical_place="Rome,Lazio,Italy",
    proxy_country="IT",
    proxy_city="rome",
    proxy_pass="tua_password",
)
print(f"Ricevuti {len(html)} byte di HTML")

3. ProxyHat SDK Client (Wrapper) per Gestione Multi-Locale

import base64
import logging
from dataclasses import dataclass, field
from typing import Optional
import requests

logger = logging.getLogger("proxyhat_serp")

@dataclass
class LocaleConfig:
    """Configurazione locale per scraping SERP geo-targetato."""
    country: str          # es. "US"
    city: str             # es. "newyork"
    gl: str               # es. "us"
    hl: str               # es. "en"
    google_domain: str    # es. "google.com"
    canonical_place: str  # es. "New York,New York,United States"
    lr: Optional[str] = None

@dataclass
class ProxyHatClient:
    """Client ProxyHat per scraping SERP geo-targetato con rotazione residenziale."""
    username: str
    password: str
    gateway: str = "gate.proxyhat.com"
    http_port: int = 8080
    socks5_port: int = 1080
    session: requests.Session = field(default_factory=requests.Session)

    def _proxy_url(self, locale: LocaleConfig, session_id: Optional[str] = None) -> str:
        """Costruisce l'URL del proxy con geo-targeting."""
        user = f"user-country-{locale.country}-city-{locale.city}"
        if session_id:
            user += f"-session-{session_id}"
        return f"http://{user}:{self.password}@{self.gateway}:{self.http_port}"

    def build_uule(self, canonical_place: str) -> str:
        prefix = "w+CAIQICI"
        return prefix + base64.b64encode(
            canonical_place.encode("utf-8")
        ).decode("ascii")

    def scrape(self, query: str, locale: LocaleConfig,
               num: int = 20, session_id: Optional[str] = None) -> str:
        """Esegue scraping SERP geo-targetato con IP residenziale allineato."""
        uule = self.build_uule(locale.canonical_place)
        params = {
            "q": query, "gl": locale.gl, "hl": locale.hl,
            "google_domain": locale.google_domain,
            "uule": uule, "pws": "0", "num": str(num),
        }
        if locale.lr:
            params["lr"] = locale.lr

        url = f"https://www.{locale.google_domain}/search?" + \
              "&".join(f"{k}={v}" for k, v in params.items())

        proxy_url = self._proxy_url(locale, session_id)
        proxies = {"http": proxy_url, "https": proxy_url}
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 (KHTML, like Gecko) "
                          "Chrome/124.0.0.0 Safari/537.36",
            "Accept-Language": f"{locale.hl}-{locale.country},{locale.hl};q=0.9",
        }

        logger.info(f"Scraping '{query}' per {locale.city} via {proxy_url}")
        resp = self.session.get(url, proxies=proxies, headers=headers, timeout=30)
        resp.raise_for_status()
        return resp.text

# Utilizzo
client = ProxyHatClient(username="user", password="pass")

us_nyc = LocaleConfig(
    country="US", city="newyork", gl="us", hl="en",
    google_domain="google.com",
    canonical_place="New York,New York,United States",
    lr="lang_en",
)

html = client.scrape("best pizza near me", us_nyc, num=20)

4. curl_cffi con Impersonazione Chrome e Proxy

import base64
from curl_cffi import requests as cffi_requests

def build_uule(canonical_name: str) -> str:
    prefix = "w+CAIQICI"
    return prefix + base64.b64encode(
        canonical_name.encode("utf-8")
    ).decode("ascii")

def scrape_serp_curl_cffi(query: str, canonical_place: str,
                          gl: str, hl: str, domain: str,
                          proxy_country: str, proxy_city: str,
                          password: str) -> str:
    """Scraping SERP con curl_cffi e impersonazione Chrome 120."""
    uule = build_uule(canonical_place)
    params = {
        "q": query, "gl": gl, "hl": hl,
        "google_domain": domain, "uule": uule,
        "pws": "0", "num": "20",
    }
    url = f"https://www.{domain}/search?" + \
          "&".join(f"{k}={v}" for k, v in params.items())

    proxy = (f"http://user-country-{proxy_country}-city-{proxy_city}:"
             f"{password}@gate.proxyhat.com:8080")

    # impersonate=chrome120 replica TLS fingerprint e JA3 di Chrome 120
    resp = cffi_requests.get(
        url,
        impersonate="chrome120",
        proxies={"http": proxy, "https": proxy},
        timeout=30,
    )
    resp.raise_for_status()
    return resp.text

# US geo-targeted SERP scraping best practices: New York
html_nyc = scrape_serp_curl_cffi(
    "plumber", "New York,New York,United States",
    "us", "en", "google.com", "US", "newyork", "pass"
)
print(f"NYC SERP: {len(html_nyc)} byte")

5. Parsing Risultati Organici e Local Pack con selectolax

from selectolax.parser import HTMLParser
from dataclasses import dataclass
from typing import List

@dataclass
class OrganicResult:
    position: int
    title: str
    url: str
    snippet: str

@dataclass
class LocalPackResult:
    name: str
    rating: str
    address: str

def parse_organic(html: str) -> List[OrganicResult]:
    """Estrae i risultati organici dalla SERP."""
    tree = HTMLParser(html)
    results = []
    for i, div in enumerate(tree.css("div.g"), start=1):
        title_el = div.css_first("h3")
        link_el = div.css_first("a[href]")
        snippet_el = div.css_first("div.VwiC3b") or div.css_first("span.aCOpRe")
        if title_el and link_el:
            results.append(OrganicResult(
                position=i,
                title=title_el.text(strip=True),
                url=link_el.attributes.get("href", ""),
                snippet=snippet_el.text(strip=True) if snippet_el else "",
            ))
    return results

def parse_local_pack(html: str) -> List[LocalPackResult]:
    """Estrae il local pack (risultati con mappa)."""
    tree = HTMLParser(html)
    local_results = []
    for item in tree.css("div[data-cid]"):
        name_el = item.css_first("div.fontHandle") or item.css_first(".dbg0pd")
        if name_el:
            name = name_el.text(strip=True)
            rating = ""
            address = ""
            details = item.css_first("div.rllt__details")
            if details:
                spans = details.css("span")
                if spans:
                    rating = spans[0].text(strip=True) if spans else ""
                    address = spans[-1].text(strip=True) if len(spans) > 1 else ""
            local_results.append(LocalPackResult(
                name=name, rating=rating, address=address,
            ))
    return local_results

# Utilizzo
organic = parse_organic(html_nyc)
local = parse_local_pack(html_nyc)

print(f"Risultati organici: {len(organic)}")
for r in organic[:5]:
    print(f"  #{r.position}: {r.title} -- {r.url}")

print(f"\nLocal pack: {len(local)}")
for lp in local:
    print(f"  {lp.name} -- {lp.rating} -- {lp.address}")

6. Sticky Session per SERP Multi-Pagina

import uuid
import time
import logging
from typing import List, Dict

logger = logging.getLogger("serp_multipage")

def scrape_multi_page_serp(
    client: ProxyHatClient,
    query: str,
    locale: LocaleConfig,
    max_pages: int = 3,
) -> List[Dict]:
    """Scraping SERP multi-pagina con sticky session per coerenza IP."""
    session_id = uuid.uuid4().hex[:12]  # ID sessione stabile
    all_results = []

    for page in range(max_pages):
        start_param = page * 10
        uule = client.build_uule(locale.canonical_place)

        params = {
            "q": query, "gl": locale.gl, "hl": locale.hl,
            "google_domain": locale.google_domain,
            "uule": uule, "pws": "0",
            "start": str(start_param),
        }
        url = f"https://www.{locale.google_domain}/search?" + \
              "&".join(f"{k}={v}" for k, v in params.items())

        proxy_url = client._proxy_url(locale, session_id=session_id)
        proxies = {"http": proxy_url, "https": proxy_url}
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
            "Accept-Language": f"{locale.hl}-{locale.country}",
        }

        logger.info(f"Pagina {page+1}/{max_pages} -- session={session_id}")
        resp = client.session.get(url, proxies=proxies, headers=headers, timeout=30)
        resp.raise_for_status()

        organic = parse_organic(resp.text)
        if not organic:
            logger.warning(f"Nessun risultato a pagina {page+1}, interruzione")
            break

        for r in organic:
            all_results.append({
                "page": page + 1,
                "position": r.position + start_param,
                "title": r.title,
                "url": r.url,
                "snippet": r.snippet,
            })

        time.sleep(2)  # Rate limiting rispettoso

    return all_results

# Esempio: 3 pagine di SERP per "dentist" a Chicago
chicago = LocaleConfig(
    country="US", city="chicago", gl="us", hl="en",
    google_domain="google.com",
    canonical_place="Chicago,Illinois,United States",
)

results = scrape_multi_page_serp(client, "dentist", chicago, max_pages=3)
print(f"Totali: {len(results)} risultati su {results[-1]['page']} pagine")

7. Retry, Backoff e Per-Country Proxy Pools

import time
import logging
from functools import wraps
from requests.exceptions import RequestException, HTTPError

logger = logging.getLogger("serp_retry")

def retry_with_backoff(max_retries: int = 3, base_delay: float = 2.0,
                        backoff_factor: float = 2.0):
    """Decorator per retry con backoff esponenziale su 429/503."""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            delay = base_delay
            for attempt in range(1, max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except HTTPError as e:
                    status = e.response.status_code if e.response else 0
                    if status in (429, 503):
                        wait = delay + (attempt * 1.5)
                        logger.warning(
                            f"Tentativo {attempt}/{max_retries}: "
                            f"HTTP {status}, attesa {wait:.1f}s"
                        )
                        time.sleep(wait)
                        delay *= backoff_factor
                    else:
                        raise
                except RequestException as e:
                    logger.error(f"Errore di rete: {e}")
                    if attempt == max_retries:
                        raise
                    time.sleep(delay)
                    delay *= backoff_factor
            raise RuntimeError(f"Fallito dopo {max_retries} tentativi")
        return wrapper
    return decorator

class CountryProxyPool:
    """Gestisce pool di proxy residenziali per paese con rotazione."""

    def __init__(self, username: str, password: str):
        self.username = username
        self.password = password
        self.gateway = "gate.proxyhat.com"
        self.port = 8080
        # Mapping paese -> lista citta per rotazione
        self.country_cities = {
            "US": ["newyork", "losangeles", "chicago", "miami", "seattle"],
            "IT": ["rome", "milan", "naples", "turin", "florence"],
            "DE": ["berlin", "munich", "frankfurt", "hamburg"],
            "GB": ["london", "manchester", "birmingham", "liverpool"],
        }
        self._rotation_idx = {}

    def get_proxy(self, country: str, city: str = None,
                  session_id: str = None) -> str:
        """Restituisce URL proxy per paese/citta con rotazione automatica."""
        if city is None:
            cities = self.country_cities.get(country, [country.lower()])
            idx = self._rotation_idx.get(country, 0)
            city = cities[idx % len(cities)]
            self._rotation_idx[country] = idx + 1

        user = f"user-country-{country}-city-{city}"
        if session_id:
            user += f"-session-{session_id}"
        return f"http://{user}:{self.password}@{self.gateway}:{self.port}"

# Utilizzo combinato
pool = CountryProxyPool("user", "password")

@retry_with_backoff(max_retries=4, base_delay=2.0)
def scrape_with_pool(query: str, locale: LocaleConfig,
                     pool: CountryProxyPool) -> str:
    proxy = pool.get_proxy(locale.country)
    proxies = {"http": proxy, "https": proxy}
    uule = build_uule(locale.canonical_place)
    url = (f"https://www.{locale.google_domain}/search?"
           f"q={query}&gl={locale.gl}&hl={locale.hl}"
           f"&uule={uule}&pws=0&num=20")
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": f"{locale.hl}-{locale.country}",
    }
    resp = requests.get(url, proxies=proxies, headers=headers, timeout=30)
    resp.raise_for_status()
    return resp.text

# Esecuzione con retry automatico
try:
    html = scrape_with_pool("restaurant", chicago, pool)
    print(f"Successo: {len(html)} byte")
except RuntimeError as e:
    logger.error(f"Scraping fallito: {e}")

Errori Comuni e Edge Case

  • Parametri e IP non concordanti: il problema più frequente. gl=US con IP tedesco produce risultati inaffidabili. Soluzione: usa sempre proxy nella stessa area dei parametri.
  • uule malformato: il base64 deve essere dell'encoding UTF-8 del nome canonico. Nomi non inglesi (es. "Roma" invece di "Rome") non funzionano.
  • Rate limiting aggressivo: più di 50 richieste/minuto dallo stesso IP possono innescare CAPTCHA. Usa rotazione IP e delay di 2-5 secondi tra richieste.
  • Sticky session troppo lunga: una sessione che dura più di 30 minuti può essere flaggata. Rigenera session_id periodicamente.
  • Ignorare robots.txt e ToS: i robots.txt di Google e i Termini di Servizio vietano l'accesso automatizzato non autorizzato. Valuta alternative come la Google Custom Search API per volumi moderati (100 query/giorno gratuite, poi $5 per 1000 query).

Considerazioni su Dati Pubblici e ToS

Lo scraping di Google Search solleva questioni legali e etiche. I Termini di Servizio di Google proibiscono l'accesso automatizzato non autorizzato. Per dataset di produzione, considera:

  • La Google Custom Search JSON API ufficiale (100 query/giorno gratuite, poi $5 per 1000 query).
  • Rispetta il rate limiting e non sovraccaricare i server.
  • Non raccogliere dati personali (GDPR/CCPA) dai risultati SERP.
  • Per uso commerciale su larga scala, consulta un legale esperto in data scraping.

Punti Chiave (Key Takeaways)

Il scraping SERP geo-targetato richiede tre elementi allineati: parametri URL corretti (gl, hl, uule, pws=0), IP residenziale nella stessa area geografica, e parsing robusto che gestisca CAPTCHA e cambiamenti di layout. Senza allineamento IP-parametri, i dati raccolti sono inaffidabili.

  • uule è essenziale per precisione a livello città — il solo gl non basta per local SEO.
  • pws=0 elimina la personalizzazione per baseline riproducibili.
  • Proxy residenziali su gate.proxyhat.com:8080 con flag -country-XX-city-yyy garantiscono allineamento IP-parametri.
  • Sticky session per SERP multi-pagina: stesso IP per coerenza tra pagine.
  • Retry con backoff su 429/503 e rotazione IP per-country per evitare CAPTCHA.
  • curl_cffi con impersonate=chrome supera i controlli TLS fingerprint meglio di requests puro.

Per approfondire, consulta la documentazione sui prezzi di ProxyHat e i nostri casi d'uso per SERP tracking. La documentazione ufficiale ProxyHat contiene tutti i dettagli sulla configurazione avanzata dei proxy residenziali.

Domande frequenti

Cos'è lo scraping SERP geo-targetato?

Lo scraping SERP geo-targetato è la pratica di raccogliere risultati di ricerca di Google specifici per una località geografica precisa, utilizzando parametri come gl, hl, uule e pws=0 combinati con proxy residenziali nella stessa area. A differenza dello scraping SERP generico, il targeting geografico permette di ottenere risultati che riflettono ciò che gli utenti reali vedono in una specifica città o regione, essenziale per il rank tracking locale e il competitive analysis SEO.

Perché lo scraping SERP geo-targetato è importante per gli utenti proxy?

Lo scraping SERP geo-targetato è critico per gli utenti proxy perché Google cross-controlla i parametri URL con la geolocalizzazione dell'IP. Se i parametri indicano US ma l'IP è in Europa, i risultati sono inaffidabili. I proxy residenziali permettono di allineare l'IP con i parametri URL, garantendo che i dati raccolti siano accurati e riproducibili. Senza proxy localizzati, il geo-targeting tramite soli parametri URL produce risultati distorti e non rappresentativi.

Quale tipo di proxy funziona meglio per lo scraping SERP geo-targetato?

I proxy residenziali sono la scelta ottimale per lo scraping SERP geo-targetato perché utilizzano IP di dispositivi reali assegnati da ISP locali, rendendoli indistinguibili dal traffico organico. I proxy datacenter sono facilmente identificabili e spesso bloccati da Google. I proxy mobili offrono un ulteriore livello di affidabilità ma a costi maggiori. Per la maggior parte dei casi d'uso SERP, i residenziali con targeting città offrono il miglior rapporto qualità-prezzo.

Come evitare i blocchi nello scraping SERP geo-targetato?

Per evitare blocchi nello scraping SERP geo-targetato: usa proxy residenziali con rotazione IP per paese, mantieni un rate di massimo 50 richieste/minuto per IP, implementa retry con backoff esponenziale su HTTP 429/503, usa curl_cffi con impersonazione Chrome per superare i controlli TLS fingerprint, aggiungi delay di 2-5 secondi tra richieste, e rigenera le sessioni sticky ogni 30 minuti. Rispetta sempre i Termini di Servizio della piattaforma.

Monitoraggio delle posizioni che non viene bloccato

Dati SERP accurati con proxy residenziali. Crea un account e avvia il monitoraggio.

Avvia il monitoraggio
← Torna al Blog