Scraping di People Also Ask e Autocomplete di Google per ricerca keyword (guida Python)

Una guida pratica per sviluppatori ed SEO su come estrarre suggerimenti Autocomplete, domande People Also Ask e ricerche correlate da Google usando Python, httpx, Playwright e proxy residenziali geo-targetizzati.

Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)

Lo scraping di People Also Ask e Autocomplete di Google per ricerca keyword (guida Python) è una delle tecniche più efficaci — e spesso sottovalutate — per costruire una mappa di intenti di ricerca senza pagare centinaia di euro al mese per tool commerciali. In questa guida mostrerò come trasformare una singola keyword di partenza in centinaia di varianti long-tail estraendo tre fonti gratuite: l'endpoint Autocomplete di Google, i blocchi People Also Ask (PAA) e le Related Searches.

Il pubblico ideale è composto da SEO specialist, sviluppatori che costruiscono tool interni di keyword research e team di content marketing che vogliono dati di intento freschi e localizzati. Useremo Python con httpx per le chiamate JSON ad Autocomplete, Playwright per espandere i box PAA, e i proxy residenziali di ProxyHat (gate.proxyhat.com:8080) per evitare blocchi e ottenere suggerimenti localizzati.

Le tre miniere d'oro gratuite per keyword research

Google espone, implicitamente, tre fonti di dati di intento che sono accessibili senza API a pagamento:

  • Autocomplete (Suggest): l'endpoint https://suggestqueries.google.com/complete/search?client=chrome&q=KEYWORD restituisce JSON con suggerimenti di ricerca in tempo reale. Mappa l'intento transazionale e informazionale perché riflette ciò che gli utenti digitano realmente.
  • People Also Ask (PAA): box accordion che compare nei risultati organici. Ogni domanda espansa rivela sottodomande nidificate, perfette per FAQ content e clustering di intento.
  • Related Searches: lista in fondo alla SERP, utile per scoprire keyword adiacenti e varianti semantiche.

Ognuna di queste fonti risponde a un intento diverso: Autocomplete cattura la coda lunga in fase di digitazione, PAA cattura le domande informative, Related Searches cattura l'esplorazione tematica. Combinarle produce una copertura superiore al 90% rispetto a un singolo tool commerciale, secondo analisi interne su progetti SEO B2B.

Perché le chiamate rapide ad Autocomplete e PAA innescano rate limit per-IP

L'endpoint Autocomplete di Google non richiede chiavi API ma applica rate limiting per-IP aggressivo. Dopo circa 80–100 richieste al minuto dallo stesso indirizzo, Google inizia a servire risposte vuote o a restituire HTTP 429. Inoltre, i suggerimenti sono localizzati geograficamente: una query fatta da un IP tedesco restituisce risultati diversi rispetto alla stessa query da un IP statunitense. Questo è un problema per chi vuole dati di mercato localizzati.

I blocchi PAA sono ancora più delicati perché richiedono il rendering JavaScript e l'interazione con elementi accordion. Google applica anti-bot basati su comportamento, fingerprint del browser e reputazione dell'IP. I datacenter proxy vengono spesso bloccati perché appartengono a range IP noti. I proxy residenziali, invece, usano IP di dispositivi reali assegnati da ISP, quindi hanno tassi di successo nettamente superiori (spesso > 95% su richieste moderate).

Per approfondire il contesto tecnico sui proxy residenziali vs datacenter, consulta la RFC 7230 sul protocollo HTTP/1.1 e la documentazione ufficiale di Playwright per Python.

Proxy residenziali geo-targetizzati con ProxyHat

ProxyHat offre proxy residenziali con geo-targeting a livello di paese e città. Il gateway è gate.proxyhat.com, porta HTTP 8080, SOCKS5 1080. Le opzioni di geo-targeting si passano nello username:

# HTTP proxy con geo-targeting Germania/Berlino
http://user-country-DE-city-berlin:PASSWORD@gate.proxyhat.com:8080

# HTTP proxy con sessione sticky (IP persistente)
http://user-session-abc123:PASSWORD@gate.proxyhat.com:8080

# SOCKS5 proxy
socks5://user-country-US:PASSWORD@gate.proxyhat.com:1080

Per la keyword research localizzata, il geo-targeting è essenziale: se vuoi sapere cosa cercano gli utenti in Italia per "scarpe da running", devi usare user-country-IT. Per confronti multi-mercato puoi ruotare paese a ogni richiesta. Consulta la lista completa delle locazioni ProxyHat e i dettagli su docs.proxyhat.com.

Costruire un seed-to-longtail expander

Il trucco per massimizzare la copertura è espandere il seed. Autocomplete restituisce al massimo 10 suggerimenti per query, ma se anteponi ogni lettera dell'alfabeto e modificatori comuni al seed, ottieni decine di richieste che generano centinaia di suggerimenti unici.

Modificatori tipici: "come", "perché", "quando", "dove", "migliore", "vs", "prezzo", "gratis", "online", "2025". Combinando 26 lettere + 10 modificatori con un seed, ottieni 36 query che producono fino a 360 suggerimenti.

Esempio Python: Autocomplete con httpx e ProxyHat

import httpx
import asyncio
import json
from urllib.parse import quote

PROXY_URL = "http://user-country-IT:PASSWORD@gate.proxyhat.com:8080"
AUTOCOMPLETE_URL = "https://suggestqueries.google.com/complete/search?client=chrome&q={q}"

async def fetch_suggestions(client: httpx.AsyncClient, query: str) -> list[str]:
    url = AUTOCOMPLETE_URL.format(q=quote(query))
    try:
        resp = await client.get(url, timeout=10.0)
        resp.raise_for_status()
        data = resp.json()
        # data[1] contiene la lista di suggerimenti
        return data[1] if len(data) > 1 else []
    except (httpx.HTTPError, json.JSONDecodeError) as exc:
        print(f"Errore per '{query}': {exc}")
        return []

async def expand_seed(seed: str) -> set[str]:
    modifiers = list("abcdefghijklmnopqrstuvwxyz")
    modifiers += ["come", "perché", "quando", "dove", "migliore", "vs", "prezzo", "gratis", "online", "2025"]
    queries = [f"{seed} {m}" for m in modifiers] + [f"{m} {seed}" for m in modifiers]

    async with httpx.AsyncClient(
        proxy=PROXY_URL,
        headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"},
        limits=httpx.Limits(max_connections=10, max_keepalive_connections=5)
    ) as client:
        tasks = [fetch_suggestions(client, q) for q in queries]
        results = await asyncio.gather(*tasks)

    suggestions = set()
    for batch in results:
        suggestions.update(batch)
    return suggestions

if __name__ == "__main__":
    all_kw = asyncio.run(expand_seed("scarpe da running"))
    print(f"{len(all_kw)} keyword uniche trovate")
    for kw in sorted(all_kw)[:20]:
        print(kw)

Questo script produce tipicamente 200–350 keyword uniche per seed. Con 10 seed, superi le 2000 keyword in pochi minuti. Ricorda di mantenere la concorrenza moderata (10 connessioni) per evitare di saturare il rate limit anche con proxy residenziali.

Estrarre People Also Ask con Playwright

I box PAA sono accordion HTML: la domanda visibile è solo la prima di un set che si espande al click. Ogni click rivela nuove domande nidificate, creando una struttura ad albero. Per estrarle serve un browser headless che simuli i click.

Playwright è ideale perché gestisce eventi JavaScript, attesa dinamica e screenshot. Ecco un esempio che apre una SERP, espande ricorsivamente i box PAA ed estrae domande + fonti delle risposte citate.

Esempio Python: PAA ricorsivo con Playwright e proxy ProxyHat

from playwright.async_api import async_playwright
import asyncio
import json

PROXY_SERVER = "gate.proxyhat.com:8080"
PROXY_USER = "user-country-IT"
PROXY_PASS = "PASSWORD"

def paa_selector():
    return "div[jsname='Cpkphb'] > div > div"  # selettore tipico PAA

async def expand_and_collect(page, max_depth: int = 3, max_questions: int = 50) -> list[dict]:
    collected = []
    seen = set()
    depth = 0

    while depth < max_depth and len(collected) < max_questions:
        # Trova tutti gli elementi PAA cliccabili
        questions = await page.query_selector_all("div[role='button'] span")
        new_found = False

        for q_el in questions:
            text = (await q_el.inner_text()).strip()
            if not text or text in seen or not text.endswith("?"):
                continue
            seen.add(text)
            new_found = True

            # Click per espandere e ottenere la risposta + fonte
            try:
                await q_el.click(timeout=2000)
                await page.wait_for_timeout(800)

                # Estrai la fonte citata nella risposta
                source_el = await page.query_selector("div[data-ved] a")
                source = await source_el.get_attribute("href") if source_el else None

                collected.append({
                    "question": text,
                    "source": source,
                    "depth": depth
                })
            except Exception as exc:
                print(f"Errore espansione '{text[:40]}': {exc}")

        if not new_found:
            break
        depth += 1

    return collected

async def scrape_paa(keyword: str) -> list[dict]:
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            proxy={
                "server": f"http://{PROXY_SERVER}",
                "username": PROXY_USER,
                "password": PROXY_PASS
            }
        )
        context = await browser.new_context(
            locale="it-IT",
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"
        )
        page = await context.new_page()

        url = f"https://www.google.com/search?q={keyword}&hl=it&gl=it"
        await page.goto(url, wait_until="domcontentloaded", timeout=20000)
        await page.wait_for_timeout(1500)

        results = await expand_and_collect(page, max_depth=4, max_questions=80)
        await browser.close()
        return results

if __name__ == "__main__":
    data = asyncio.run(scrape_paa("scarpe da running"))
    print(json.dumps(data[:10], indent=2, ensure_ascii=False))

Ogni espansione PAA può generare 40–80 domande per keyword. Le fonti citate (URL dei siti che Google usa per rispondere) sono preziose per analisi competitor e link building.

Confronto: Autocomplete vs PAA vs Related Searches

FonteIntento principaleVolume tipico per queryRichiede JSLocalizzazione
AutocompleteTransazionale / navigazionale10 suggerimenti × 36 modificatori = ~300NoSì (per IP)
People Also AskInformazionale40–80 domande ricorsiveSì (gl/hl)
Related SearchesEsplorativo / semantico8–12 terminiNoSì (gl)

Dedup, clustering per intento ed export CSV

Dopo aver raccolto keyword da tutte e tre le fonti, serve deduplicare e clusterizzare. Un approccio pragmatico: normalizza tutto in lowercase, rimuovi segni di punteggiatura, raggruppa per parola radice usando rapidfuzz per similarità testuale.

import csv
from rapidfuzz import fuzz, process

def normalize(kw: str) -> str:
    return kw.lower().strip().replace("?", "").replace("'", "")

def cluster_by_intent(keywords: list[str], threshold: int = 80) -> dict[str, list[str]]:
    clusters = {}
    used = set()

    for kw in keywords:
        norm = normalize(kw)
        if norm in used:
            continue

        # Trova cluster esistente con similarità > threshold
        match = process.extractOne(
            norm,
            list(clusters.keys()),
            scorer=fuzz.token_sort_ratio,
            score_cutoff=threshold
        )

        if match:
            cluster_key = match[0]
            clusters[cluster_key].append(kw)
            used.add(norm)
        else:
            clusters[norm] = [kw]
            used.add(norm)

    return clusters

def export_csv(clusters: dict[str, list[str]], filename: str = "keywords.csv"):
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["cluster", "keyword", "intent_signal"])
        for cluster, kws in clusters.items():
            for kw in kws:
                intent = "informazionale" if "?" in kw else "transazionale"
                writer.writerow([cluster, kw, intent])

# Esempio d'uso
all_keywords = ["come scegliere scarpe da running", "scarpe da running migliori", "scarpe da running prezzo", "perché scarpe da running costose?"]
clusters = cluster_by_intent(all_keywords)
export_csv(clusters)
print(f"{len(clusters)} cluster creati")

L'output CSV è pronto per essere importato in Notion, Airtable o un content calendar. Il clustering riduce tipicamente il volume del 30–50% eliminando duplicati semantici.

Rotazione IP e gestione errori in produzione

In produzione, devi gestire retry, circuit breaker e rotazione IP. ProxyHat supporta sessioni sticky tramite il flag user-session-ID nello username: questo mantiene lo stesso IP per tutta la durata della sessione, utile per evitare incongruenze geografiche durante scraping multi-pagina.

import httpx
import asyncio
import random
import logging
from tenacity import retry, stop_after_attempt, wait_exponential

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

countries = ["IT", "DE", "FR", "ES", "US"]

def proxy_for_country(country: str, session_id: str = None) -> str:
    user = f"user-country-{country}"
    if session_id:
        user += f"-session-{session_id}"
    return f"http://{user}:PASSWORD@gate.proxyhat.com:8080"

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
async def safe_autocomplete(query: str, country: str) -> list[str]:
    proxy = proxy_for_country(country, session_id=f"s{random.randint(1000,9999)}")
    async with httpx.AsyncClient(
        proxy=proxy,
        headers={"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"},
        timeout=httpx.Timeout(15.0, connect=5.0)
    ) as client:
        url = f"https://suggestqueries.google.com/complete/search?client=chrome&q={query}"
        resp = await client.get(url)
        resp.raise_for_status()
        return resp.json()[1]

async def main():
    queries = ["scarpe running", "abbonamento streaming", "vpn gratis"]
    tasks = []
    for q in queries:
        for c in countries:
            tasks.append(safe_autocomplete(q, c))
    results = await asyncio.gather(*tasks, return_exceptions=True)
    total = sum(len(r) for r in results if isinstance(r, list))
    logger.info(f"Totale suggerimenti: {total}")

asyncio.run(main())

Questo pattern combina rotazione paese, sessioni sticky, retry con backoff esponenziale e logging strutturato — una base solida per pipeline di keyword research automatizzate.

Errori comuni e casi limite

  • Locale bias non gestito: se non imposti gl e hl nei parametri URL, Google usa la localizzazione dell'IP. Con proxy IT ottieni risultati italiani, ma se vuoi dati US devi usare user-country-US e gl=us&hl=en.
  • Selettori PAA fragili: Google cambia spesso il markup HTML dei box PAA. Usa selettori basati su role='button' o jsname e aggiorna regolarmente. Un fallback robusto è cercare elementi che terminano con "?".
  • Troppa concorrenza: 50 connessioni simultanee verso Autocomplete dallo stesso gateway proxy possono saturare il rate limit del provider. Mantieni sotto 10–15 connessioni attive.
  • Cookie e sessioni: Playwright accumula cookie tra le navigazioni. Crea un new_context() per ogni keyword per evitare contaminazione di stato.

Considerazioni etiche e legali

I dati di Autocomplete e PAA sono pubblicamente visibili nel browser, ma lo scraping su larga scala deve rispettare i direttive robots.txt di Google e i Termini di Servizio. Per progetti ad alto volume, considera l'API ufficiale Google Custom Search o il Keyword Planner di Google Ads, che offrono dati strutturati e con licenza d'uso.

Linee guida pratiche: throttle a massimo 1 richiesta al secondo per IP, rispetta Crawl-delay se specificato, non ripubblicare dati grezzi di Google come se fossero tuoi, e usa i risultati per analisi interna, non per ricostruire un servizio competitivo diretto. Per approfondire i casi d'uso legittimi, vedi la pagina web scraping use cases e SERP tracking su ProxyHat.

ProxyHat-specific setup

Per iniziare con ProxyHat: registra un account su dashboard.proxyhat.com, ottieni le credenziali, e usa il gateway gate.proxyhat.com:8080 per HTTP o :1080 per SOCKS5. Il geo-targeting nello username segue il formato user-country-XX-city-yyy. Per keyword research multi-paese, ruota il parametro country per confrontare mercati.

Il piano base di ProxyHat offre traffico residenziale con rotazione automatica. Per scraping intensivo, valuta piani con sessioni sticky illimitate che permettono di mantenere lo stesso IP per minuti o ore — utile per espansioni PAA che richiedono coerenza di sessione.

Key Takeaways

  • Autocomplete, PAA e Related Searches sono tre fonti gratuite che coprono intenti diversi: transazionale, informazionale, esplorativo.
  • Un seed-to-longtail expander con 36 modificatori genera 200–350 keyword uniche per seed.
  • I box PAA richiedono Playwright per espansione ricorsiva: 40–80 domande per keyword, con fonti citate.
  • I proxy residenziali geo-targetizzati (gate.proxyhat.com:8080) sono essenziali per evitare rate limit e ottenere suggerimenti localizzati.
  • Dedup con rapidfuzz + clustering per intento riduce il volume del 30–50% e prepara i dati per il content planning.
  • Etica: throttle moderato, rispetto robots.txt, preferire API ufficiali per scale enterprise.

FAQ

D: Cos'è lo scraping di People Also Ask e Autocomplete di Google per ricerca keyword?
R: È la tecnica di estrarre suggerimenti di ricerca dall'endpoint Autocomplete di Google (suggestqueries.google.com) e le domande dai box People Also Ask presenti nei risultati organici, per costruire una mappa di keyword e intenti di ricerca senza usare tool commerciali a pagamento. Si implementa in Python con httpx per le chiamate JSON e Playwright per l'espansione dei box PAA.

D: Perché i proxy sono necessari per lo scraping di Autocomplete e PAA?
R: Google applica rate limiting per-IP aggressivo su Autocomplete (circa 80–100 richieste/minuto) e sistemi anti-bot sui box PAA. I proxy residenziali geo-targetizzati evitano blocchi, mantengono tassi di successo superiori al 95% e permettono di ottenere suggerimenti localizzati per paese e città, essenziali per keyword research multi-mercato.

D: Quale tipo di proxy funziona meglio per lo scraping di People Also Ask e Autocomplete?
R: I proxy residenziali sono la scelta ottimale perché usano IP assegnati da ISP reali, hanno reputazione alta e non vengono bloccati come i datacenter proxy. ProxyHat offre proxy residenziali con geo-targeting a livello di paese e città tramite il gateway gate.proxyhat.com:8080, con sessioni sticky per coerenza durante scraping multi-pagina.

D: Come evitare i blocchi durante lo scraping di People Also Ask e Autocomplete?
R: Mantieni la concorrenza sotto 10–15 connessioni attive, usa sessioni sticky per coerenza IP, implementa retry con backoff esponenziale, ruota i paesi per distribuire il carico, imposta header User-Agent realistici e rispetta un throttle di circa 1 richiesta al secondo per IP. Combina proxy residenziali con Playwright per i box PAA che richiedono rendering JavaScript.

D: Quante keyword si possono ottenere da un singolo seed?
R: Con 36 modificatori (26 lettere + 10 modificatori semantici), Autocomplete produce tipicamente 200–350 keyword uniche per seed. Aggiungendo l'espansione ricorsiva di PAA (40–80 domande) e Related Searches (8–12 termini), un singolo seed può generare oltre 400 keyword con copertura multi-intento.

Pronto per iniziare?

Accedi a oltre 50M di IP residenziali in oltre 148 paesi con filtraggio AI.

Vedi i prezziProxy residenziali
← Torna al Blog