[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-de-geo-targeted-serp-scraping-leitfaden":3},{"success":4,"payload":5,"related":61,"errors":128},true,{"id":6,"slug":7,"title":8,"excerpt":9,"body_html":10,"meta_title":11,"meta_description":12,"canonical_url":13,"canonical_override":14,"og_title":15,"og_description":16,"og_image_url":17,"faq_json":18,"key_takeaways":14,"allow_index":28,"noindex_google_only":28,"allow_follow":4,"published_at":29,"updated_at":29,"content_updated_at":30,"featured_image_url":31,"featured_image_alt":32,"card_image_url":33,"reading_time_minutes":34,"author":35,"categories":39,"tags":46,"alternates":47,"locale_paths":49,"views":60},198,"geo-targeted-serp-scraping-leitfaden","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.","\u003Ch2>Best Practices für Geo-Targeted SERP Scraping: Was Sie wissen müssen\u003C\u002Fh2>\n\u003Cp>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 (\u003Ccode>gl\u003C\u002Fcode>, \u003Ccode>hl\u003C\u002Fcode>, \u003Ccode>uule\u003C\u002Fcode>), 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, \u003Ccode>curl_cffi\u003C\u002Fcode>, \u003Ccode>selectolax\u003C\u002Fcode> und Residential Proxies über \u003Ccode>gate.proxyhat.com\u003C\u002Fcode> produktionsreif umsetzen.\u003C\u002Fp>\n\n\u003Ch2>Warum dieselbe Suchanfrage unterschiedliche Ergebnisse liefert\u003C\u002Fh2>\n\u003Cp>Google verwendet mindestens drei Signale, um die Geolocation eines Nutzers zu bestimmen:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>IP-Adresse\u003C\u002Fstrong> — wird über GeoIP-Datenbanken wie \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGeoIP\" rel=\"noopener noreferrer\">MaxMind GeoIP2\u003C\u002Fa> auf Länder- und Stadtebene aufgelöst.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>URL-Parameter\u003C\u002Fstrong> — \u003Ccode>gl\u003C\u002Fcode> (Google-Ländercode), \u003Ccode>hl\u003C\u002Fcode> (Interface-Sprache), \u003Ccode>google_domain\u003C\u002Fcode> (z.B. \u003Ccode>google.de\u003C\u002Fcode> vs. \u003Ccode>google.co.uk\u003C\u002Fcode>) und \u003Ccode>uule\u003C\u002Fcode> (codierter Ortsname).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Kontextsignale\u003C\u002Fstrong> — Browser-Sprache (\u003Ccode>Accept-Language\u003C\u002Fcode>), GPS\u002FHTML5-Geolocation (nur im Browser) und Suchverlauf (personalisierte Ergebnisse).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Ein Request von einer deutschen IP ohne \u003Ccode>gl\u003C\u002Fcode>-Parameter liefert Ergebnisse für den deutschen Markt. Dieselbe Suchanfrage mit \u003Ccode>gl=us\u003C\u002Fcode> und einer US-IP liefert deutlich andere organische Ergebnisse, ein anderes Local Pack und oft andere Featured Snippets. \u003Cstrong>Länderebene allein reicht jedoch nicht\u003C\u002Fstrong>: Ein Nutzer in New York sieht andere Local-Pack-Einträge als jemand in Austin, Texas — selbst wenn beide \u003Ccode>gl=us\u003C\u002Fcode> setzen. Für lokales SEO benötigen Sie \u003Cstrong>City- oder District-Level-Präzision\u003C\u002Fstrong> über den \u003Ccode>uule\u003C\u002Fcode>-Parameter, kombiniert mit einer passenden IP aus derselben Region.\u003C\u002Fp>\n\n\u003Ch2>Die Kern-Parameter: gl, hl, google_domain, lr und uule\u003C\u002Fh2>\n\u003Cp>Google unterstützt mehrere Parameter zur Steuerung der Lokalisierung. Laut der Google Custom Search XML-Dokumentation steuern \u003Ccode>gl\u003C\u002Fcode> und \u003Ccode>hl\u003C\u002Fcode> die grundlegende Länder- und Sprachzuordnung. Für präzises Geo-Targeting benötigen Sie jedoch zusätzlich \u003Ccode>uule\u003C\u002Fcode> und \u003Ccode>pws=0\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Parameter\u003C\u002Fth>\n\u003Cth>Beschreibung\u003C\u002Fth>\n\u003Cth>Beispiel\u003C\u002Fth>\n\u003Cth>Pflicht für City-Targeting?\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gl\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Ländercode (ISO 3166-1 alpha-2)\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>gl=us\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Ja — Basis-Lokalisierung\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hl\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Interface-Sprache\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>hl=en\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Empfohlen — sollte mit \u003Ccode>gl\u003C\u002Fcode> übereinstimmen\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>google_domain\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Top-Level-Domain\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>google.de\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Optional — \u003Ccode>gl\u003C\u002Fcode> ist verlässlicher\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lr\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Sprache der Dokumente einschränken\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>lr=lang_en\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Optional — für sprachspezifische Filter\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>uule\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Codierter kanonischer Ortsname\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Ja — City-Level-Präzision\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>pws=0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Personalisierung deaktivieren\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>pws=0\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Empfohlen — reproduzierbare Baseline\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Ch3>uule konstruieren: City-Level-Präzision\u003C\u002Fh3>\n\u003Cp>Der \u003Ccode>uule\u003C\u002Fcode>-Parameter ist ein Base64-codierter kanonischer Ortsname mit einem festen Präfix und einem Längen-Key. Der Aufbau ist: \u003Ccode>w+CAIQICI\u003C\u002Fcode> (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 \u003Ccode>Stadt,Bundesland,Land\u003C\u002Fcode>, z.B. \u003Ccode>Austin,Texas,United States\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Die \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBase64\" rel=\"noopener noreferrer\">Base64-Codierung\u003C\u002Fa> ist in RFC 4648 spezifiziert. Der Längen-Key wird als \u003Ccode>chr(len(base64_string) + 0x40)\u003C\u002Fcode> berechnet — bei einer Länge von 36 Zeichen ergibt das \u003Ccode>chr(100)\u003C\u002Fcode> = \u003Ccode>'d'\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># uule-Konstruktion in reinem Python\nimport base64\n\ndef build_uule(canonical_name: str) -&gt; str:\n    &quot;&quot;&quot;\n    Erzeugt einen Google uule-Parameter aus einem kanonischen Ortsnamen.\n    Format: &apos;w+CAIQICI&apos; + length_key + base64(canonical_name)\n    \n    Beispiele für canonical_name:\n      &apos;Austin,Texas,United States&apos;\n      &apos;New York,New York,United States&apos;\n      &apos;Berlin,Berlin,Germany&apos;\n      &apos;München,Bayern,Germany&apos;\n    &quot;&quot;&quot;\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;utf-8&quot;)\n    length_key = chr(len(b64) + 0x40)  # &apos;@&apos;=0x40, len=1 -&gt; &apos;A&apos;\n    return f&quot;w+CAIQICI{length_key}{b64}&quot;\n\n# Beispiel\nuule = build_uule(&quot;Austin,Texas,United States&quot;)\nprint(uule)\n# -&gt; w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>IP-Geographie und Proxy-Koordination\u003C\u002Fh2>\n\u003Cp>Google gleicht die URL-Parameter mit der IP-Geographie ab. Wenn Sie \u003Ccode>gl=us&uule=...Austin...\u003C\u002Fcode> 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:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>user-country-US-region-new_york-city-new_york_city:pass\u003C\u002Fcode> — US-IP aus New York\u003C\u002Fli>\n\u003Cli>\u003Ccode>user-country-DE-region-state_of_berlin-city-berlin:pass\u003C\u002Fcode> — deutsche IP aus Berlin\u003C\u002Fli>\n\u003Cli>\u003Ccode>user-country-US-region-texas-city-austin:pass\u003C\u002Fcode> — US-IP aus Austin, Texas\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Die Kombination aus \u003Ccode>uule\u003C\u002Fcode> 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.\u003C\u002Fp>\n\n\u003Ch2>Implementierung: Code-Beispiele\u003C\u002Fh2>\n\n\u003Ch3>1. Basis-Request mit curl (Raw Proxy Usage)\u003C\u002Fh3>\n\u003Cp>Der einfachste Weg, einen geo-targeted SERP-Request abzusetzen — mit \u003Ccode>curl\u003C\u002Fcode> und ProxyHat als HTTP-Proxy:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># SERP-Request für &quot;coffee shop&quot; in Austin, TX\n# mit gl, hl, uule und pws=0 über ProxyHat Residential Proxy\n\ncurl -s \\\n  --proxy &quot;http:\u002F\u002Fuser-country-US-region-texas-city-austin:PASS@gate.proxyhat.com:8080&quot; \\\n  -H &quot;User-Agent: Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F131.0.0.0 Safari\u002F537.36&quot; \\\n  -H &quot;Accept-Language: en-US,en;q=0.9&quot; \\\n  &quot;https:\u002F\u002Fwww.google.com\u002Fsearch?q=coffee+shop&amp;gl=us&amp;hl=en&amp;uule=w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM=&amp;pws=0&amp;num=100&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>2. ProxyHat Helper-Klasse (SDK-Stil) und curl_cffi mit Chrome-Impersonation\u003C\u002Fh3>\n\u003Cp>Für produktive Systeme sollten Sie den Proxy-URL-Bau kapseln. Hier eine Lightweight-Helper-Klasse, die als Mini-SDK fungiert, kombiniert mit \u003Ccode>curl_cffi\u003C\u002Fcode> für TLS-Fingerprint-Impersonation:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># pip install curl_cffi selectolax\n\nfrom curl_cffi import requests as cffi_requests\nfrom dataclasses import dataclass\nimport base64\nimport logging\nimport random\nimport time\n\nlogging.basicConfig(level=logging.INFO, format=&quot;%(asctime)s [%(levelname)s] %(message)s&quot;)\nlogger = logging.getLogger(&quot;serp_scraper&quot;)\n\n# --- ProxyHat Mini-SDK ---\n\nclass ProxyHat:\n    &quot;&quot;&quot;Lightweight ProxyHat SDK für Geo-Targeted SERP Scraping.&quot;&quot;&quot;\n    GATEWAY = &quot;gate.proxyhat.com&quot;\n    HTTP_PORT = 8080\n    SOCKS5_PORT = 1080\n\n    def __init__(self, username: str, password: str):\n        self.username = username\n        self.password = password\n\n    def proxy_url(\n        self,\n        country: str | None = None,\n        city: str | None = None,\n        session: str | None = None,\n        protocol: str = &quot;http&quot;,\n    ) -&gt; str:\n        &quot;&quot;&quot;Erzeugt eine Proxy-URL mit Geo- und Session-Flags.&quot;&quot;&quot;\n        parts = [self.username]\n        if country:\n            parts.append(f&quot;country-{country.upper()}&quot;)\n        if city:\n            parts.append(f&quot;city-{city.lower().replace(&apos; &apos;, &apos;&apos;)}&quot;)\n        if session:\n            parts.append(f&quot;sid-{session}&quot;)\n        user = &quot;-&quot;.join(parts)\n        port = self.HTTP_PORT if protocol == &quot;http&quot; else self.SOCKS5_PORT\n        scheme = &quot;http&quot; if protocol == &quot;http&quot; else &quot;socks5&quot;\n        return f&quot;{scheme}:\u002F\u002F{user}:{self.password}@{self.GATEWAY}:{port}&quot;\n\n    def proxies(self, **kwargs) -&gt; dict:\n        &quot;&quot;&quot;Gibt ein proxies-dict für requests\u002Fcurl_cffi zurück.&quot;&quot;&quot;\n        url = self.proxy_url(**kwargs)\n        return {&quot;http&quot;: url, &quot;https&quot;: url}\n\n\n# --- uule-Builder ---\n\ndef build_uule(canonical_name: str) -&gt; str:\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;utf-8&quot;)\n    length_key = chr(len(b64) + 0x40)\n    return f&quot;w+CAIQICI{length_key}{b64}&quot;\n\n\n# --- SERP-Scraper ---\n\n@dataclass\nclass LocaleConfig:\n    country_code: str       # &quot;us&quot;\n    language: str           # &quot;en&quot;\n    canonical_name: str     # &quot;Austin,Texas,United States&quot;\n    proxy_city: str         # &quot;austin&quot;\n    google_domain: str = &quot;www.google.com&quot;\n\n\nLOCALES = [\n    LocaleConfig(&quot;us&quot;, &quot;en&quot;, &quot;Austin,Texas,United States&quot;, &quot;austin&quot;),\n    LocaleConfig(&quot;us&quot;, &quot;en&quot;, &quot;New York,New York,United States&quot;, &quot;newyork&quot;),\n    LocaleConfig(&quot;de&quot;, &quot;de&quot;, &quot;Berlin,Berlin,Germany&quot;, &quot;berlin&quot;),\n    LocaleConfig(&quot;de&quot;, &quot;de&quot;, &quot;München,Bayern,Germany&quot;, &quot;münchen&quot;),\n]\n\n\ndef scrape_serp(query: str, locale: LocaleConfig, ph: ProxyHat) -&gt; str:\n    &quot;&quot;&quot;Sendet einen geo-targeted SERP-Request mit Chrome-Impersonation.&quot;&quot;&quot;\n    uule = build_uule(locale.canonical_name)\n    params = {\n        &quot;q&quot;: query,\n        &quot;gl&quot;: locale.country_code,\n        &quot;hl&quot;: locale.language,\n        &quot;uule&quot;: uule,\n        &quot;pws&quot;: &quot;0&quot;,\n        &quot;num&quot;: &quot;100&quot;,\n    }\n    url = f&quot;https:\u002F\u002F{locale.google_domain}\u002Fsearch&quot;\n\n    proxies = ph.proxies(\n        country=locale.country_code,\n        city=locale.proxy_city,\n    )\n\n    resp = cffi_requests.get(\n        url,\n        params=params,\n        proxies=proxies,\n        impersonate=&quot;chrome&quot;,\n        timeout=30,\n    )\n    logger.info(\n        f&quot;[{locale.canonical_name}] status={resp.status_code} &quot;\n        f&quot;bytes={len(resp.text)} ip_session=rotating&quot;\n    )\n    resp.raise_for_status()\n    return resp.text\n\n\n# --- Main ---\nif __name__ == &quot;__main__&quot;:\n    ph = ProxyHat(&quot;user&quot;, &quot;your_password&quot;)\n    for locale in LOCALES:\n        try:\n            html = scrape_serp(&quot;best coffee shop&quot;, locale, ph)\n            with open(f&quot;serp_{locale.proxy_city}.html&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as f:\n                f.write(html)\n        except Exception as e:\n            logger.error(f&quot;Fehler für {locale.proxy_city}: {e}&quot;)\n        time.sleep(random.uniform(1.5, 3.5))  # Rate-Limiting\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>Raw-Proxy-Alternative ohne Helper-Klasse: Statt der \u003Ccode>ProxyHat\u003C\u002Fcode>-Klasse können Sie die Proxy-URL auch direkt konstruieren:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># Direkte Proxy-URL (ohne SDK-Helper)\nproxy = &quot;http:\u002F\u002Fuser-country-US-region-texas-city-austin:PASS@gate.proxyhat.com:8080&quot;\nresp = cffi_requests.get(url, params=params, proxies={&quot;http&quot;: proxy, &quot;https&quot;: proxy}, impersonate=&quot;chrome&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>3. Organic Results und Local Pack parsen mit selectolax\u003C\u002Fh3>\n\u003Cp>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:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>from selectolax.parser import HTMLParser\nfrom dataclasses import dataclass, asdict\nimport json\n\n@dataclass\nclass OrganicResult:\n    position: int\n    title: str\n    url: str\n    snippet: str\n\n@dataclass\nclass LocalPackEntry:\n    name: str\n    rating: float | None\n    reviews: int | None\n    address: str | None\n    phone: str | None\n\n\ndef parse_organic(html: str) -&gt; list[OrganicResult]:\n    &quot;&quot;&quot;Parst organische Suchergebnisse.&quot;&quot;&quot;\n    tree = HTMLParser(html)\n    results = []\n    pos = 0\n    for node in tree.css(&quot;div.g div.tF2Cxc&quot;):\n        pos += 1\n        title_el = node.css_first(&quot;h3&quot;)\n        link_el = node.css_first(&quot;a[href]&quot;)\n        snippet_el = node.css_first(&quot;div[data-sncf], div.VwiC3b, span.aCOpRe&quot;)\n        title = title_el.text(strip=True) if title_el else &quot;&quot;\n        url = link_el.attributes.get(&quot;href&quot;, &quot;&quot;) if link_el else &quot;&quot;\n        snippet = snippet_el.text(strip=True) if snippet_el else &quot;&quot;\n        if title and url:\n            results.append(OrganicResult(pos, title, url, snippet))\n    return results\n\n\ndef parse_local_pack(html: str) -&gt; list[LocalPackEntry]:\n    &quot;&quot;&quot;Parst das Local Pack (Google Maps Results).&quot;&quot;&quot;\n    tree = HTMLParser(html)\n    entries = []\n    # Local Pack Container — Selektor kann variieren\n    for card in tree.css(&quot;div[data-cid] div.SW5HFd, div.rllt__details&quot;):\n        name_el = card.css_first(&quot;div.dbg0p, span.O3ErS&quot;)\n        rating_el = card.css_first(&quot;span.MV3lbe, span[role=&apos;img&apos;]&quot;)\n        name = name_el.text(strip=True) if name_el else &quot;&quot;\n        rating = None\n        if rating_el:\n            r = rating_el.attributes.get(&quot;aria-label&quot;, &quot;&quot;)\n            if &quot;star&quot; in r.lower():\n                try:\n                    rating = float(r.split()[0].replace(&quot;,&quot;, &quot;.&quot;))\n                except (ValueError, IndexError):\n                    pass\n        entries.append(LocalPackEntry(name, rating, None, None, None))\n    return entries\n\n\n# --- Usage ---\nif __name__ == &quot;__main__&quot;:\n    with open(&quot;serp_austin.html&quot;, &quot;r&quot;, encoding=&quot;utf-8&quot;) as f:\n        html = f.read()\n\n    organic = parse_organic(html)\n    local = parse_local_pack(html)\n\n    print(f&quot;=== Organic Results ({len(organic)}) ===&quot;)\n    for r in organic[:5]:\n        print(f&quot;{r.position}. {r.title} — {r.url}&quot;)\n\n    print(f&quot;\\n=== Local Pack ({len(local)}) ===&quot;)\n    for e in local[:3]:\n        print(f&quot;{e.name} (Rating: {e.rating})&quot;)\n\n    # Als JSON exportieren\n    output = {\n        &quot;organic&quot;: [asdict(r) for r in organic],\n        &quot;local_pack&quot;: [asdict(e) for e in local],\n    }\n    with open(&quot;serp_austin_parsed.json&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as f:\n        json.dump(output, f, ensure_ascii=False, indent=2)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>4. Sticky Sessions für Multi-Page-SERPs\u003C\u002Fh3>\n\u003Cp>Wenn Sie mehrere Seiten derselben Suchanfrage abrufen (z.B. Ergebnisse 1–100 über \u003Ccode>start=0\u003C\u002Fcode>, \u003Ccode>start=10\u003C\u002Fcode>, \u003Ccode>start=20\u003C\u002Fcode>), muss dieselbe IP verwendet werden — sonst kann Google unterschiedliche Personalisierungen pro Seite anwenden. ProxyHat unterstützt Sticky Sessions über das \u003Ccode>session\u003C\u002Fcode>-Flag im Usernamen:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import random\nimport string\nfrom curl_cffi import requests as cffi_requests\n\ndef scrape_multi_page(query: str, locale: LocaleConfig, ph: ProxyHat, pages: int = 5):\n    &quot;&quot;&quot;\n    Ruft mehrere SERP-Seiten ab mit derselben IP (Sticky Session).\n    Die Session-ID hält die IP für die Dauer der Session stabil.\n    &quot;&quot;&quot;\n    session_id = &quot;serp_&quot; + &quot;&quot;.join(random.choices(string.ascii_lowercase + string.digits, k=8))\n    uule = build_uule(locale.canonical_name)\n    all_results = []\n\n    for page in range(pages):\n        start = page * 10\n        params = {\n            &quot;q&quot;: query,\n            &quot;gl&quot;: locale.country_code,\n            &quot;hl&quot;: locale.language,\n            &quot;uule&quot;: uule,\n            &quot;pws&quot;: &quot;0&quot;,\n            &quot;num&quot;: &quot;10&quot;,\n            &quot;start&quot;: str(start),\n        }\n        url = f&quot;https:\u002F\u002F{locale.google_domain}\u002Fsearch&quot;\n\n        # Sticky Session: dieselbe session_id -&gt; dieselbe IP\n        proxies = ph.proxies(\n            country=locale.country_code,\n            city=locale.proxy_city,\n            session=session_id,\n        )\n\n        try:\n            resp = cffi_requests.get(\n                url,\n                params=params,\n                proxies=proxies,\n                impersonate=&quot;chrome&quot;,\n                timeout=30,\n            )\n            logger.info(\n                f&quot;Page {page+1}\u002F{pages} | start={start} | &quot;\n                f&quot;status={resp.status_code} | session={session_id}&quot;\n            )\n            resp.raise_for_status()\n            results = parse_organic(resp.text)\n            all_results.extend(results)\n        except Exception as e:\n            logger.error(f&quot;Page {page+1} fehlgeschlagen: {e}&quot;)\n            break\n\n        time.sleep(random.uniform(2.0, 4.0))\n\n    return all_results\n\n# Beispielaufruf\nph = ProxyHat(&quot;user&quot;, &quot;your_password&quot;)\nlocale = LocaleConfig(&quot;us&quot;, &quot;en&quot;, &quot;Austin,Texas,United States&quot;, &quot;austin&quot;)\nresults = scrape_multi_page(&quot;plumber&quot;, locale, ph, pages=5)\nprint(f&quot;Insgesamt {len(results)} organische Ergebnisse über 5 Seiten&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>5. Retry\u002FBackoff mit per-Country Proxy-Pools und CAPTCHA-Erkennung\u003C\u002Fh3>\n\u003Cp>Google antwortet auf verdächtiges Scraping-Verhalten mit HTTP 429 (Too Many Requests), CAPTCHAs oder 302-Redirects auf \u003Ccode>sorry.google.com\u003C\u002Fcode>. Ein robuster Scraper braucht Exponential Backoff, CAPTCHA-Erkennung und separate Proxy-Pools pro Land:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import time\nimport random\nfrom curl_cffi import requests as cffi_requests\nfrom dataclasses import dataclass\n\n@dataclass\nclass ScrapeResult:\n    success: bool\n    html: str | None\n    status_code: int\n    error: str | None\n\n\nclass SERPScraper:\n    &quot;&quot;&quot;Robuster SERP-Scraper mit Retry, Backoff und CAPTCHA-Erkennung.&quot;&quot;&quot;\n\n    MAX_RETRIES = 4\n    BASE_DELAY = 3.0  # Sekunden\n    MAX_DELAY = 60.0\n\n    def __init__(self, ph: ProxyHat):\n        self.ph = ph\n\n    def _is_captcha(self, html: str) -&gt; bool:\n        markers = [&quot;sorry.google.com&quot;, &quot;g-recaptcha&quot;, &quot;unusual traffic&quot;, &quot;CAPTCHA&quot;]\n        return any(m in html for m in markers)\n\n    def _backoff(self, attempt: int) -&gt; float:\n        delay = min(self.BASE_DELAY * (2 ** attempt) + random.uniform(0, 1), self.MAX_DELAY)\n        return delay\n\n    def scrape(\n        self,\n        query: str,\n        locale: LocaleConfig,\n        session: str | None = None,\n    ) -&gt; ScrapeResult:\n        &quot;&quot;&quot;\n        Sendet einen SERP-Request mit Retry-Logik.\n        Rotiert bei 429\u002FCAPTCHA automatisch auf eine neue IP\n        (neue Session-ID = neue IP aus demselben Geo-Pool).\n        &quot;&quot;&quot;\n        uule = build_uule(locale.canonical_name)\n        url = f&quot;https:\u002F\u002F{locale.google_domain}\u002Fsearch&quot;\n        params = {\n            &quot;q&quot;: query,\n            &quot;gl&quot;: locale.country_code,\n            &quot;hl&quot;: locale.language,\n            &quot;uule&quot;: uule,\n            &quot;pws&quot;: &quot;0&quot;,\n            &quot;num&quot;: &quot;100&quot;,\n        }\n\n        for attempt in range(self.MAX_RETRIES):\n            # Bei Retry: neue Session-ID für neue IP aus demselben City-Pool\n            current_session = session if session else f&quot;retry_{attempt}_{random.randint(1000,9999)}&quot;\n            proxies = self.ph.proxies(\n                country=locale.country_code,\n                city=locale.proxy_city,\n                session=current_session,\n            )\n\n            try:\n                resp = cffi_requests.get(\n                    url,\n                    params=params,\n                    proxies=proxies,\n                    impersonate=&quot;chrome&quot;,\n                    timeout=30,\n                )\n\n                # CAPTCHA-Erkennung\n                if resp.status_code == 200 and self._is_captcha(resp.text):\n                    delay = self._backoff(attempt)\n                    logger.warning(\n                        f&quot;CAPTCHA erkannt für {locale.proxy_city} | &quot;\n                        f&quot;attempt={attempt+1}\u002F{self.MAX_RETRIES} | &quot;\n                        f&quot;backoff={delay:.1f}s&quot;\n                    )\n                    time.sleep(delay)\n                    continue\n\n                # Rate Limiting\n                if resp.status_code == 429:\n                    delay = self._backoff(attempt)\n                    logger.warning(\n                        f&quot;HTTP 429 für {locale.proxy_city} | &quot;\n                        f&quot;attempt={attempt+1}\u002F{self.MAX_RETRIES} | &quot;\n                        f&quot;backoff={delay:.1f}s&quot;\n                    )\n                    time.sleep(delay)\n                    continue\n\n                resp.raise_for_status()\n                logger.info(\n                    f&quot;Erfolg: {locale.proxy_city} | &quot;\n                    f&quot;status={resp.status_code} | &quot;\n                    f&quot;bytes={len(resp.text)} | &quot;\n                    f&quot;attempt={attempt+1}&quot;\n                )\n                return ScrapeResult(True, resp.text, resp.status_code, None)\n\n            except cffi_requests.RequestsError as e:\n                delay = self._backoff(attempt)\n                logger.error(\n                    f&quot;Request-Fehler für {locale.proxy_city}: {e} | &quot;\n                    f&quot;backoff={delay:.1f}s&quot;\n                )\n                time.sleep(delay)\n\n        return ScrapeResult(False, None, 0, &quot;Max retries exceeded&quot;)\n\n\n# --- Multi-Locale Scraping mit Per-Country Pools ---\nif __name__ == &quot;__main__&quot;:\n    ph = ProxyHat(&quot;user&quot;, &quot;your_password&quot;)\n    scraper = SERPScraper(ph)\n\n    queries = [&quot;dentist&quot;, &quot;electrician&quot;, &quot;roofing contractor&quot;]\n    locales = [\n        LocaleConfig(&quot;us&quot;, &quot;en&quot;, &quot;Austin,Texas,United States&quot;, &quot;austin&quot;),\n        LocaleConfig(&quot;us&quot;, &quot;en&quot;, &quot;New York,New York,United States&quot;, &quot;newyork&quot;),\n        LocaleConfig(&quot;de&quot;, &quot;de&quot;, &quot;Berlin,Berlin,Germany&quot;, &quot;berlin&quot;),\n    ]\n\n    for locale in locales:\n        for query in queries:\n            result = scraper.scrape(query, locale)\n            if result.success:\n                organic = parse_organic(result.html)\n                local_pack = parse_local_pack(result.html)\n                logger.info(\n                    f&quot;{locale.proxy_city} | q=&apos;{query}&apos; | &quot;\n                    f&quot;organic={len(organic)} | local_pack={len(local_pack)}&quot;\n                )\n            else:\n                logger.error(f&quot;{locale.proxy_city} | q=&apos;{query}&apos; | FAILED: {result.error}&quot;)\n            time.sleep(random.uniform(2.0, 5.0))\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Häufige Fehler und Edge Cases\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Parameter-Mismatch: \u003Ccode>gl=us\u003C\u002Fcode> mit \u003Ccode>hl=de\u003C\u002Fcode> und einer deutschen IP führt zu unvorhersehbaren Ergebnissen. \u003Ccode>gl\u003C\u002Fcode>, \u003Ccode>hl\u003C\u002Fcode> und Proxy-Land sollten konsistent sein.\u003C\u002Fli>\n\u003Cli>uule ohne passende IP: \u003Ccode>uule\u003C\u002Fcode> 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.\u003C\u002Fli>\n\u003Cli>Vergessenes \u003Ccode>pws=0\u003C\u002Fcode>: Ohne \u003Ccode>pws=0\u003C\u002Fcode> personalisiert Google Ergebnisse basierend auf Cookies und Suchverlauf — selbst bei Inprivate-Requests können personalisierte SERPs zurückkommen, wenn Google den Fingerprint assoziiert.\u003C\u002Fli>\n\u003Cli>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\u002FSekunde mit zufälligen Delays ist sicherer.\u003C\u002Fli>\n\u003Cli>Veraltete CSS-Selektoren: Google ändert HTML-Klassen regelmäßig. Testen Sie Parser gegen aktuelle SERP-HTML-Snippets und implementieren Sie Fallback-Selektoren.\u003C\u002Fli>\n\u003Cli>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.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>ProxyHat-spezifische Einrichtung\u003C\u002Fh2>\n\u003Cp>ProxyHat macht Geo-Targeting einfach: Alle Parameter werden im Usernamen codiert. Für US Geo-Targeted SERP Scraping Best Practices verwenden Sie das Format \u003Ccode>user-country-US-region-{region}-city-{city}:pass\u003C\u002Fcode>. Die vollständige Dokumentation aller Parameter finden Sie unter \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">docs.proxyhat.com\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>Die wichtigsten Konfigurationen für SERP-Scraping:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Rotierende IPs (Standard): Jeder Request erhält eine neue IP — ideal für breite SERP-Erfassung.\u003C\u002Fli>\n\u003Cli>Sticky Sessions: \u003Ccode>sid-{id}\u003C\u002Fcode> hält die IP stabil — notwendig für Multi-Page-SERPs.\u003C\u002Fli>\n\u003Cli>City-Level-Targeting: \u003Ccode>city-{name}\u003C\u002Fcode> — kombiniert mit \u003Ccode>uule\u003C\u002Fcode> für maximale Präzision beim Local SERP Scraping by City.\u003C\u002Fli>\n\u003Cli>SOCKS5: Für Anwendungen, die SOCKS5 benötigen, verwenden Sie Port \u003Ccode>1080\u003C\u002Fcode> statt \u003Ccode>8080\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Preise und verfügbare Standorte finden Sie auf der \u003Ca href=\"\u002Fde\u002Fpricing\">Preisseite\u003C\u002Fa> und der \u003Ca href=\"\u002Fde\u002Flocations\">Standortübersicht\u003C\u002Fa>. Weitere Use Cases für Web-Scraping und SERP-Tracking finden Sie unter \u003Ca href=\"\u002Fde\u002Fuse-cases\u002Fweb-scraping\">Web-Scraping\u003C\u002Fa> und \u003Ca href=\"\u002Fde\u002Fuse-cases\u002Fserp-tracking\">SERP-Tracking\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Rechtliche Hinweise: TOS und öffentliche Daten\u003C\u002Fh2>\n\u003Cp>Das Scraping von Google-SERPs bewegt sich in einer rechtlichen Grauzone. Googles \u003Ca href=\"https:\u002F\u002Fwww.google.com\u002Fintl\u002Fen\u002Fpolicies\u002Fterms\u002F\" rel=\"noopener noreferrer\">Nutzungsbedingungen\u003C\u002Fa> verbieten automatisierte Abfragen. In der Praxis scrapen viele SEO-Tools SERP-Daten, aber Sie sollten:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Rate-Limits respektieren und menschenähnliche Request-Muster verwenden.\u003C\u002Fli>\n\u003Cli>\u003Ccode>robots.txt\u003C\u002Fcode> prüfen — Google erlaubt bestimmte Pfade nicht.\u003C\u002Fli>\n\u003Cli>DSGVO\u002FGDPR beachten, wenn personenbezogene Daten (z.B. aus Local Packs) gespeichert werden.\u003C\u002Fli>\n\u003Cli>Eine rechtliche Beratung einholen, bevor Sie kommerzielle SERP-Datensets verkaufen.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cblockquote>\n\u003Cp>Wichtig: Dieser Artikel beschreibt technische Methoden für Entwickler. Die Einhaltung der Nutzungsbedingungen Dritter und geltender Gesetze liegt in Ihrer Verantwortung.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\n\u003Ch2>Key Takeaways\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Stellen Sie \u003Ccode>gl\u003C\u002Fcode>, \u003Ccode>hl\u003C\u002Fcode> und \u003Ccode>uule\u003C\u002Fcode> konsistent ein und kombinieren Sie sie mit \u003Ccode>pws=0\u003C\u002Fcode> für reproduzierbare, nicht-personalisierte SERPs.\u003C\u002Fli>\n\u003Cli>City-Level-Targeting erfordert \u003Ccode>uule\u003C\u002Fcode> + passende IP: Google gleicht URL-Parameter mit der IP-Geographie ab. Verwenden Sie Residential Proxies aus derselben Stadt.\u003C\u002Fli>\n\u003Cli>Sticky Sessions für Multi-Page-SERPs: Verwenden Sie \u003Ccode>sid-{id}\u003C\u002Fcode> im ProxyHat-Usernamen, um dieselbe IP über mehrere Seiten zu halten.\u003C\u002Fli>\n\u003Cli>Implementieren Sie Exponential Backoff und CAPTCHA-Erkennung: HTTP 429 und CAPTCHA-Redirects sind normal — ein robuster Scraper rotiert die IP und wartet mit Backoff.\u003C\u002Fli>\n\u003Cli>Chrome-Impersonation via \u003Ccode>curl_cffi\u003C\u002Fcode> reduziert TLS-Fingerprinting-Risiken erheblich gegenüber Standard \u003Ccode>requests\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Halten Sie Parser aktuell: Google ändert HTML-Klassen regelmäßig. Testen Sie gegen aktuelle SERP-HTML-Snippets.\u003C\u002Fli>\n\u003C\u002Ful>","Best Practices: Geo-Targeted SERP Scraping | ProxyHat","Best Practices für Geo-Targeted SERP Scraping: uule, gl, hl korrekt setzen, City-Level-Targeting mit Residential Proxies von ProxyHat umsetzen und Blöcke vermeiden.","\u002Fde\u002Fblog\u002Fgeo-targeted-serp-scraping-leitfaden",null,"Geo-Targeted SERP Scraping Best Practices | ProxyHat","Best Practices für Geo-Targeted SERP Scraping: uule, gl, hl korrekt setzen, City-Level-Targeting mit Residential Proxies von ProxyHat umsetzen.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgeo-targeted-serp-scraping-leitfaden-og.webp",[19,22,25],{"question":20,"answer":21},"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-region-texas-city-austin:pass. Datacenter-Proxies können für Tests funktionieren, haben aber eine deutlich höhere Block-Wahrscheinlichkeit.",{"question":23,"answer":24},"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\u002FSekunde pro Proxy-Pool). Verwenden Sie Sticky Sessions für Multi-Page-Abfragen, um IP-Wechsel innerhalb einer Suchanfrage zu vermeiden.",{"question":26,"answer":27},"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.",false,"2026-07-31T16:11:16+00:00","2026-10-03T23:52:59+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgeo-targeted-serp-scraping-leitfaden-master.webp","Geo-Targeted SERP Scraping Best Practices for Local SEO Data","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgeo-targeted-serp-scraping-leitfaden-card.webp",12,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[40],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},3,"serp-und-seo","SERP & SEO","SERP & SEO Anleitungen | ProxyHat Blog","Suchmaschinen-Rankings verfolgen und SERPs mit Proxies scrapen.",[],{"en":48,"x-default":48},"\u002Fblog\u002Fgeo-targeted-serp-scraping-best-practices",{"zh":50,"ja":51,"pl":52,"es":53,"it":54,"tr":55,"ko":56,"en":48,"ru":57,"de":13,"fr":58,"pt":59},"\u002Fcn\u002Fblog\u002Fserp-dili-dingwei-zhuaqu-zhinan","\u002Fja\u002Fblog\u002Fgeo-targeted-serp-scraping-guide","\u002Fpl\u002Fblog\u002Fgeotargetowane-scrapowanie-serp-najlepsze-praktyki","\u002Fes\u002Fblog\u002Fscraping-serp-geo-segmentado-mejores-practicas","\u002Fit\u002Fblog\u002Fscraping-serp-geo-targetato-best-practices","\u002Ftr\u002Fblog\u002Fcografi-hedefli-serp-kazima-rehberi","\u002Fko\u002Fblog\u002Fgeo-targeted-serp-scraping-guide","\u002Fru\u002Fblog\u002Fgeo-targeted-serp-scraping-best-practices","\u002Ffr\u002Fblog\u002Fscraping-serp-geocible-meilleures-pratiques","\u002Fpt\u002Fblog\u002Fpraticas-serp-scraping-geo-targeted",59,[62,79,95,112],{"id":63,"slug":64,"title":65,"excerpt":66,"featured_image_url":67,"featured_image_alt":68,"card_image_url":69,"og_image_url":70,"published_at":71,"updated_at":71,"content_updated_at":72,"reading_time_minutes":73,"is_featured":28,"indexable":28,"views":74,"author":75,"categories":76,"tags":78},155,"amazon-keyword-rank-tracking-mit-proxies","Amazon Keyword Rank Tracking mit Proxies: Entwickler-Leitfaden","Praktischer Leitfaden für Amazon Keyword Rank Tracking mit Proxies: Parsing der Amazon-SERP, Geo-Targeting, Python-Beispiele mit curl_cffi und ProxyHat sowie Produktionstipps für zuverlässiges Rank-Tracking.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Famazon-keyword-rank-tracking-mit-proxies-master.webp","Amazon Keyword Rank Tracking with Proxies: A Developer's Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Famazon-keyword-rank-tracking-mit-proxies-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Famazon-keyword-rank-tracking-mit-proxies-og.webp","2026-07-16T16:05:31+00:00","2026-10-04T01:29:51+00:00",13,98,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[77],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":80,"slug":81,"title":82,"excerpt":83,"featured_image_url":84,"featured_image_alt":85,"card_image_url":86,"og_image_url":87,"published_at":88,"updated_at":88,"content_updated_at":89,"reading_time_minutes":34,"is_featured":28,"indexable":28,"views":90,"author":91,"categories":92,"tags":94},153,"people-also-ask-autocomplete-scrapen","Google People Also Ask und Autocomplete für die Keyword-Recherche scrapen – Python-Leitfaden","Praktischer Leitfaden zum Scrapen von Google Autocomplete, People Also Ask und Related Searches mit Python, httpx und Playwright – inklusive ProxyHat-Setup, Dedup-Logik und CSV-Export für die Keyword-Recherche.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fpeople-also-ask-autocomplete-scrapen-master.webp","Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fpeople-also-ask-autocomplete-scrapen-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fpeople-also-ask-autocomplete-scrapen-og.webp","2026-07-14T16:06:25+00:00","2026-10-03T08:29:54+00:00",124,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[93],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":96,"slug":97,"title":98,"excerpt":99,"featured_image_url":100,"featured_image_alt":101,"card_image_url":102,"og_image_url":103,"published_at":104,"updated_at":104,"content_updated_at":105,"reading_time_minutes":106,"is_featured":28,"indexable":28,"views":107,"author":108,"categories":109,"tags":111},154,"marke-google-ai-overviews-verfolgen","Marke in Google AI Overviews verfolgen: Strategischer Leitfaden für SEO-Teams","Generative Suche verändert alles: Erfahren Sie, wie Sie Ihre Marke in Google AI Overviews verfolgen — mit Citation-Share-Analyse, Build-vs-Buy-Vergleich und einem ProxyHat-gestützten Messprogramm.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fmarke-google-ai-overviews-verfolgen-master.webp","How to Track Your Brand in Google AI Overviews: A Strategic Guide for SEO & Data Teams","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fmarke-google-ai-overviews-verfolgen-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fmarke-google-ai-overviews-verfolgen-og.webp","2026-07-14T10:05:37+00:00","2026-10-03T08:29:51+00:00",10,66,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[110],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":113,"slug":114,"title":115,"excerpt":116,"featured_image_url":117,"featured_image_alt":118,"card_image_url":119,"og_image_url":120,"published_at":121,"updated_at":121,"content_updated_at":122,"reading_time_minutes":34,"is_featured":28,"indexable":28,"views":123,"author":124,"categories":125,"tags":127},152,"google-rank-tracker-python-bauen","Google Rank Tracker in Python mit Residential Proxies bauen – Praxis-Leitfaden 2026","Schritt-für-Schritt-Anleitung zum Bau eines produktionsreifen Google-Rank-Trackers in Python: SERP-Paginierung, TLS-Fingerprinting, Residential Proxies, SQLite-Historie und Production-Hardening inklusive.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgoogle-rank-tracker-python-bauen-master.webp","Build a Google Rank Tracker in Python with Residential Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgoogle-rank-tracker-python-bauen-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fde\u002Fgoogle-rank-tracker-python-bauen-og.webp","2026-07-02T16:04:58+00:00","2026-10-03T08:57:46+00:00",56,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[126],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],[]]