Best Practices für Geo-Targeted SERP Scraping: Der Developer-Leitfaden

Praktischer Leitfaden für Geo-Targeted SERP Scraping: uule, gl, hl und google_domain korrekt kombinieren, City-Level-Targeting mit Residential Proxies umsetzen und Google-Blöcke vermeiden.

Geo-Targeted SERP Scraping Best Practices for Local SEO Data
In diesem Artikel

Best Practices für Geo-Targeted SERP Scraping: Was Sie wissen müssen

Wenn Sie lokalisierte SERP-Datasets für Rank-Tracking, Wettbewerbsanalyse oder lokales SEO aufbauen, reicht ein einfacher HTTP-Request an google.com nicht aus. Google personalisiert Suchergebnisse nach Geolocation, Sprache, Suchverlauf und Geräte-Typ — und genau hier setzen die Best Practices für Geo-Targeted SERP Scraping an: Sie müssen URL-Parameter (gl, hl, uule), IP-Geographie und Browser-Fingerprinting koordinieren, damit die zurückgegebenen SERPs tatsächlich dem Zielmarkt entsprechen. Dieser Leitfaden zeigt Ihnen, wie Sie das mit Python, curl_cffi, selectolax und Residential Proxies über gate.proxyhat.com produktionsreif umsetzen.

Warum dieselbe Suchanfrage unterschiedliche Ergebnisse liefert

Google verwendet mindestens drei Signale, um die Geolocation eines Nutzers zu bestimmen:

  • IP-Adresse — wird über GeoIP-Datenbanken wie MaxMind GeoIP2 auf Länder- und Stadtebene aufgelöst.
  • URL-Parametergl (Google-Ländercode), hl (Interface-Sprache), google_domain (z.B. google.de vs. google.co.uk) und uule (codierter Ortsname).
  • Kontextsignale — Browser-Sprache (Accept-Language), GPS/HTML5-Geolocation (nur im Browser) und Suchverlauf (personalisierte Ergebnisse).

Ein Request von einer deutschen IP ohne gl-Parameter liefert Ergebnisse für den deutschen Markt. Dieselbe Suchanfrage mit gl=us und einer US-IP liefert deutlich andere organische Ergebnisse, ein anderes Local Pack und oft andere Featured Snippets. Länderebene allein reicht jedoch nicht: Ein Nutzer in New York sieht andere Local-Pack-Einträge als jemand in Austin, Texas — selbst wenn beide gl=us setzen. Für lokales SEO benötigen Sie City- oder District-Level-Präzision über den uule-Parameter, kombiniert mit einer passenden IP aus derselben Region.

Die Kern-Parameter: gl, hl, google_domain, lr und uule

Google unterstützt mehrere Parameter zur Steuerung der Lokalisierung. Laut der Google Custom Search XML-Dokumentation steuern gl und hl die grundlegende Länder- und Sprachzuordnung. Für präzises Geo-Targeting benötigen Sie jedoch zusätzlich uule und pws=0.

Parameter Beschreibung Beispiel Pflicht für City-Targeting?
gl Ländercode (ISO 3166-1 alpha-2) gl=us Ja — Basis-Lokalisierung
hl Interface-Sprache hl=en Empfohlen — sollte mit gl übereinstimmen
google_domain Top-Level-Domain google.de Optional — gl ist verlässlicher
lr Sprache der Dokumente einschränken lr=lang_en Optional — für sprachspezifische Filter
uule Codierter kanonischer Ortsname w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM= Ja — City-Level-Präzision
pws=0 Personalisierung deaktivieren pws=0 Empfohlen — reproduzierbare Baseline

uule konstruieren: City-Level-Präzision

Der uule-Parameter ist ein Base64-codierter kanonischer Ortsname mit einem festen Präfix und einem Längen-Key. Der Aufbau ist: w+CAIQICI (fester Präfix) + Längen-Key (ein Zeichen, das die Länge des Base64-Strings repräsentiert) + Base64(Ortsname). Der kanonische Ortsname folgt dem Format Stadt,Bundesland,Land, z.B. Austin,Texas,United States.

Die Base64-Codierung ist in RFC 4648 spezifiziert. Der Längen-Key wird als chr(len(base64_string) + 0x40) berechnet — bei einer Länge von 36 Zeichen ergibt das chr(100) = 'd'.

# uule-Konstruktion in reinem Python
import base64

def build_uule(canonical_name: str) -> str:
    """
    Erzeugt einen Google uule-Parameter aus einem kanonischen Ortsnamen.
    Format: 'w+CAIQICI' + length_key + base64(canonical_name)
    
    Beispiele für canonical_name:
      'Austin,Texas,United States'
      'New York,New York,United States'
      'Berlin,Berlin,Germany'
      'München,Bayern,Germany'
    """
    b64 = base64.b64encode(canonical_name.encode("utf-8")).decode("utf-8")
    length_key = chr(len(b64) + 0x40)  # '@'=0x40, len=1 -> 'A'
    return f"w+CAIQICI{length_key}{b64}"

# Beispiel
uule = build_uule("Austin,Texas,United States")
print(uule)
# -> w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=

IP-Geographie und Proxy-Koordination

Google gleicht die URL-Parameter mit der IP-Geographie ab. Wenn Sie gl=us&uule=...Austin... senden, die Anfrage aber von einer IP in Frankfurt kommt, kann Google die Parameter ignorieren oder ein CAPTCHA auslösen. Die Lösung: Residential Proxies aus demselben Markt. ProxyHat bietet Geo-Targeting auf Länder- und Stadtebene direkt im Usernamen:

  • user-country-US-city-newyork:pass — US-IP aus New York
  • user-country-DE-city-berlin:pass — deutsche IP aus Berlin
  • user-country-US-city-austin:pass — US-IP aus Austin, Texas

Die Kombination aus uule und passender IP aus derselben Stadt liefert die verlässlichsten lokalen SERP-Daten. Datacenter-IPs funktionieren für Tests, werden von Google aber häufiger herausgefiltert — Residential Proxies haben typischerweise eine 3-5× höhere Erfolgsquote bei SERP-Scraping.

Implementierung: Code-Beispiele

1. Basis-Request mit curl (Raw Proxy Usage)

Der einfachste Weg, einen geo-targeted SERP-Request abzusetzen — mit curl und ProxyHat als HTTP-Proxy:

# SERP-Request für "coffee shop" in Austin, TX
# mit gl, hl, uule und pws=0 über ProxyHat Residential Proxy

curl -s \
  --proxy "http://user-country-US-city-austin:PASS@gate.proxyhat.com:8080" \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" \
  -H "Accept-Language: en-US,en;q=0.9" \
  "https://www.google.com/search?q=coffee+shop&gl=us&hl=en&uule=w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=&pws=0&num=100"

2. ProxyHat Helper-Klasse (SDK-Stil) und curl_cffi mit Chrome-Impersonation

Für produktive Systeme sollten Sie den Proxy-URL-Bau kapseln. Hier eine Lightweight-Helper-Klasse, die als Mini-SDK fungiert, kombiniert mit curl_cffi für TLS-Fingerprint-Impersonation:

# pip install curl_cffi selectolax

from curl_cffi import requests as cffi_requests
from dataclasses import dataclass
import base64
import logging
import random
import time

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("serp_scraper")

# --- ProxyHat Mini-SDK ---

class ProxyHat:
    """Lightweight ProxyHat SDK für Geo-Targeted SERP Scraping."""
    GATEWAY = "gate.proxyhat.com"
    HTTP_PORT = 8080
    SOCKS5_PORT = 1080

    def __init__(self, username: str, password: str):
        self.username = username
        self.password = password

    def proxy_url(
        self,
        country: str | None = None,
        city: str | None = None,
        session: str | None = None,
        protocol: str = "http",
    ) -> str:
        """Erzeugt eine Proxy-URL mit Geo- und Session-Flags."""
        parts = [self.username]
        if country:
            parts.append(f"country-{country.upper()}")
        if city:
            parts.append(f"city-{city.lower().replace(' ', '')}")
        if session:
            parts.append(f"session-{session}")
        user = "-".join(parts)
        port = self.HTTP_PORT if protocol == "http" else self.SOCKS5_PORT
        scheme = "http" if protocol == "http" else "socks5"
        return f"{scheme}://{user}:{self.password}@{self.GATEWAY}:{port}"

    def proxies(self, **kwargs) -> dict:
        """Gibt ein proxies-dict für requests/curl_cffi zurück."""
        url = self.proxy_url(**kwargs)
        return {"http": url, "https": url}


# --- uule-Builder ---

def build_uule(canonical_name: str) -> str:
    b64 = base64.b64encode(canonical_name.encode("utf-8")).decode("utf-8")
    length_key = chr(len(b64) + 0x40)
    return f"w+CAIQICI{length_key}{b64}"


# --- SERP-Scraper ---

@dataclass
class LocaleConfig:
    country_code: str       # "us"
    language: str           # "en"
    canonical_name: str     # "Austin,Texas,United States"
    proxy_city: str         # "austin"
    google_domain: str = "www.google.com"


LOCALES = [
    LocaleConfig("us", "en", "Austin,Texas,United States", "austin"),
    LocaleConfig("us", "en", "New York,New York,United States", "newyork"),
    LocaleConfig("de", "de", "Berlin,Berlin,Germany", "berlin"),
    LocaleConfig("de", "de", "München,Bayern,Germany", "münchen"),
]


def scrape_serp(query: str, locale: LocaleConfig, ph: ProxyHat) -> str:
    """Sendet einen geo-targeted SERP-Request mit Chrome-Impersonation."""
    uule = build_uule(locale.canonical_name)
    params = {
        "q": query,
        "gl": locale.country_code,
        "hl": locale.language,
        "uule": uule,
        "pws": "0",
        "num": "100",
    }
    url = f"https://{locale.google_domain}/search"

    proxies = ph.proxies(
        country=locale.country_code,
        city=locale.proxy_city,
    )

    resp = cffi_requests.get(
        url,
        params=params,
        proxies=proxies,
        impersonate="chrome",
        timeout=30,
    )
    logger.info(
        f"[{locale.canonical_name}] status={resp.status_code} "
        f"bytes={len(resp.text)} ip_session=rotating"
    )
    resp.raise_for_status()
    return resp.text


# --- Main ---
if __name__ == "__main__":
    ph = ProxyHat("user", "your_password")
    for locale in LOCALES:
        try:
            html = scrape_serp("best coffee shop", locale, ph)
            with open(f"serp_{locale.proxy_city}.html", "w", encoding="utf-8") as f:
                f.write(html)
        except Exception as e:
            logger.error(f"Fehler für {locale.proxy_city}: {e}")
        time.sleep(random.uniform(1.5, 3.5))  # Rate-Limiting

Raw-Proxy-Alternative ohne Helper-Klasse: Statt der ProxyHat-Klasse können Sie die Proxy-URL auch direkt konstruieren:

# Direkte Proxy-URL (ohne SDK-Helper)
proxy = "http://user-country-US-city-austin:PASS@gate.proxyhat.com:8080"
resp = cffi_requests.get(url, params=params, proxies={"http": proxy, "https": proxy}, impersonate="chrome")

3. Organic Results und Local Pack parsen mit selectolax

Nach dem Abruf müssen Sie die HTML-Struktur parsen. Google ändert Klassen häufig, aber die folgenden Selektoren sind über mehrere Updates stabil geblieben:

from selectolax.parser import HTMLParser
from dataclasses import dataclass, asdict
import json

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

@dataclass
class LocalPackEntry:
    name: str
    rating: float | None
    reviews: int | None
    address: str | None
    phone: str | None


def parse_organic(html: str) -> list[OrganicResult]:
    """Parst organische Suchergebnisse."""
    tree = HTMLParser(html)
    results = []
    pos = 0
    for node in tree.css("div.g div.tF2Cxc"):
        pos += 1
        title_el = node.css_first("h3")
        link_el = node.css_first("a[href]")
        snippet_el = node.css_first("div[data-sncf], div.VwiC3b, span.aCOpRe")
        title = title_el.text(strip=True) if title_el else ""
        url = link_el.attributes.get("href", "") if link_el else ""
        snippet = snippet_el.text(strip=True) if snippet_el else ""
        if title and url:
            results.append(OrganicResult(pos, title, url, snippet))
    return results


def parse_local_pack(html: str) -> list[LocalPackEntry]:
    """Parst das Local Pack (Google Maps Results)."""
    tree = HTMLParser(html)
    entries = []
    # Local Pack Container — Selektor kann variieren
    for card in tree.css("div[data-cid] div.SW5HFd, div.rllt__details"):
        name_el = card.css_first("div.dbg0p, span.O3ErS")
        rating_el = card.css_first("span.MV3lbe, span[role='img']")
        name = name_el.text(strip=True) if name_el else ""
        rating = None
        if rating_el:
            r = rating_el.attributes.get("aria-label", "")
            if "star" in r.lower():
                try:
                    rating = float(r.split()[0].replace(",", "."))
                except (ValueError, IndexError):
                    pass
        entries.append(LocalPackEntry(name, rating, None, None, None))
    return entries


# --- Usage ---
if __name__ == "__main__":
    with open("serp_austin.html", "r", encoding="utf-8") as f:
        html = f.read()

    organic = parse_organic(html)
    local = parse_local_pack(html)

    print(f"=== Organic Results ({len(organic)}) ===")
    for r in organic[:5]:
        print(f"{r.position}. {r.title} — {r.url}")

    print(f"\n=== Local Pack ({len(local)}) ===")
    for e in local[:3]:
        print(f"{e.name} (Rating: {e.rating})")

    # Als JSON exportieren
    output = {
        "organic": [asdict(r) for r in organic],
        "local_pack": [asdict(e) for e in local],
    }
    with open("serp_austin_parsed.json", "w", encoding="utf-8") as f:
        json.dump(output, f, ensure_ascii=False, indent=2)

4. Sticky Sessions für Multi-Page-SERPs

Wenn Sie mehrere Seiten derselben Suchanfrage abrufen (z.B. Ergebnisse 1–100 über start=0, start=10, start=20), muss dieselbe IP verwendet werden — sonst kann Google unterschiedliche Personalisierungen pro Seite anwenden. ProxyHat unterstützt Sticky Sessions über das session-Flag im Usernamen:

import random
import string
from curl_cffi import requests as cffi_requests

def scrape_multi_page(query: str, locale: LocaleConfig, ph: ProxyHat, pages: int = 5):
    """
    Ruft mehrere SERP-Seiten ab mit derselben IP (Sticky Session).
    Die Session-ID hält die IP für die Dauer der Session stabil.
    """
    session_id = "serp_" + "".join(random.choices(string.ascii_lowercase + string.digits, k=8))
    uule = build_uule(locale.canonical_name)
    all_results = []

    for page in range(pages):
        start = page * 10
        params = {
            "q": query,
            "gl": locale.country_code,
            "hl": locale.language,
            "uule": uule,
            "pws": "0",
            "num": "10",
            "start": str(start),
        }
        url = f"https://{locale.google_domain}/search"

        # Sticky Session: dieselbe session_id -> dieselbe IP
        proxies = ph.proxies(
            country=locale.country_code,
            city=locale.proxy_city,
            session=session_id,
        )

        try:
            resp = cffi_requests.get(
                url,
                params=params,
                proxies=proxies,
                impersonate="chrome",
                timeout=30,
            )
            logger.info(
                f"Page {page+1}/{pages} | start={start} | "
                f"status={resp.status_code} | session={session_id}"
            )
            resp.raise_for_status()
            results = parse_organic(resp.text)
            all_results.extend(results)
        except Exception as e:
            logger.error(f"Page {page+1} fehlgeschlagen: {e}")
            break

        time.sleep(random.uniform(2.0, 4.0))

    return all_results

# Beispielaufruf
ph = ProxyHat("user", "your_password")
locale = LocaleConfig("us", "en", "Austin,Texas,United States", "austin")
results = scrape_multi_page("plumber", locale, ph, pages=5)
print(f"Insgesamt {len(results)} organische Ergebnisse über 5 Seiten")

5. Retry/Backoff mit per-Country Proxy-Pools und CAPTCHA-Erkennung

Google antwortet auf verdächtiges Scraping-Verhalten mit HTTP 429 (Too Many Requests), CAPTCHAs oder 302-Redirects auf sorry.google.com. Ein robuster Scraper braucht Exponential Backoff, CAPTCHA-Erkennung und separate Proxy-Pools pro Land:

import time
import random
from curl_cffi import requests as cffi_requests
from dataclasses import dataclass

@dataclass
class ScrapeResult:
    success: bool
    html: str | None
    status_code: int
    error: str | None


class SERPScraper:
    """Robuster SERP-Scraper mit Retry, Backoff und CAPTCHA-Erkennung."""

    MAX_RETRIES = 4
    BASE_DELAY = 3.0  # Sekunden
    MAX_DELAY = 60.0

    def __init__(self, ph: ProxyHat):
        self.ph = ph

    def _is_captcha(self, html: str) -> bool:
        markers = ["sorry.google.com", "g-recaptcha", "unusual traffic", "CAPTCHA"]
        return any(m in html for m in markers)

    def _backoff(self, attempt: int) -> float:
        delay = min(self.BASE_DELAY * (2 ** attempt) + random.uniform(0, 1), self.MAX_DELAY)
        return delay

    def scrape(
        self,
        query: str,
        locale: LocaleConfig,
        session: str | None = None,
    ) -> ScrapeResult:
        """
        Sendet einen SERP-Request mit Retry-Logik.
        Rotiert bei 429/CAPTCHA automatisch auf eine neue IP
        (neue Session-ID = neue IP aus demselben Geo-Pool).
        """
        uule = build_uule(locale.canonical_name)
        url = f"https://{locale.google_domain}/search"
        params = {
            "q": query,
            "gl": locale.country_code,
            "hl": locale.language,
            "uule": uule,
            "pws": "0",
            "num": "100",
        }

        for attempt in range(self.MAX_RETRIES):
            # Bei Retry: neue Session-ID für neue IP aus demselben City-Pool
            current_session = session if session else f"retry_{attempt}_{random.randint(1000,9999)}"
            proxies = self.ph.proxies(
                country=locale.country_code,
                city=locale.proxy_city,
                session=current_session,
            )

            try:
                resp = cffi_requests.get(
                    url,
                    params=params,
                    proxies=proxies,
                    impersonate="chrome",
                    timeout=30,
                )

                # CAPTCHA-Erkennung
                if resp.status_code == 200 and self._is_captcha(resp.text):
                    delay = self._backoff(attempt)
                    logger.warning(
                        f"CAPTCHA erkannt für {locale.proxy_city} | "
                        f"attempt={attempt+1}/{self.MAX_RETRIES} | "
                        f"backoff={delay:.1f}s"
                    )
                    time.sleep(delay)
                    continue

                # Rate Limiting
                if resp.status_code == 429:
                    delay = self._backoff(attempt)
                    logger.warning(
                        f"HTTP 429 für {locale.proxy_city} | "
                        f"attempt={attempt+1}/{self.MAX_RETRIES} | "
                        f"backoff={delay:.1f}s"
                    )
                    time.sleep(delay)
                    continue

                resp.raise_for_status()
                logger.info(
                    f"Erfolg: {locale.proxy_city} | "
                    f"status={resp.status_code} | "
                    f"bytes={len(resp.text)} | "
                    f"attempt={attempt+1}"
                )
                return ScrapeResult(True, resp.text, resp.status_code, None)

            except cffi_requests.RequestsError as e:
                delay = self._backoff(attempt)
                logger.error(
                    f"Request-Fehler für {locale.proxy_city}: {e} | "
                    f"backoff={delay:.1f}s"
                )
                time.sleep(delay)

        return ScrapeResult(False, None, 0, "Max retries exceeded")


# --- Multi-Locale Scraping mit Per-Country Pools ---
if __name__ == "__main__":
    ph = ProxyHat("user", "your_password")
    scraper = SERPScraper(ph)

    queries = ["dentist", "electrician", "roofing contractor"]
    locales = [
        LocaleConfig("us", "en", "Austin,Texas,United States", "austin"),
        LocaleConfig("us", "en", "New York,New York,United States", "newyork"),
        LocaleConfig("de", "de", "Berlin,Berlin,Germany", "berlin"),
    ]

    for locale in locales:
        for query in queries:
            result = scraper.scrape(query, locale)
            if result.success:
                organic = parse_organic(result.html)
                local_pack = parse_local_pack(result.html)
                logger.info(
                    f"{locale.proxy_city} | q='{query}' | "
                    f"organic={len(organic)} | local_pack={len(local_pack)}"
                )
            else:
                logger.error(f"{locale.proxy_city} | q='{query}' | FAILED: {result.error}")
            time.sleep(random.uniform(2.0, 5.0))

Häufige Fehler und Edge Cases

  • Parameter-Mismatch: gl=us mit hl=de und einer deutschen IP führt zu unvorhersehbaren Ergebnissen. gl, hl und Proxy-Land sollten konsistent sein.
  • uule ohne passende IP: uule für Austin mit einer IP aus Los Angeles liefert verzerrte Local-Pack-Ergebnisse. Die IP-Stadt muss nicht exakt übereinstimmen, sollte aber im selben Markt liegen.
  • Vergessenes pws=0: Ohne pws=0 personalisiert Google Ergebnisse basierend auf Cookies und Suchverlauf — selbst bei Inprivate-Requests können personalisierte SERPs zurückkommen, wenn Google den Fingerprint assoziiert.
  • Zu hohe Concurrency: Mehr als 10–15 Requests pro Sekunde aus demselben Proxy-Pool erhöhen das CAPTCHA-Risiko deutlich. Eine Rate von 2–5 Requests/Sekunde mit zufälligen Delays ist sicherer.
  • Veraltete CSS-Selektoren: Google ändert HTML-Klassen regelmäßig. Testen Sie Parser gegen aktuelle SERP-HTML-Snippets und implementieren Sie Fallback-Selektoren.
  • Local Pack in Ländern ohne Google Maps: In einigen Märkten (z.B. China) ist das Local Pack nicht verfügbar oder unterschiedlich strukturiert.

ProxyHat-spezifische Einrichtung

ProxyHat macht Geo-Targeting einfach: Alle Parameter werden im Usernamen codiert. Für US Geo-Targeted SERP Scraping Best Practices verwenden Sie das Format user-country-US-city-{city}:pass. Die vollständige Dokumentation aller Parameter finden Sie unter docs.proxyhat.com.

Die wichtigsten Konfigurationen für SERP-Scraping:

  • Rotierende IPs (Standard): Jeder Request erhält eine neue IP — ideal für breite SERP-Erfassung.
  • Sticky Sessions: session-{id} hält die IP stabil — notwendig für Multi-Page-SERPs.
  • City-Level-Targeting: city-{name} — kombiniert mit uule für maximale Präzision beim Local SERP Scraping by City.
  • SOCKS5: Für Anwendungen, die SOCKS5 benötigen, verwenden Sie Port 1080 statt 8080.

Preise und verfügbare Standorte finden Sie auf der Preisseite und der Standortübersicht. Weitere Use Cases für Web-Scraping und SERP-Tracking finden Sie unter Web-Scraping und SERP-Tracking.

Rechtliche Hinweise: TOS und öffentliche Daten

Das Scraping von Google-SERPs bewegt sich in einer rechtlichen Grauzone. Googles Nutzungsbedingungen verbieten automatisierte Abfragen. In der Praxis scrapen viele SEO-Tools SERP-Daten, aber Sie sollten:

  • Rate-Limits respektieren und menschenähnliche Request-Muster verwenden.
  • robots.txt prüfen — Google erlaubt bestimmte Pfade nicht.
  • DSGVO/GDPR beachten, wenn personenbezogene Daten (z.B. aus Local Packs) gespeichert werden.
  • Eine rechtliche Beratung einholen, bevor Sie kommerzielle SERP-Datensets verkaufen.

Wichtig: Dieser Artikel beschreibt technische Methoden für Entwickler. Die Einhaltung der Nutzungsbedingungen Dritter und geltender Gesetze liegt in Ihrer Verantwortung.

Key Takeaways

  • Stellen Sie gl, hl und uule konsistent ein und kombinieren Sie sie mit pws=0 für reproduzierbare, nicht-personalisierte SERPs.
  • City-Level-Targeting erfordert uule + passende IP: Google gleicht URL-Parameter mit der IP-Geographie ab. Verwenden Sie Residential Proxies aus derselben Stadt.
  • Sticky Sessions für Multi-Page-SERPs: Verwenden Sie session-{id} im ProxyHat-Usernamen, um dieselbe IP über mehrere Seiten zu halten.
  • Implementieren Sie Exponential Backoff und CAPTCHA-Erkennung: HTTP 429 und CAPTCHA-Redirects sind normal — ein robuster Scraper rotiert die IP und wartet mit Backoff.
  • Chrome-Impersonation via curl_cffi reduziert TLS-Fingerprinting-Risiken erheblich gegenüber Standard requests.
  • Halten Sie Parser aktuell: Google ändert HTML-Klassen regelmäßig. Testen Sie gegen aktuelle SERP-HTML-Snippets.

FAQ

Was ist Geo-Targeted SERP Scraping?

Geo-Targeted SERP Scraping ist das gezielte Abrufen von Google-Suchergebnissen für eine bestimmte geografische Region — nicht nur auf Länderebene, sondern auf Stadt- oder District-Ebene. Dabei werden URL-Parameter wie gl (Land), hl (Sprache) und uule (codierter Ortsname) mit einer passenden IP aus derselben Region kombiniert, um sicherzustellen, dass die zurückgegebenen SERPs tatsächlich den lokalen Markt widerspiegeln.

Warum ist Geo-Targeted SERP Scraping wichtig für Proxy-Nutzer?

Google gleicht die Geolocation-Parameter mit der IP-Adresse des Anfragenden ab. Wenn Sie gl=us und uule für Austin setzen, aber die Anfrage von einer deutschen IP kommt, kann Google die Parameter ignorieren oder ein CAPTCHA auslösen. Proxy-Nutzer müssen Residential Proxies aus demselben Markt verwenden, damit die IP-Geographie mit den URL-Parametern übereinstimmt und die SERP-Daten verlässlich sind.

Welcher Proxy-Typ funktioniert am besten für Geo-Targeted SERP Scraping?

Residential Proxies sind die beste Wahl für Geo-Targeted SERP Scraping. Sie stammen von echten ISPs und werden von Google seltener als automatisierte Traffic-Quelle erkannt als Datacenter-IPs. ProxyHat bietet Residential Proxies mit Geo-Targeting auf Stadtebene über das Username-Format user-country-US-city-austin:pass. Datacenter-Proxies können für Tests funktionieren, haben aber eine deutlich höhere Block-Wahrscheinlichkeit.

Wie vermeidet man Blöcke beim Geo-Targeted SERP Scraping?

Verwenden Sie Chrome-Impersonation (z.B. curl_cffi mit impersonate="chrome"), um TLS-Fingerprints zu verschleiern. Setzen Sie realistische Accept-Language-Header, die mit hl übereinstimmen. Implementieren Sie Exponential Backoff bei HTTP 429 und CAPTCHA-Redirects, rotieren Sie IPs bei Fehlern, und halten Sie die Concurrency niedrig (2–5 Requests/Sekunde pro Proxy-Pool). Verwenden Sie Sticky Sessions für Multi-Page-Abfragen, um IP-Wechsel innerhalb einer Suchanfrage zu vermeiden.

Wie konstruiert man den uule-Parameter korrekt?

Der uule-Parameter besteht aus dem festen Präfix w+CAIQICI, gefolgt von einem Längen-Key-Zeichen und dem Base64-codierten kanonischen Ortsnamen im Format Stadt,Bundesland,Land. Der Längen-Key wird als chr(len(base64_string) + 0x40) berechnet. Beispiel: Für Austin,Texas,United States ergibt sich w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=. Setzen Sie immer zusätzlich pws=0, um Personalisierung zu deaktivieren.

Häufig gestellte Fragen

Was ist Geo-Targeted SERP Scraping?

Geo-Targeted SERP Scraping ist das gezielte Abrufen von Google-Suchergebnissen für eine bestimmte geografische Region — nicht nur auf Länderebene, sondern auf Stadt- oder District-Ebene. Dabei werden URL-Parameter wie gl (Land), hl (Sprache) und uule (codierter Ortsname) mit einer passenden IP aus derselben Region kombiniert, um sicherzustellen, dass die zurückgegebenen SERPs tatsächlich den lokalen Markt widerspiegeln.

Warum ist Geo-Targeted SERP Scraping wichtig für Proxy-Nutzer?

Google gleicht die Geolocation-Parameter mit der IP-Adresse des Anfragenden ab. Wenn Sie gl=us und uule für Austin setzen, aber die Anfrage von einer deutschen IP kommt, kann Google die Parameter ignorieren oder ein CAPTCHA auslösen. Proxy-Nutzer müssen Residential Proxies aus demselben Markt verwenden, damit die IP-Geographie mit den URL-Parametern übereinstimmt und die SERP-Daten verlässlich sind.

Welcher Proxy-Typ funktioniert am besten für Geo-Targeted SERP Scraping?

Residential Proxies sind die beste Wahl für Geo-Targeted SERP Scraping. Sie stammen von echten ISPs und werden von Google seltener als automatisierte Traffic-Quelle erkannt als Datacenter-IPs. ProxyHat bietet Residential Proxies mit Geo-Targeting auf Stadtebene über das Username-Format user-country-US-city-austin:pass. Datacenter-Proxies können für Tests funktionieren, haben aber eine deutlich höhere Block-Wahrscheinlichkeit.

Wie vermeidet man Blöcke beim Geo-Targeted SERP Scraping?

Verwenden Sie Chrome-Impersonation (z.B. curl_cffi mit impersonate=chrome), um TLS-Fingerprints zu verschleiern. Setzen Sie realistische Accept-Language-Header, die mit hl übereinstimmen. Implementieren Sie Exponential Backoff bei HTTP 429 und CAPTCHA-Redirects, rotieren Sie IPs bei Fehlern, und halten Sie die Concurrency niedrig (2–5 Requests/Sekunde pro Proxy-Pool). Verwenden Sie Sticky Sessions für Multi-Page-Abfragen, um IP-Wechsel innerhalb einer Suchanfrage zu vermeiden.

Wie konstruiert man den uule-Parameter korrekt?

Der uule-Parameter besteht aus dem festen Präfix w+CAIQICI, gefolgt von einem Längen-Key-Zeichen und dem Base64-codierten kanonischen Ortsnamen im Format Stadt,Bundesland,Land. Der Längen-Key wird als chr(len(base64_string) + 0x40) berechnet. Beispiel: Für Austin,Texas,United States ergibt sich w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=. Setzen Sie immer zusätzlich pws=0, um Personalisierung zu deaktivieren.

Bereit loszulegen?

Residential-, ISP- und Mobile-Proxys in über 148 Ländern. Erstelle ein kostenloses Konto.

Kostenloses Konto erstellen
← Zurück zum Blog