Scrapowanie danych recenzji to jedno z najczęstszych zastosowań proxy residential w analizie rynku i monitoringu marek. Platformy takie jak Trustpilot, G2 czy Google Business agregują miliony opinii klientów, które są cennym źródłem danych dla analizy sentymentu, śledzenia konkurencji i badań produktowych. Problem polega na tym, że te platformy aktywnie chronią swoje dane przed automatycznym pobieraniem — stosują rate limiting, detekcję botów i personalizację wyników na podstawie lokalizacji IP.
Ważne zastrzeżenie: Ten artykuł dotyczy wyłącznie zbierania publicznie dostępnych danych recenzji, które nie wymagają logowania. Przestrzegaj Warunków Korzystania (ToS) każdej platformy oraz odpowiednich przepisów prawnych, w tym CFAA w USA i RODO w UE. Nie zbieraj danych osobowych (PII) ani danych dostępnych tylko po zalogowaniu. Szanuj pliki robots.txt i wewnętrzne limity zapytań.
Jak proxy pomagają w scrapowaniu danych recenzji: dlaczego pojedyncze IP nie wystarczy
Strony z recenzjami stosują wielowarstwowe mechanizmy obronne. Głównym problemem nie jest to, że dane są ukryte — większość recenzji na Trustpilot, G2 czy Google Business jest publicznie widoczna. Problemem jest to, że platformy ograniczają dostęp na poziomie infrastruktury:
- Rate limiting: Trustpilot i G2 stosują limity zapytań na adres IP — często zaledwie 20–50 zapytań na minutę z jednego IP, po czym następuje throttle (HTTP 429) lub tymczasowa blokada.
- Geo-personalizacja: Google Business wyświetla różne recenzje w zależności od parametrów
hl(język) igl(kraj) oraz lokalizacji IP. Recenzje widoczne dla IP z USA mogą różnić się od tych widocznych dla IP z Niemiec. - Detekcja wzorców: Setki zapytań z tego samego IP w krótkim czasie są sygnałem alarmowym. Platformy używają heurystyk analizujących częstotliwość, nagłówki i zachowanie sesji.
- Anti-bot challenges: G2 stosuje agresywniejsze środki — w tym CAPTCHA i JavaScript challenges — które mogą blokować datacenter IP znacznie szybciej niż residential IP.
Rotacyjne proxy residential rozwiązują te problemy, ponieważ każdy adres IP pochodzi od prawdziwego dostawcy ISP i wygląda jak ruch organiczny. Zamiast wysyłać 500 zapytań z jednego IP, rozpraszasz je po 50–100 IP, utrzymując niską częstotliwość zapytań na każdy adres. Geo-targeting pozwala dodatkowo ustalić spójny kraj sesji, co ma krytyczne znaczenie dla Google Business, gdzie lokalizacja wpływa na to, które recenzje są widoczne.
Architektura scrapowania recenzji z ProxyHat
ProxyHat oferuje bramę proxy residential dostępną pod gate.proxyhat.com na porcie 8080 (HTTP) lub 1080 (SOCKS5). Konfiguracja geo-targetingu i sesji odbywa się w nazwie użytkownika, co eliminuje potrzebę ręcznego zarządzania pulą IP. Pełną dokumentację znajdziesz na docs.proxyhat.com.
| Funkcja | Składnia nazwy użytkownika | Zastosowanie |
|---|---|---|
| Rotacja IP per-request | user:pass | Każde zapytanie otrzymuje nowy IP |
| Geo-targeting kraj | user-country-US:pass | IP z określonego kraju |
| Geo-targeting miasto | user-country-DE-city-berlin:pass | IP z określonego miasta |
| Sticky session | user-session-abc123:pass | Ten sam IP dla wielu zapytań |
Trustpilot: scrapowanie recenzji z __NEXT_DATA__ JSON
Trustpilot renderuje profile firmowe przy użyciu Next.js, co oznacza, że pełne dane recenzji są osadzone w tagu <script id="__NEXT_DATA__"> jako obiekt JSON. Zamiast parsować kruche selektory HTML, można wyciągnąć ten JSON bezpośrednio — jest to znacznie bardziej odporne na zmiany layoutu.
Paginacja na Trustpilot odbywa się przez parametr ?page=N w URL profilu firmy. Każda strona zawiera około 20 recenzji. Przykładowy URL: https://www.trustpilot.com/review/example.com?page=2.
Python: Trustpilot z rotacją IP per strona
import requests
import json
import re
import time
import random
PROXY = "http://user:pass@gate.proxyhat.com:8080"
proxies = {"http": PROXY, "https": PROXY}
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
def scrape_trustpilot_reviews(domain, max_pages=10):
all_reviews = []
for page in range(1, max_pages + 1):
url = f"https://www.trustpilot.com/review/{domain}?page={page}"
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
if resp.status_code == 429:
print(f"Rate limited on page {page}, waiting...")
time.sleep(random.uniform(5, 10))
continue
if resp.status_code != 200:
print(f"Status {resp.status_code} on page {page}")
break
# Extract __NEXT_DATA__ JSON
match = re.search(
r'<script id="__NEXT_DATA__"[^>]*>(.*?)</script>',
resp.text, re.DOTALL
)
if not match:
print(f"No __NEXT_DATA__ on page {page}")
break
data = json.loads(match.group(1))
reviews = data.get("props", {}).get("pageProps", {}).get("reviews", [])
for r in reviews:
all_reviews.append({
"id": r.get("id"),
"title": r.get("title"),
"text": r.get("text"),
"rating": r.get("rating"),
"date": r.get("dates", {}).get("publishedDate"),
"author": r.get("consumer", {}).get("displayName"),
})
print(f"Page {page}: {len(reviews)} reviews")
time.sleep(random.uniform(1.5, 3.0))
except Exception as e:
print(f"Error on page {page}: {e}")
return all_reviews
reviews = scrape_trustpilot_reviews("example.com", max_pages=5)
print(f"Total reviews collected: {len(reviews)}")
Powyższy kod używa domyślnej rotacji IP — każde zapytanie przez ProxyHat otrzymuje nowy adres IP. Opóźnienie 1.5–3.0 sekundy między zapytaniami dodatkowo zmniejsza ryzyko detekcji wzorca.
G2: scrapowanie recenzji produktów z residential proxy
G2 stosuje znacznie agresywniejszą ochronę anti-bot niż Trustpilot. Datacenter IP są często blokowane już po kilku zapytaniach. Residential IP są tu niezbędne, a realistyczne nagłówki HTTP odgrywają kluczową rolę — brak nagłówka Accept lub nieprawidłowy Sec-Fetch-Dest może wywołać challenge.
G2 wyświetla recenzje produktów na URL typu https://www.g2.com/products/{product-slug}/reviews. Paginacja używa parametru ?page=N. Każda strona zawiera około 10 recenzji wraz z rozkładem ocen gwiazdkowych.
Python: G2 z sticky session i realistycznymi nagłówkami
import requests
import time
import random
def get_g2_proxy(session_id):
return {
"http": f"http://user-session-{session_id}:pass@gate.proxyhat.com:8080",
"https": f"http://user-session-{session_id}:pass@gate.proxyhat.com:8080",
}
HEADERS = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
}
def scrape_g2_reviews(product_slug, max_pages=5):
all_reviews = []
session_id = f"g2-{product_slug}-{random.randint(1000,9999)}"
proxies = get_g2_proxy(session_id)
for page in range(1, max_pages + 1):
url = f"https://www.g2.com/products/{product_slug}/reviews?page={page}"
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
if resp.status_code == 403:
print(f"Blocked on page {page} — rotating session")
session_id = f"g2-{product_slug}-{random.randint(1000,9999)}"
proxies = get_g2_proxy(session_id)
time.sleep(random.uniform(3, 7))
continue
if resp.status_code == 429:
wait = random.uniform(10, 20)
print(f"Throttled, waiting {wait:.1f}s")
time.sleep(wait)
continue
if resp.status_code != 200:
print(f"Status {resp.status_code} on page {page}")
break
# Parse reviews from HTML (G2 does not embed __NEXT_DATA__)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
review_items = soup.find_all("div", attrs={"itemprop": "review"})
for item in review_items:
rating_tag = item.find("meta", attrs={"itemprop": "ratingValue"})
title_tag = item.find("div", attrs={"class": "review-title"})
body_tag = item.find("div", attrs={"itemprop": "reviewBody"})
all_reviews.append({
"rating": rating_tag["content"] if rating_tag else None,
"title": title_tag.get_text(strip=True) if title_tag else None,
"text": body_tag.get_text(strip=True) if body_tag else None,
"page": page,
})
print(f"Page {page}: {len(review_items)} reviews")
time.sleep(random.uniform(2, 4))
except Exception as e:
print(f"Error on page {page}: {e}")
return all_reviews
reviews = scrape_g2_reviews("slack", max_pages=3)
print(f"Collected {len(reviews)} G2 reviews")
Sticky session (-session-{id}) utrzymuje ten sam IP przez wiele zapytań, co jest ważne dla G2 — nagła zmiana IP w trakcie przeglądania stron może wywołać challenge. Jeśli sesja zostanie zablokowana (HTTP 403), kod generuje nowy identyfikator sesji, co wymusza rotację IP.
Google Business: scrapowanie recenzji z geo-targetingiem
Google Business reviews są szczególnie wrażliwe na lokalizację. Parametry hl (język interfejsu) i gl (kraj) w URL wpływają na to, które recenzje są wyświetlane. Na przykład:
https://www.google.com/maps/place/.../?hl=en&gl=us— recenzje widoczne dla użytkowników w USAhttps://www.google.com/maps/place/.../?hl=de&gl=de— recenzje widoczne dla użytkowników w Niemczech
Aby uzyskać spójny zestaw recenzji, należy dopasować parametry URL do kraju IP proxy. Użycie IP z USA z parametrem gl=de może spowodować niespójne wyniki lub dodatkowe weryfikacje. Krajowy geo-targeting ProxyHat (-country-US) rozwiązuje ten problem.
Python: Google Business z country-targeted residential sessions
import requests
import json
import time
import random
PROXY_TEMPLATE = "http://user-country-{country}-session-{sid}:pass@gate.proxyhat.com:8080"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
def scrape_google_reviews(place_id, country="US", max_scrolls=20):
session_id = f"gb-{place_id}-{random.randint(1000,9999)}"
proxy_url = PROXY_TEMPLATE.format(country=country, sid=session_id)
proxies = {"http": proxy_url, "https": proxy_url}
# Google Maps uses an internal API endpoint for review pagination
base_url = "https://www.google.com/maps/place"
url = f"{base_url}/?q=place_id:{place_id}&hl=en&gl={country.lower()}"
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
if resp.status_code != 200:
print(f"Initial load failed: {resp.status_code}")
return []
# Extract initial review data from embedded JSON
# Google embeds data in window.__initData or similar structures
text = resp.text
reviews = []
# Look for review data in the embedded protobuf/JSON
# This is simplified — Google's format changes frequently
import re
review_matches = re.findall(
r'"\[\"(.*?)\".*?"(\d)".*?"(\d{4}-\d{2}-\d{2})',
text
)
for match in review_matches[:50]:
reviews.append({
"text": match[0][:500],
"rating": int(match[1]),
"date": match[2],
"country": country,
})
print(f"Collected {len(reviews)} reviews for {place_id} ({country})")
time.sleep(random.uniform(2, 4))
return reviews
except Exception as e:
print(f"Error: {e}")
return []
# Collect reviews from multiple countries for comparison
for country in ["US", "DE", "GB"]:
reviews = scrape_google_reviews("ChIJN1t_tDeuEmsRUsoyG83frY4", country=country)
print(f"{country}: {len(reviews)} reviews")
Wskazówka: Google często zmienia format osadzonych danych. Zamiast polegać na parsowaniu HTML, rozważ użycie Places API jako oficjalnej alternatywy, jeśli Twój przypadek użycia na to pozwala. Scrapowanie Google Maps jest trudniejsze i bardziej ryzykowne niż Trustpilot czy G2.
Node.js: uniwersalny scraper recenzji z ProxyHat
Poniższy przykład Node.js demonstruje rotację IP per-request dla zbierania recenzji z wielu platform jednocześnie. Używa biblioteki axios z proxy HTTP.
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const PROXY_BASE = 'http://user:pass@gate.proxyhat.com:8080';
const HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
};
async function fetchWithProxy(url, sessionTag = null) {
const proxyUrl = sessionTag
? `http://user-session-${sessionTag}:pass@gate.proxyhat.com:8080`
: PROXY_BASE;
const agent = new HttpsProxyAgent(proxyUrl);
try {
const resp = await axios.get(url, {
httpsAgent: agent,
headers: HEADERS,
timeout: 30000,
validateStatus: (s) => s < 500,
});
return { status: resp.status, data: resp.data };
} catch (err) {
console.error(`Fetch error: ${err.message}`);
return { status: 0, data: null };
}
}
async function scrapeTrustpilot(domain, maxPages = 5) {
const reviews = [];
for (let page = 1; page <= maxPages; page++) {
const url = `https://www.trustpilot.com/review/${domain}?page=${page}`;
const { status, data } = await fetchWithProxy(url);
if (status === 429) {
console.log(`Throttled on page ${page}, pausing...`);
await new Promise(r => setTimeout(r, 5000 + Math.random() * 5000));
page--; // retry
continue;
}
if (status !== 200) {
console.log(`Stopping at page ${page}: HTTP ${status}`);
break;
}
const match = data.match(
/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/
);
if (match) {
const json = JSON.parse(match[1]);
const pageReviews = json.props?.pageProps?.reviews || [];
pageReviews.forEach(r => {
reviews.push({
title: r.title,
rating: r.rating,
date: r.dates?.publishedDate,
page,
});
});
console.log(`Page ${page}: ${pageReviews.length} reviews`);
}
await new Promise(r => setTimeout(r, 1500 + Math.random() * 1500));
}
return reviews;
}
(async () => {
const reviews = await scrapeTrustpilot('example.com', 5);
console.log(`Total: ${reviews.length} reviews`);
})();
Najczęstsze błędy i przypadki brzegowe
1. Ignorowanie parametrów geo w Google Business
Użycie IP z USA z parametrem gl=de powoduje niespójne wyniki. Zawsze dopasowuj kraj IP do parametru gl w URL. ProxyHat pozwala ustawiać kraj przez -country-XX w nazwie użytkownika.
2. Zbyt agresywne tempo zapytań
Nawet z rotacyjnymi proxy, wysyłanie 100 zapytań na sekundę z różnych IP może zostać wykryte przez zaawansowane systemy anti-bot. Utrzymuj 1–3 sekundy opóźnienia między zapytaniami i dodaj losowe jitter.
3. Brak obsługi HTTP 429 i 403
Zawsze implementuj retry logic z exponential backoff. HTTP 429 oznacza rate limit — odczekaj i spróbuj ponownie. HTTP 403 oznacza blokadę IP — rotuj sesję i spróbuj z nowym IP.
4. Poleganie na kruchych selektorach HTML
Trustpilot używa Next.js — dane są w __NEXT_DATA__. G2 wymaga parsowania HTML, ale struktura może się zmienić. Używaj atrybutów itemprop i data-testid zamiast klas CSS, które są często generowane dynamicznie.
5. Scrapowanie danych wymagających logowania
Niektóre recenzje na G2 są widoczne tylko po zalogowaniu. Scrapowanie danych za login wall narusza ToS i może naruszać przepisy. Zbieraj wyłącznie recenzje dostępne publicznie, bez autoryzacji.
Konfiguracja ProxyHat i linki
ProxyHat oferuje residential, mobile i datacenter proxy. Do scrapowania recenzji zalecamy residential proxy ze względu na najwyższą niezawodność i najniższe ryzyko blokad. Szczegóły konfiguracji znajdziesz w przypadku użycia web scraping oraz na stronie lokalizacji.
Dla projektów wymagających monitorowania pozycji w wyszukiwarce obok recenzji, zobacz nasz przypadek użycia SERP tracking. Cennik proxy residential dostępny jest na stronie cennika ProxyHat.
Etyka i kiedy używać oficjalnych API
Scrapowanie danych recenzji powinno być przeprowadzane odpowiedzialnie. Kilka zasad:
- Szanuj robots.txt: Sprawdź, czy platforma wyraźnie zabrania scrapowania sekcji z recenzjami. Trustpilot i G2 mają pliki robots.txt — przeczytaj je przed rozpoczęciem.
- Bez PII: Nazwy użytkowników i awatary to dane osobowe. Jeśli zbierasz je w celach analitycznych, rozważ anonimizację lub hashowanie. Zgodnie z Art. 5 RODO, dane osobowe muszą być przetwarzane zgodnie z zasadami minimalizacji.
- Umiarkowane tempo: Nie przeciążaj serwerów platformy. 1–3 zapytania na sekundę z rotacją IP to bezpieczne tempo dla większości przypadków.
- Oficjalne API: Jeśli platforma oferuje oficjalne API (np. Google Places API), rozważ jego użycie. API zapewnia stabilny format danych, dokumentację i zgodność z ToS — kosztem limitów zapytań i opłat.
W praktyce, wiele zespołów używa hybrydowego podejścia: oficjalne API tam, gdzie jest dostępne i opłacalne, oraz scrapowanie z proxy residential tam, gdzie API nie obejmuje potrzebnych danych lub jest zbyt kosztowne przy dużej skali.
Najważniejsze wnioski
- Rotacyjne proxy residential są niezbędne do scrapowania recenzji z Trustpilot, G2 i Google Business — pojedyncze IP zostanie zablokowane po 20–50 zapytaniach.
- Trustpilot osadza dane recenzji w
__NEXT_DATA__JSON — parsuj JSON zamiast kruchych selektorów HTML.- G2 wymaga sticky sessions i realistycznych nagłówków — rotacja IP w trakcie sesji może wywołać challenge anti-bot.
- Google Business potrzebuje country-targeted proxy dopasowanych do parametrów
hl/gl— niespójność lokalizacji IP i URL powoduje błędne wyniki.- ProxyHat umożliwia konfigurację geo-targetingu i sesji w nazwie użytkownika przez
gate.proxyhat.com:8080— bez zarządzania pulą IP.- Zgodność — zbieraj tylko publiczne dane, szanuj ToS, robots.txt i przepisy o ochronie danych osobowych.






