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-Parameter —
gl(Google-Ländercode),hl(Interface-Sprache),google_domain(z.B.google.devs.google.co.uk) unduule(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 Yorkuser-country-DE-city-berlin:pass— deutsche IP aus Berlinuser-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=usmithl=deund einer deutschen IP führt zu unvorhersehbaren Ergebnissen.gl,hlund Proxy-Land sollten konsistent sein. - uule ohne passende IP:
uulefü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: Ohnepws=0personalisiert 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 mituulefür maximale Präzision beim Local SERP Scraping by City. - SOCKS5: Für Anwendungen, die SOCKS5 benötigen, verwenden Sie Port
1080statt8080.
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.txtprü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,hlunduulekonsistent ein und kombinieren Sie sie mitpws=0fü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_cffireduziert TLS-Fingerprinting-Risiken erheblich gegenüber Standardrequests. - 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.



