Các nền tảng giao đồ ăn bảo vệ dữ liệu về giá của họ bằng CAPTCHA và tính năng phát hiện bot. Các dịch vụ so sánh giá, nhà nghiên cứu thị trường và công cụ phân tích nhà hàng cần quyền truy cập tự động để so sánh giá thực đơn, phí giao hàng và chương trình khuyến mãi trên DoorDash, Uber Eats, Grubhub và các nền tảng khác.
CAPTCHA trên nền tảng phân phối
| Nền tảng | Loại CAPTCHA | Trình kích hoạt | Dữ liệu được bảo vệ |
|---|---|---|---|
| CửaDash | reCAPTCHA v3 + Cloudflare | Phát hiện bot | Thực đơn, giá cả, phí |
| Đồ ăn Uber | Cloudflare Turnstile | Truy cập tự động | Danh sách nhà hàng, giá cả |
| Grubhub | reCAPTCHA v2 | Giới hạn tỷ lệ | Thực đơn, khuyến mãi |
| Bạn cùng phòng | Cloudflare Challenge | Phát hiện cạo | Phí giao hàng, ETA |
| chỉ cần ăn | reCAPTCHA v2 | Tìm kiếm lặp lại | Dữ liệu nhà hàng |
| giỏ hàng tức thời | reCAPTCHA v3 | Phát hiện bot | Giá tạp hóa |
Công cụ so sánh giá đa nền tảng
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')}")
Đề xuất ủy quyền
| Nền tảng | Proxy tốt nhất | tại sao |
|---|---|---|
| CửaDash | Di động (4G) | Phát hiện bot nặng, mong đợi trên thiết bị di động |
| Đồ ăn Uber | Di động (4G) | Nền tảng di động đầu tiên |
| Grubhub | Khu dân cư | Bảo vệ tiêu chuẩn |
| giỏ hàng tức thì | Khu dân cư | Phát hiện bot vừa phải |
| chỉ cần ăn | Khu dân cư xoay vòng | Đám mây tiêu chuẩn |
Ứng dụng phân phối ưu tiên thiết bị di động - đa dạng nguồn yêu cầu có Tác nhân người dùng di động mang lại kết quả tốt nhất.
Điểm dữ liệu để theo dõi
| Số liệu | Giá trị doanh nghiệp |
|---|---|
| Giá các món trong thực đơn | Phân tích ngang giá và chênh lệch giá |
| Phí giao hàng | So sánh phí nền tảng |
| Số lượng đặt hàng tối thiểu | Phân tích rào cản truy cập |
| Ước tính thời gian giao hàng | So sánh mức độ dịch vụ |
| Khuyến mãi/discounts | Thông tin tiếp thị |
| Tình trạng sẵn có của nhà hàng | Phân tích phạm vi bảo hiểm |
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Kết quả nhà hàng trống | Vị trí không được cung cấp hoặc trang CAPTCHA | Đặt mã zip địa chỉ giao hàng chính xác |
| Giá thực đơn khác với ứng dụng | Sự khác biệt về giá trên web và ứng dụng | Sử dụng UA di động để nhận được mức giá tương đương với ứng dụng |
| Vòng lặp thử thách Cloudflare | Dấu vân tay không khớp | Sử dụng đa dạng nguồn yêu cầu + UA di động |
| Nhà hàng được tìm thấy trên một nền tảng nhưng không tìm thấy trên nền tảng khác | Phạm vi bảo hiểm khác nhau | Đánh dấu là "không có sẵn" khi so sánh |
| Phí giao hàng không chính xác | Định giá phụ thuộc vào vị trí | Khớp địa lý proxy với vị trí mục tiêu |
Câu hỏi thường gặp
Tại sao giá khác nhau giữa các nền tảng giao hàng?
Các nhà hàng đặt các mức giá khác nhau cho mỗi nền tảng để tính tỷ lệ hoa hồng khác nhau (15-30%). Phí giao hàng và phí dịch vụ cũng khác nhau tùy theo nền tảng.
Tôi nên sử dụng thiết bị di động hay máy tính để bàn để thu thập các ứng dụng phân phối?
Di động - đây là những nền tảng ưu tiên thiết bị di động. đa dạng nguồn yêu cầu với Tác nhân người dùng iPhone/Android tạo ra lưu lượng truy cập trông chân thực nhất.
Tôi nên so sánh giá bao lâu một lần?
Hàng tuần để phân tích thị trường chung. Hàng ngày trong thời gian khuyến mại hoặc chạy nước rút nghiên cứu cạnh tranh.
Hướng dẫn liên quan
- Giám sát hàng tồn kho bán lẻ
- đa dạng nguồn yêu cầu cho CAPTCHA
- Ủy quyền dân cư luân phiên
So sánh giá giao đồ ăn trên quy mô lớn —lấy khóa CaptchaAI của bạnvà tự động hóa phân tích đa nền tảng.