Jak proxy pomagają w scrapowaniu danych recenzji: Trustpilot, G2 i Google Business

Praktyczny przewodnik po scrapowaniu publicznych recenzji z Trustpilot, G2 i Google Business przy użyciu rotacyjnych proxy residential. Przykłady kodu w Python i Node.js, strategie rotacji IP i geo-targetingu.

How Proxies Help You Scrape Reviews Data: Trustpilot, G2 & Google Business
W tym artykule

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) i gl (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.

FunkcjaSkładnia nazwy użytkownikaZastosowanie
Rotacja IP per-requestuser:passKażde zapytanie otrzymuje nowy IP
Geo-targeting krajuser-country-US:passIP z określonego kraju
Geo-targeting miastouser-country-DE-city-berlin:passIP z określonego miasta
Sticky sessionuser-session-abc123:passTen 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 USA
  • https://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.

Często zadawane pytania

Jak proxy pomagają w scrapowaniu danych recenzji?

Proxy residential umożliwiają rozproszenie zapytań HTTP po wielu adresach IP, co zapobiega blokadom rate limitingu narzucanym przez platformy takie jak Trustpilot (20-50 zapytań/min na IP), G2 czy Google Business. Rotacja IP per-request sprawia, że każdy adres IP wysyła tylko jedno zapytanie, a geo-targeting zapewnia spójność lokalizacji z parametrami URL — co jest krytyczne dla Google Business, gdzie lokalizacja IP wpływa na widoczne recenzje.

Który typ proxy jest najlepszy do scrapowania recenzji?

Residential proxy są najlepsze do scrapowania recenzji, ponieważ adresy IP pochodzą od prawdziwych dostawców ISP i wyglądają jak ruch organiczny. Datacenter IP są często blokowane przez platformy takie jak G2 już po kilku zapytaniach. Mobile proxy są jeszcze trudniejsze do wykrycia, ale zazwyczaj droższe. Dla większości przypadków użycia residential proxy oferują najlepszy stosunek kosztu do niezawodności.

Jak unikać blokad podczas scrapowania recenzji?

Używaj rotacyjnych proxy residential z opóźnieniem 1-3 sekundy między zapytaniami i losowym jitterem. Implementuj retry logic z exponential backoff dla HTTP 429. Używaj realistycznych nagłówków HTTP (Accept, Accept-Language, Sec-Fetch-*). Dla G2 stosuj sticky sessions, aby utrzymać ten sam IP w trakcie przeglądania stron profilu. Dla Google Business dopasuj kraj IP do parametrów gl/hl w URL.

Czy scrapowanie recenzji Trustpilot jest legalne?

Scrapowanie publicznie dostępnych recenzji (bez logowania) jest ogólnie dopuszczalne, jeśli przestrzegasz Warunków Korzystania platformy, plików robots.txt oraz przepisów takich jak CFAA w USA i RODO w UE. Nie należy zbierać danych osobowych (PII) ani danych dostępnych tylko po zalogowaniu. Warto rozważyć użycie oficjalnych API tam, gdzie są dostępne, aby zapewnić pełną zgodność z ToS platformy.

Jak scrapować recenzje Google Business z geo-targetingiem?

Google Business wyświetla różne recenzje w zależności od parametrów hl (język) i gl (kraj) oraz lokalizacji IP. Używaj country-targeted residential proxy (np. user-country-US:pass@gate.proxyhat.com:8080) dopasowanych do parametru gl w URL. Niespójność między krajem IP a parametrem gl powoduje niespójne wyniki lub dodatkowe weryfikacje. Sticky sessions pomagają utrzymać spójność podczas paginacji recenzji.

Gotowy, aby zacząć?

Dostęp do ponad 50 mln rezydencjalnych IP w ponad 148 krajach z filtrowaniem AI.

Zobacz cenyProxy rezydencjalne
← Powrót do Bloga