代理如何帮助你抓取评论数据:Trustpilot、G2与Google商家实战指南

通过住宅代理IP轮换和地理定位,从Trustpilot、G2和Google商家页面高效采集公开评论数据,包含Python和Node.js可运行代码示例及合规指南。

How Proxies Help You Scrape Reviews Data: Trustpilot, G2 & Google Business
本文目录

在市场调研和品牌监控中,评论数据是洞察用户情绪与产品反馈的金矿。但当你尝试从Trustpilot、G2或Google商家页面批量获取评论时,很快就会遭遇限流、验证码和地域化内容偏移。代理如何帮助你抓取评论数据——核心答案在于通过IP轮换和地理定位绕过这些限制,同时保持请求的合法性和可控性。本文将聚焦Trustpilot、G2和Google商家评论的实战抓取方案。

合规声明:本文仅讨论公开可访问的评论数据采集,不涉及登录墙后的内容或个人身份信息(PII)的批量抓取。在抓取任何平台前,请务必阅读其服务条款(ToS)和robots.txt文件,并遵守适用法律,包括美国的CFAA和欧盟的GDPR。robots.txt标准是判断哪些页面允许被爬取的第一道参考。

代理如何帮助你抓取评论数据:为什么评论页面会被限流和地域化

评论平台普遍部署多层反爬机制。以Trustpilot为例,其页面内容通过Next.js服务端渲染,评论数据嵌入在__NEXT_DATA__ JSON中;G2则使用更激进的反机器人检测,包括Cloudflare挑战和浏览器指纹校验;Google商家评论的展示受hl(语言)和gl(国家)参数影响,不同地区用户看到的评论子集可能完全不同。

当你用单一IP连续请求这些页面时,通常在50-200次请求后就会触发限流(HTTP 429)或验证码挑战。更隐蔽的问题是地域化内容偏移:平台会根据请求IP的地理位置返回不同语言的评论或不同的评论排序。例如,从日本IP请求Google商家页面,可能优先展示日语评论,而非你需要的英文评论。

住宅代理通过以下方式解决这些问题:

  • IP轮换:每个请求来自不同的真实ISP IP地址,避免触发基于IP的频率限制。
  • 地理定位:指定country-US等参数,确保获取目标地区的评论内容。
  • 真实指纹:住宅IP来自真实ISP,反爬系统难以区分代理流量与正常用户流量。

根据行业经验,使用住宅代理抓取评论数据的成功率通常可达90%以上,而数据中心代理在强反爬平台上往往低于30%。

代理类型对比:评论抓取场景

代理类型成功率平均延迟适用平台成本
住宅代理90-98%200-800msTrustpilot / G2 / Google中高
数据中心代理10-30%50-150ms低防护站点
移动代理95-99%300-1200ms强反爬平台

对于评论抓取,住宅代理是性价比最优的选择。如果你需要更深入了解代理类型差异,可以参考ProxyHat代理位置页面了解可用的地理定位选项。

Trustpilot评论抓取实战:解析__NEXT_DATA__

Trustpilot的评论页面使用Next.js框架,所有评论数据以JSON格式嵌入在HTML源码中的<script id="__NEXT_DATA__">标签内。直接解析这段JSON比提取DOM元素更稳定,因为Trustpilot的CSS类名经常变化,但JSON结构相对固定。

关键策略:每页轮换IP,通过ProxyHat的session参数为每一页分配不同的出口IP,同时设置2-3秒的请求间隔以模拟人类浏览行为。

import requests
import json
import re
import time

PROXY_TEMPLATE = "http://user-session-{sid}:pass@gate.proxyhat.com:8080"

def scrape_trustpilot_reviews(domain, max_pages=10):
    all_reviews = []
    for page in range(1, max_pages + 1):
        # 每页使用不同的session ID,实现IP轮换
        session_id = f"tp-{domain}-{page}"
        proxy_url = PROXY_TEMPLATE.format(sid=session_id)
        proxies = {"http": proxy_url, "https": proxy_url}

        url = f"https://www.trustpilot.com/review/{domain}?page={page}"
        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",
            "Accept": "text/html,application/xhtml+xml",
        }

        try:
            resp = requests.get(url, proxies=proxies, headers=headers, timeout=30)
            if resp.status_code == 200:
                match = re.search(
                    r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>',
                    resp.text, re.DOTALL
                )
                if match:
                    data = json.loads(match.group(1))
                    reviews = data.get("props", {}).get("pageProps", {})
                    .get("reviews", [])
                    for r in reviews:
                        all_reviews.append({
                            "title": r.get("title", ""),
                            "text": r.get("text", ""),
                            "rating": r.get("rating", 0),
                            "date": r.get("dates", {}).get("publishedDate", ""),
                        })
                    print(f"Page {page}: {len(reviews)} reviews")
                else:
                    print(f"Page {page}: __NEXT_DATA__ not found")
            elif resp.status_code == 429:
                print(f"Page {page}: Rate limited, waiting 10s")
                time.sleep(10)
            else:
                print(f"Page {page}: HTTP {resp.status_code}")
        except Exception as e:
            print(f"Page {page}: Error - {e}")

        time.sleep(2.5)  # 请求间隔
    return all_reviews

reviews = scrape_trustpilot_reviews("example.com", max_pages=5)
print(f"Total: {len(reviews)} reviews")

上述代码通过user-session-{sid}为每一页创建独立的代理会话,ProxyHat网关会为不同session分配不同的出口IP。如果需要保持同一IP跨页抓取(例如需要登录态一致性),则使用固定的session ID即可。

G2评论抓取:对抗更强的反爬机制

G2的反爬比Trustpilot更激进,通常部署Cloudflare的JS挑战和浏览器指纹检测。直接用requests请求往往返回403或挑战页面。应对策略是使用住宅代理配合更真实的请求头,必要时考虑使用无头浏览器(如Playwright)。

G2的产品评论页面URL格式为https://www.g2.com/products/{slug}/reviews,星级分布和评论列表嵌入在页面HTML中。以下是Python抓取示例,使用国家定向住宅代理:

import requests
import time
from bs4 import BeautifulSoup

# 使用美国住宅代理,带session保持
proxy = "http://user-country-US-session-g2-sticky:pass@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}

def scrape_g2_reviews(product_slug, max_pages=5):
    all_reviews = []
    for page in range(1, max_pages + 1):
        url = f"https://www.g2.com/products/{product_slug}/reviews?page={page}"
        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",
            "Accept-Language": "en-US,en;q=0.9",
            "Accept-Encoding": "gzip, deflate, br",
            "DNT": "1",
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1",
        }

        try:
            resp = requests.get(url, proxies=proxies, headers=headers, timeout=45)
            if resp.status_code == 200:
                soup = BeautifulSoup(resp.text, "html.parser")
                # G2评论容器
                review_items = soup.find_all("div", attrs={"itemprop": "review"})
                for item in review_items:
                    review = {
                        "author": item.find("span", class_="author-name").get_text(strip=True) if item.find("span", class_="author-name") else "",
                        "rating": float(item.find("meta", attrs={"itemprop": "ratingValue"}).get("content", 0)) if item.find("meta", attrs={"itemprop": "ratingValue"}) else 0,
                        "title": item.find("div", class_="review-title").get_text(strip=True) if item.find("div", class_="review-title") else "",
                        "text": item.find("div", attrs={"itemprop": "reviewBody"}).get_text(strip=True) if item.find("div", attrs={"itemprop": "reviewBody"}) else "",
                    }
                    all_reviews.append(review)
                print(f"Page {page}: {len(review_items)} reviews")
            elif resp.status_code == 403:
                print(f"Page {page}: Blocked (403), try rotating IP")
                break
            else:
                print(f"Page {page}: HTTP {resp.status_code}")
        except Exception as e:
            print(f"Page {page}: Error - {e}")

        time.sleep(3)  # G2需要更长的间隔
    return all_reviews

reviews = scrape_g2_reviews("slack", max_pages=3)
print(f"Total: {len(reviews)} reviews")

注意G2使用粘性会话(session-g2-sticky)配合country-US,确保整个抓取过程使用同一美国IP,减少因IP跳变触发的安全检查。如果遇到403,建议切换session ID并增加间隔至5秒以上。

Google商家评论抓取:处理hl/gl地域化参数

Google商家(Google Business Profile)评论的展示受URL参数hl(界面语言)和gl(国家代码)影响。不同地区IP请求同一商家页面,可能看到不同的评论排序和语言偏好。使用国家定向的住宅代理可以确保获取一致locale的评论内容。

Google商家评论页面URL格式为:https://www.google.com/maps/place/{place_id}/reviews,或通过搜索https://www.google.com/search?q={business_name}+reviews&hl=en&gl=us获取。评论数据通常以动态加载方式呈现,需要解析页面中的protobuf或JSON响应。

import requests
import json
import re
import time

# 国家定向住宅代理 - 美国IP
proxy = "http://user-country-US-session-gb-stable:pass@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}

def scrape_google_business_reviews(place_id, max_scrolls=5):
    all_reviews = []
    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",
        "Accept": "text/html,application/xhtml+xml",
    }

    # 使用hl=en和gl=us确保英文评论
    url = f"https://www.google.com/maps/place/?q=place_id:{place_id}&hl=en&gl=us"

    try:
        resp = requests.get(url, proxies=proxies, headers=headers, timeout=45)
        if resp.status_code == 200:
            # Google Maps页面中的评论数据嵌入在页面脚本中
            # 搜索类似 window.APP_INITIALIZATION_STATE 的数据块
            json_matches = re.findall(
                r'\[null,null,"(.*?)"\]', resp.text
            )
            print(f"Found {len(json_matches)} potential data blocks")

            # 提取评论文本
            review_pattern = re.findall(
                r'"(\d)\.0","([^"]{10,500})"', resp.text
            )
            for rating, text in review_pattern[:50]:
                all_reviews.append({
                    "rating": int(rating),
                    "text": text.replace("\\n", " ").replace("\\u0026", "&"),
                })
            print(f"Extracted {len(all_reviews)} reviews")
        else:
            print(f"HTTP {resp.status_code}")
    except Exception as e:
        print(f"Error: {e}")

    return all_reviews

reviews = scrape_google_business_reviews("ChIJN1t_tDeuEmsRUsoyG3fr8-4")
print(f"Total: {len(reviews)} reviews")

Google商家评论抓取的复杂度较高,因为Google使用动态加载和protobuf编码。对于大规模数据采集,建议结合Playwright等无头浏览器处理动态渲染,同时使用country-US住宅代理保持locale一致性。更多关于SERP抓取的场景说明,可参考SERP追踪用例页面。

Node.js示例:使用ProxyHat代理抓取评论

以下是Node.js版本的评论抓取示例,使用https-proxy-agent通过ProxyHat住宅代理请求Trustpilot页面:

const { HttpsProxyAgent } = require('https-proxy-agent');
const axios = require('axios');

async function scrapeReviews(domain, maxPages = 5) {
  const allReviews = [];

  for (let page = 1; page <= maxPages; page++) {
    const sessionId = `node-tp-${page}`;
    const proxyUrl = `http://user-session-${sessionId}:pass@gate.proxyhat.com:8080`;
    const agent = new HttpsProxyAgent(proxyUrl);

    const url = `https://www.trustpilot.com/review/${domain}?page=${page}`;
    const headers = {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      'Accept-Language': 'en-US,en;q=0.9',
    };

    try {
      const resp = await axios.get(url, {
        httpsAgent: agent,
        headers,
        timeout: 30000,
      });

      if (resp.status === 200) {
        const match = resp.data.match(
          /<script id="__NEXT_DATA__" type="application\/json">(.*?)<\/script>/s
        );
        if (match) {
          const data = JSON.parse(match[1]);
          const reviews = data.props?.pageProps?.reviews || [];
          reviews.forEach(r => {
            allReviews.push({
              title: r.title || '',
              rating: r.rating || 0,
              text: r.text || '',
            });
          });
          console.log(`Page ${page}: ${reviews.length} reviews`);
        }
      } else {
        console.log(`Page ${page}: HTTP ${resp.status}`);
      }
    } catch (err) {
      console.log(`Page ${page}: ${err.message}`);
    }

    await new Promise(r => setTimeout(r, 2500)); // 2.5s间隔
  }

  return allReviews;
}

scrapeReviews('example.com', 5).then(r => {
  console.log(`Total: ${r.length} reviews`);
});

常见错误与边界情况

1. 未设置Accept-Language导致地域偏移

即使使用美国IP,如果不设置Accept-Language: en-US,en;q=0.9头部,某些平台仍可能根据其他信号返回非英文评论。始终将语言头部与代理国家保持一致。

2. Session ID冲突导致IP不轮换

ProxyHat的session参数控制粘性:相同session ID复用同一IP,不同session ID分配新IP。如果你希望每页轮换IP,必须为每一页使用不同的session ID(如tp-page-1tp-page-2)。如果所有页面使用相同session ID,则所有请求走同一IP——这在需要登录态一致性时有用,但在纯轮换场景下会适得其反。

3. 并发过高触发平台级封锁

即使IP轮换,如果同一目标域名的并发请求超过100次/秒,平台仍可能通过行为分析识别爬虫。建议保持每IP 2-5个请求/秒的速率,全局并发不超过20-50个请求。

4. 忽略robots.txt

在抓取前应检查目标域名的/robots.txt,确认评论页面是否允许爬取。部分平台可能通过robots.txt明确禁止抓取某些路径。更多合规细节参见robots.txt标准

合规与道德抓取:何时应使用官方API

在投入代理抓取之前,应先评估目标平台是否提供官方API。Google提供Places API可获取商家评论(有配额限制);Trustpilot提供Business API供已认证的企业主访问评论数据。如果官方API能满足你的数据需求,优先使用API——它更稳定、合规风险更低。

当官方API不可用或数据覆盖不足时,代理抓取公开评论数据是合理替代方案,但需遵循以下原则:

  • 仅采集公开数据:不绕过登录墙,不抓取需要认证才能访问的内容。
  • 不采集PII:评论中的用户名、头像URL等个人信息应按需脱敏或遵循GDPR要求处理。
  • 尊重速率限制:即使技术上可以更快,也应保持合理的请求频率。
  • 遵守ToS:阅读平台服务条款,部分平台明确禁止自动化数据采集。
  • 数据用途透明:明确数据将用于市场调研还是商业再分发,后者可能涉及更多法律约束。

关于代理定价和套餐选择,请参考ProxyHat定价页面。如需更广泛的网页抓取场景说明,可查看网页抓取用例。完整API文档请访问ProxyHat官方文档

关键要点

  • 评论平台通过IP限流、地域化和反爬机制保护数据,单一IP通常在50-200次请求后被封锁。
  • 住宅代理通过IP轮换和地理定位有效绕过这些限制,成功率可达90%以上。
  • Trustpilot评论嵌入在__NEXT_DATA__ JSON中,解析JSON比提取HTML更稳定。
  • G2反爬更激进,需要住宅IP配合真实请求头,建议使用粘性会话保持IP一致性。
  • Google商家评论受hl/gl参数影响,使用country-US住宅代理确保locale一致。
  • ProxyHat通过gate.proxyhat.com:8080提供HTTP代理,session参数控制IP轮换与粘性。
  • 优先使用官方API;代理抓取仅限于公开数据,需遵守ToS、robots.txt和适用法律。

常见问题

代理如何帮助你抓取评论数据?

代理通过IP轮换和地理定位,使每个请求看起来来自不同的真实用户和地区,从而避免单一IP触发限流、验证码或地域化内容偏移。住宅代理尤其有效,因为其IP来自真实ISP,反爬系统难以区分代理流量与正常用户流量。对于Trustpilot、G2等强反爬平台,住宅代理的成功率通常可达90%以上。

抓取评论数据时哪种代理类型效果最好?

住宅代理是抓取评论数据的最佳选择,因为其IP来自真实ISP分配的住宅地址,反爬系统难以识别。数据中心代理速度快但容易被封锁,成功率往往低于30%;移动代理覆盖好但成本较高。对于Trustpilot和G2等强反爬平台,住宅代理在成功率和成本之间提供了最优平衡。

如何在抓取评论时避免被封锁?

关键策略包括:每页请求轮换IP、设置2-5秒的请求间隔、使用真实的浏览器请求头(尤其是Accept-Language与代理国家一致)、遵守robots.txt规则、以及使用粘性会话保持多页抓取的IP一致性。同时应限制全局并发不超过20-50个请求,避免短时间内大量请求同一域名触发行为分析。

抓取Trustpilot评论需要注意什么?

Trustpilot使用Next.js框架,评论数据嵌入在页面源码的__NEXT_DATA__ JSON中。直接解析JSON比提取HTML元素更稳定,因为CSS类名经常变化但JSON结构相对固定。建议按页轮换IP(使用不同session ID),每页间隔2-3秒,并设置Accept-Language头部以获取目标语言的评论。

抓取Google商家评论如何处理地域化问题?

Google商家评论的展示受hl(语言)和gl(国家)参数影响,不同地区用户看到的评论子集可能不同。使用国家定向的住宅代理(如country-US)配合hl=en和gl=us参数,可以稳定获取特定地区的英文评论内容。建议使用粘性会话保持抓取过程中IP一致性。

准备开始了吗?

通过AI过滤访问148多个国家的5000多万个住宅IP。

查看价格住宅代理
← 返回博客