Wer Menüpreise und Liefergebühren über mehrere Plattformen hinweg vergleicht, kommt an reCAPTCHA und Cloudflare Turnstile nicht vorbei. Der Ablauf, der trotzdem verlässlich Daten liefert, ist immer derselbe: Jede blockierte Anfrage geht an einen CAPTCHA-Lösungsdienst, das zurückgelieferte Token landet wieder im Request, und der Parser liest anschließend Preise, Gebühren und Lieferzeiten aus. Genau dafür ist dieser Leitfaden gedacht – für Preisvergleichsdienste, Marktforschung und Restaurant-Analytics, die DoorDash, Uber Eats, Grubhub und im DACH-Raum auch Lieferando oder Wolt strukturiert auswerten wollen.
Welche CAPTCHAs die Lieferdienste schützen
Lieferplattformen schirmen ihre Preisdaten mit unterschiedlichen Abfragetypen ab. Wer weiß, was wo auftaucht, wählt von vornherein den richtigen Lösungsweg.
| Plattform | CAPTCHA-Typ | Auslöser | Geschützte Daten |
|---|---|---|---|
| DoorDash | reCAPTCHA v3 + Cloudflare | Bot-Erkennung | Menüs, Preise, Gebühren |
| Uber Eats | Cloudflare Turnstile | Automatisierter Zugriff | Restauranteinträge, Preise |
| Grubhub | reCAPTCHA v2 | Rate-Limiting | Menüpunkte, Aktionen |
| Postmates | Cloudflare Challenge | Scraping-Erkennung | Liefergebühren, Lieferzeiten |
| Just Eat | reCAPTCHA v2 | Wiederholte Suchen | Restaurantdaten |
| Instacart | reCAPTCHA v3 | Bot-Erkennung | Lebensmittelpreise |
CaptchaAI deckt genau diese Familien ab: reCAPTCHA v2 und v3, Cloudflare Turnstile und Cloudflare Challenge. hCaptcha und FunCaptcha gehören nicht dazu – sollte eine Plattform darauf umstellen, greift dieser Workflow nicht.
Welche Preisdaten sich zu erfassen lohnen
Bevor Sie das erste Skript starten, lohnt sich die Frage, welche Felder überhaupt einen Geschäftswert haben. Das hält den Datensatz schlank und den Traffic niedrig.
| Kennzahl | Geschäftswert |
|---|---|
| Preise einzelner Menüpunkte | Preisparität und Aufschlagsanalyse |
| Liefergebühren | Vergleich der Plattformgebühren |
| Mindestbestellwerte | Analyse der Zugangsbarrieren |
| Geschätzte Lieferzeiten | Service-Level-Vergleich |
| Aktionen und Rabatte | Marketing-Intelligence |
| Restaurant-Verfügbarkeit | Abdeckungsanalyse |
Vergleichsskript für mehrere Plattformen
Das folgende Beispiel bündelt Suche, Menüabruf und CAPTCHA-Behandlung in einer Klasse. Erkennt der Code eine Abfrage, übermittelt er Sitekey und Page-URL an CaptchaAI, fügt das Token in den Folge-Request ein und liest die Seite danach normal aus.
import requests
import time
import re
from bs4 import BeautifulSoup
import json
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_captcha(method, sitekey, pageurl, **kwargs):
data = {
"key": CAPTCHAAI_KEY, "method": method,
"googlekey": sitekey, "pageurl": pageurl, "json": 1,
}
data.update(kwargs)
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
r = result.json()
if r["request"] != "CAPCHA_NOT_READY":
return r["request"]
raise TimeoutError("Timeout")
class FoodDeliveryComparator:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 "
"Mobile/15E148 Safari/604.1",
"Accept-Language": "en-US,en;q=0.9",
})
def search_restaurants(self, platform_url, location, cuisine=None):
"""Search restaurants on a delivery platform."""
params = {"address": location}
if cuisine:
params["cuisine"] = cuisine
url = f"{platform_url}/search"
resp = self.session.get(url, params=params, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, url)
return self._parse_restaurants(resp.text)
def get_menu(self, restaurant_url):
"""Get menu with prices from a specific restaurant."""
resp = self.session.get(restaurant_url, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, restaurant_url)
return self._parse_menu(resp.text)
def compare_restaurant_across_platforms(self, restaurant_name, platforms, location):
"""Compare same restaurant's pricing across delivery platforms."""
results = []
for platform in platforms:
try:
restaurants = self.search_restaurants(
platform["url"], location,
)
# Find matching restaurant
match = None
for r in restaurants:
if restaurant_name.lower() in r["name"].lower():
match = r
break
if match and match.get("url"):
menu = self.get_menu(match["url"])
results.append({
"platform": platform["name"],
"restaurant": match["name"],
"delivery_fee": match.get("delivery_fee", ""),
"delivery_time": match.get("delivery_time", ""),
"menu_items": len(menu),
"sample_prices": menu[:5],
})
else:
results.append({
"platform": platform["name"],
"restaurant": restaurant_name,
"status": "not found",
})
except Exception as e:
results.append({
"platform": platform["name"],
"error": str(e),
})
time.sleep(5)
return results
def track_delivery_fees(self, platforms, location, output_file):
"""Track delivery fees across platforms for analysis."""
all_data = []
for platform in platforms:
try:
restaurants = self.search_restaurants(
platform["url"], location,
)
for r in restaurants[:20]: # Top 20 per platform
all_data.append({
"platform": platform["name"],
"restaurant": r["name"],
"delivery_fee": r.get("delivery_fee", ""),
"delivery_time": r.get("delivery_time", ""),
"rating": r.get("rating", ""),
})
time.sleep(5)
except Exception as e:
print(f"Error on {platform['name']}: {e}")
with open(output_file, "w") as f:
json.dump(all_data, f, indent=2)
return all_data
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile',
'challenge-platform',
])
def _solve_and_retry(self, html, url):
match = re.search(r'data-sitekey="([^"]+)"', html)
if not match:
return self.session.get(url)
sitekey = match.group(1)
if 'cf-turnstile' in html:
token = solve_captcha("turnstile", sitekey, url)
return self.session.post(url, data={"cf-turnstile-response": token})
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _parse_restaurants(self, html):
soup = BeautifulSoup(html, "html.parser")
restaurants = []
for card in soup.select(".restaurant-card, .store-card, .merchant"):
name_el = card.select_one(".name, .store-name, h3")
if name_el:
restaurants.append({
"name": name_el.get_text(strip=True),
"url": self._link(card),
"delivery_fee": self._text(card, ".delivery-fee, .fee"),
"delivery_time": self._text(card, ".delivery-time, .eta"),
"rating": self._text(card, ".rating, .stars"),
})
return restaurants
def _parse_menu(self, html):
soup = BeautifulSoup(html, "html.parser")
items = []
for item in soup.select(".menu-item, .item-card"):
items.append({
"name": self._text(item, ".item-name, .name"),
"price": self._text(item, ".price, .item-price"),
"description": self._text(item, ".description, .item-desc"),
})
return items
def _text(self, el, selector):
found = el.select_one(selector)
return found.get_text(strip=True) if found else ""
def _link(self, card):
a = card.select_one("a")
return a.get("href", "") if a else ""
# Usage
comparator = FoodDeliveryComparator(
proxy="http://user:pass@mobile.proxy.com:5000"
)
# Compare platforms
platforms = [
{"name": "Platform A", "url": "https://delivery-a.example.com"},
{"name": "Platform B", "url": "https://delivery-b.example.com"},
{"name": "Platform C", "url": "https://delivery-c.example.com"},
]
comparison = comparator.compare_restaurant_across_platforms(
restaurant_name="Pizza Palace",
platforms=platforms,
location="10001",
)
for result in comparison:
print(f"{result.get('platform')}: Fee={result.get('delivery_fee')} "
f"ETA={result.get('delivery_time')}")
Ein Hinweis zur Rechtslage: Öffentliche Menüpreise sind das eine, personenbezogene Daten das andere. IP-Adressen und Standortangaben gelten nach DSGVO als personenbezogen. Prüfen Sie vor produktivem Einsatz Ihre Rechtsgrundlage und beschränken Sie die Erfassung auf öffentlich zugängliche Preis- und Gebührendaten.
Proxy-Wahl je Plattform
Lieferdienste sind konsequent „Mobile First" aufgebaut. Ein mobiler Proxy in Kombination mit einem mobilen User-Agent erzeugt daher den realistischsten Datenverkehr und reduziert die Zahl der ausgelösten Abfragen spürbar.
| Plattform | Empfohlener Proxy | Grund |
|---|---|---|
| DoorDash | Mobil (4G) | Starke Bot-Erkennung, erwartet Mobilgeräte |
| Uber Eats | Mobil (4G) | Mobile-First-Plattform |
| Grubhub | Residential | Standardschutz |
| Instacart | Residential | Mäßige Bot-Erkennung |
| Just Eat | Rotierendes Residential | Standard-Cloudflare |
Threads und Kosten für regelmäßige Vergleiche
CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung – innerhalb eines Tarifs lösen Sie also unbegrenzt viele CAPTCHAs. Für Preisvergleiche entscheidet die gewünschte Parallelität über den Tarif: Wie viele Plattformen und Standorte fragen Sie gleichzeitig ab?
- BASIC (15 $/Monat, 5 Threads) – für gelegentliche Vergleiche einzelner Restaurants über wenige Plattformen.
- STANDARD (30 $/Monat, 15 Threads) – für regelmäßige, parallele Läufe über mehrere Städte.
- ADVANCE (90 $/Monat, 50 Threads) – für tägliche Marktabdeckung mit vielen Plattformen und Standorten.
Alle Preise in US-Dollar. Der Durchsatz hängt zusätzlich von der plattformspezifischen Lösungszeit ab; die aktuellen Tarife finden Sie auf der CaptchaAI-Preisseite.
Typische Fehler beim Scraping von Lieferpreisen
| Problem | Ursache | Lösung |
|---|---|---|
| Leere Restaurantliste | Standort nicht bedient oder CAPTCHA-Seite | Korrekte Postleitzahl der Lieferadresse setzen |
| Menüpreise weichen von der App ab | Unterschied zwischen Web- und App-Preisen | Mobilen User-Agent nutzen, um App-äquivalente Preise zu erhalten |
| Wiederholte Cloudflare-Challenge | Browser-Signale passen nicht zum Proxy | Mobilen Proxy mit mobilem User-Agent kombinieren |
| Restaurant auf einer Plattform vorhanden, auf einer anderen nicht | Unterschiedliche Abdeckung | Im Vergleich als „nicht verfügbar" markieren |
| Falsche Liefergebühren | Standortabhängige Preisgestaltung | Proxy-Region an den Zielstandort anpassen |
Häufige Fragen
Welche CAPTCHA-Typen tauchen bei Lieferplattformen auf?
Überwiegend reCAPTCHA v2 und v3 sowie Cloudflare Turnstile und Cloudflare Challenge. CaptchaAI löst genau diese Typen; hCaptcha und FunCaptcha werden nicht unterstützt.
Ist das Scraping von Lieferpreisen in Deutschland zulässig?
Öffentliche Preisdaten sind grundsätzlich weniger heikel als personenbezogene Daten. Da IP-Adressen und Standortangaben unter die DSGVO fallen, sollten Sie Ihre Rechtsgrundlage vorab prüfen und die Erfassung auf öffentlich einsehbare Menü- und Gebührendaten begrenzen.
Welcher CaptchaAI-Tarif passt zu einem Preisvergleich?
Das hängt an der Parallelität. Für vereinzelte Läufe reicht BASIC (15 $/Monat, 5 Threads), für tägliche Marktabdeckung über viele Plattformen eignet sich ADVANCE (90 $/Monat, 50 Threads). Die Zahl paralleler Anfragen bestimmt den Tarif, nicht die Menge der Lösungen.
Warum unterscheiden sich die Preise zwischen den Plattformen?
Restaurants kalkulieren je Plattform anders, um Provisionssätze von 15–30 % auszugleichen. Auch Liefer- und Servicegebühren variieren – genau das macht den plattformübergreifenden Vergleich überhaupt erst interessant.
Wie verhindere ich, dass mein Vergleichslauf blockiert wird?
Halten Sie das Anfragetempo niedrig und bauen Sie Pausen zwischen den Requests ein – das Skript wartet bewusst fünf Sekunden pro Plattform. Ein mobiler Proxy pro Region, ein passender User-Agent und die Erfassung nur der wirklich benötigten Felder senken die Zahl ausgelöster CAPTCHAs zusätzlich.
Verwandte Leitfäden
- Bestandsüberwachung im Einzelhandel
- Proxy-Authentifizierung für CAPTCHA-Workflows
- Rotierende Residential-Proxys für die CAPTCHA-Lösung
Lieferpreise im großen Maßstab vergleichen – holen Sie sich Ihren CaptchaAI-Schlüssel und automatisieren Sie die plattformübergreifende Analyse.