如何抓取Google Shopping价格与产品数据:2026实战指南

Google Shopping Content API只返回商家自有商品,要获取竞品价格必须解析tbm=shop搜索结果HTML。本指南涵盖反爬机制、CSS选择器、住宅代理配置与Python实战代码。

How to Scrape Google Shopping Prices in 2026: A Practical Guide

如何抓取Google Shopping价格:API与HTML的取舍

如果你正在做竞品价格监控,第一个问题通常是:能不能用官方API?答案是——不能用于竞品分析。Google Content API for Shopping 只返回你自己Merchant Center账户中的商品数据,它是一个商家管理工具,不是竞争情报数据源。要获取竞争对手在Google Shopping上的价格、卖家和评分,你必须解析 tbm=shop 搜索结果HTML或 /shopping/product/ 商品详情页。

这就是本指南的核心:如何抓取Google Shopping价格——从URL构造、CSS选择器、反爬绕过到住宅代理配置,给出可直接运行的Python代码和工程实践。

Google反爬技术栈:你面对的是什么

Google Shopping的搜索结果页面与常规搜索共享同一套反爬基础设施。了解这套机制是成功抓取的前提。

reCAPTCHA与sorry/index重定向

当Google检测到可疑流量时,最常见的第一步是将请求重定向到 https://www.google.com/sorry/index,页面显示一个reCAPTCHA挑战。如果你用 requests 库直接请求,你会收到一个HTTP 429状态码或302重定向。这是硬封锁的信号——当前IP已被临时拉黑。

根据Google搜索中心文档的说明,Google使用多层信号来判断自动化流量,包括请求频率、IP信誉、浏览器指纹和行为模式。实际测试中,单IP在连续发送约50-80个请求后即可能触发封锁,具体阈值因IP段信誉而异。

每IP速率限制

Google的速率限制是按IP而非按账户执行的(对于未认证的SERP请求)。这意味着:

  • 同一IP短时间内大量请求 → 触发sorry/index重定向
  • 数据中心IP段(如AWS、GCP)的阈值更低,因为Google已知这些是云服务器
  • 住宅IP的阈值相对更高,因为它们与真实用户流量混合

这就是为什么住宅代理对Google Shopping抓取至关重要——它们使用真实ISP分配的IP,信誉评分远高于数据中心IP。

URL模式与CSS选择器详解

要抓取Google Shopping,你需要知道两个关键URL模式和一组CSS选择器。

搜索结果URL模式

Google Shopping搜索的基本URL格式为:

https://www.google.com/search?tbm=shop&q=YOUR_QUERY&gl=US&hl=en

关键参数:

  • tbm=shop — 切换到Shopping垂直搜索
  • q — 搜索关键词
  • gl — 国家代码(如 USDEJP),影响显示的卖家和货币
  • hl — 语言代码(如 endeja),影响UI语言和部分结果排序

商品详情页URL模式

点击搜索结果中的商品会跳转到商品详情页:

https://www.google.com/shopping/product/PRODUCT_ID?gl=US&hl=en

此页面包含更详细的卖家报价列表、规格参数和评论摘要。

核心CSS选择器

以下是2025-2026年验证有效的Google Shopping搜索结果选择器(注意:Google会不定期更新DOM结构,建议定期验证):

数据点CSS选择器说明
结果容器.sh-dgr__content每个商品卡片的根节点
结果网格.sh-pr__product-results整个结果列表的容器
商品标题.sh-dgr__content h3[role="heading"]商品名称文本
价格.a8Pemb当前价格(含货币符号)
卖家名称.a8Pemb-O5lDed 附近文本可能需要从多个节点提取
评分[role="img"] aria-label包含"Rated X out of 5"文本
商品链接.sh-dgr__content a[href]指向/shopping/product/的链接

实战提示:Google的CSS类名经常变化(如 .a8Pemb 这类自动生成的类名)。建议同时使用多个备选选择器和结构化数据属性(如 roledata-*)来提高解析鲁棒性。

为什么本地化价格需要城市级住宅代理

Google Shopping的价格和卖家列表是高度本地化的。一个美国购物者和一个德国购物者搜索同一个关键词,看到的结果可能完全不同:

  • 不同的卖家(部分卖家只在特定国家运营)
  • 不同的货币(USD vs EUR)
  • 不同的价格(同一商品在不同市场定价不同)
  • 不同的运费和库存状态

仅靠 glhl URL参数不够——Google也会根据请求IP的地理位置返回结果。如果你从一个美国数据中心IP请求 gl=DE,Google可能仍然返回部分美国卖家的结果,或者触发更严格的反爬检查。

正确做法是让代理IP的地理位置与 gl 参数一致。ProxyHat支持在用户名中指定国家和城市:

# 美国购物者视角
http://user-country-US:pass@gate.proxyhat.com:8080

# 德国柏林购物者视角
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080

# 日本东京购物者视角
http://user-country-JP-city-tokyo:pass@gate.proxyhat.com:8080

这样,请求IP的地理位置与 gl 参数匹配,Google会返回该地区购物者看到的真实结果。查看ProxyHat支持的全球位置请访问位置列表

Python实战:通过ProxyHat抓取Google Shopping

下面是一个完整的Python示例,使用 requestsBeautifulSoup 通过ProxyHat住宅代理抓取Google Shopping搜索结果。

基础请求函数

import requests
from bs4 import BeautifulSoup
import random
import time

# ProxyHat住宅代理配置
def build_proxy_url(country="US", city=None, session_id=None):
    username = f"user-country-{country}"
    if city:
        username += f"-city-{city}"
    if session_id:
        username += f"-session-{session_id}"
    password = "YOUR_PASSWORD"
    return f"http://{username}:{password}@gate.proxyhat.com:8080"

def fetch_google_shopping(query, country="US", hl="en", city=None):
    proxy_url = build_proxy_url(country=country, city=city)
    proxies = {"http": proxy_url, "https": proxy_url}

    params = {
        "q": query,
        "tbm": "shop",
        "gl": country,
        "hl": hl,
    }

    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": f"{hl},{country.lower()};q=0.9",
        "Accept": "text/html,application/xhtml+xml",
    }

    url = "https://www.google.com/search"
    resp = requests.get(url, params=params, headers=headers,
                        proxies=proxies, timeout=30)

    # 检测软封锁
    if "sorry/index" in resp.url:
        raise RuntimeError("检测到软封锁:被重定向到sorry/index")
    if resp.status_code == 429:
        raise RuntimeError("速率限制:HTTP 429")

    return resp.text

解析搜索结果

def parse_shopping_results(html):
    soup = BeautifulSoup(html, "html.parser")
    results = []

    # 查找所有商品卡片
    cards = soup.select(".sh-dgr__content")
    if not cards:
        # 备选选择器
        cards = soup.select("[data-docid]")

    for card in cards:
        item = {}

        # 标题
        title_node = card.select_one("h3") or card.select_one('[role="heading"]')
        item["title"] = title_node.get_text(strip=True) if title_node else None

        # 价格
        price_node = card.select_one(".a8Pemb")
        if price_node:
            item["price"] = price_node.get_text(strip=True)
        else:
            # 备选:查找包含货币符号的文本
            text = card.get_text()
            import re
            match = re.search(r'[\$€£¥]\d+[.,]\d{2}', text)
            item["price"] = match.group(0) if match else None

        # 卖家
        seller_node = card.select_one(".a8Pemb-O5lDed")
        item["seller"] = seller_node.get_text(strip=True) if seller_node else None

        # 评分
        rating_node = card.select_one('[role="img"][aria-label*="Rated"]')
        if rating_node:
            item["rating"] = rating_node.get("aria-label", "")

        # 商品链接
        link_node = card.select_one("a[href*='/shopping/product/']")
        if link_node:
            item["product_url"] = "https://www.google.com" + link_node["href"]

        if item["title"] and item["price"]:
            results.append(item)

    return results

# 使用示例
html = fetch_google_shopping("iPhone 15 Pro 128GB", country="US")
results = parse_shopping_results(html)
for r in results[:3]:
    print(f"标题: {r['title']}")
    print(f"价格: {r['price']}")
    print(f"卖家: {r.get('seller', 'N/A')}")
    print(f"评分: {r.get('rating', 'N/A')}")
    print("---")

示例输出(截断):

标题: Apple iPhone 15 Pro 128GB - Titanium Blue
价格: $999.00
卖家: Best Buy
评分: Rated 4.6 out of 5
---
标题: Apple iPhone 15 Pro 128GB Unlocked
价格: $979.99
卖家: Amazon.com
评分: Rated 4.5 out of 5
---

抓取商品详情页的卖家报价

def fetch_product_offers(product_id, country="US", city=None):
    proxy_url = build_proxy_url(country=country, city=city)
    proxies = {"http": proxy_url, "https": proxy_url}

    url = f"https://www.google.com/shopping/product/{product_id}"
    params = {"gl": country, "hl": "en"}

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
        "Accept-Language": f"en,{country.lower()};q=0.9",
    }

    resp = requests.get(url, params=params, headers=headers,
                        proxies=proxies, timeout=30)
    soup = BeautifulSoup(resp.text, "html.parser")

    offers = []
    # 卖家报价面板
    offer_rows = soup.select("[data-shp-handler]")
    for row in offer_rows:
        offer = {}
        price_node = row.select_one(".a8Pemb")
        seller_node = row.select_one("[data-shp-handler-title]")
        offer["price"] = price_node.get_text(strip=True) if price_node else None
        offer["seller"] = seller_node.get_text(strip=True) if seller_node else None
        if offer["price"]:
            offers.append(offer)

    return offers

分页、批量查询与软封锁检测

分页策略

Google Shopping搜索结果通常每页显示约20-40个商品。要获取更多结果,可以使用 start 参数进行分页:

def scrape_all_pages(query, country="US", max_pages=5):
    all_results = []
    for page in range(max_pages):
        start = page * 20  # 每页约20条
        params = {
            "q": query, "tbm": "shop",
            "gl": country, "hl": "en",
            "start": start,
        }
        # 每次请求使用不同的session ID实现IP轮换
        session_id = f"shop-{query[:10]}-{page}"
        proxy_url = build_proxy_url(country=country, session_id=session_id)

        html = fetch_google_shopping(query, country=country)
        page_results = parse_shopping_results(html)

        if not page_results:
            print(f"第{page+1}页无结果,停止分页")
            break

        all_results.extend(page_results)

        # 随机延迟 3-8 秒
        delay = random.uniform(3, 8)
        time.sleep(delay)

    return all_results

批量查询处理

当你需要监控数百或数千个关键词的价格时,批量处理是必须的。关键原则:

  • 分批执行:每批5-10个关键词,批间暂停30-60秒
  • 随机化延迟:每个请求间设置3-8秒随机延迟,模拟人类行为
  • IP轮换:每个请求使用不同的session ID,让ProxyHat自动分配新IP
  • 并发控制:不超过5-10个并发会话
import random
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

def batch_scrape_keywords(keywords, country="US", max_workers=5):
    results = {}

    def scrape_one(kw):
        try:
            html = fetch_google_shopping(kw, country=country)
            items = parse_shopping_results(html)
            time.sleep(random.uniform(3, 8))
            return kw, items
        except RuntimeError as e:
            print(f"软封锁检测 [{kw}]: {e}")
            return kw, []

    # 分批处理,每批max_workers个关键词
    batch_size = max_workers
    for i in range(0, len(keywords), batch_size):
        batch = keywords[i:i+batch_size]
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            futures = {executor.submit(scrape_one, kw): kw for kw in batch}
            for future in as_completed(futures):
                kw, items = future.result()
                results[kw] = items

        # 批间暂停
        if i + batch_size < len(keywords):
            pause = random.uniform(30, 60)
            print(f"批间暂停 {pause:.1f} 秒...")
            time.sleep(pause)

    return results

软封锁检测清单

在硬CAPTCHA出现之前,Google通常会发出软封锁信号。检测这些信号可以让你在完全被封之前调整策略:

信号检测方法应对措施
重定向到sorry/index检查 resp.url 是否包含 "sorry"立即暂停,更换IP段
HTTP 429检查状态码退避指数等待,切换session
空结果页解析结果数为0且页面有DOM可能IP被降级,换IP重试
CAPTCHA页面检查HTML含"captcha"关键词停止当前IP所有请求
结果数量骤降对比历史数据,成功率低于50%降低频率,扩大IP池

伦理、合规与法律考量

抓取Google Shopping价格数据涉及几个重要的法律和伦理边界,必须在实施前了解。

公开数据 vs 受限数据

本指南讨论的是公开可见的价格数据——任何用户在浏览器中访问Google Shopping都能看到的信息。这不同于:

  • 需要登录才能查看的数据
  • 通过逆向工程API获取的非公开数据
  • 受版权保护的图片或详细产品描述

CFAA与GDPR风险

在美国,Computer Fraud and Abuse Act (CFAA) 历史上被用于起诉违反网站服务条款的自动化访问。虽然2022年hiQ Labs诉LinkedIn案后法院对"超出授权访问"的解读有所收窄,但绕过技术访问控制(如CAPTCHA)仍可能构成风险。

在欧盟,GDPR主要关注个人数据处理。Google Shopping的公开价格数据本身不涉及个人数据,但如果你的抓取行为收集了用户评论中的个人信息或cookie中的用户标识,则可能触发GDPR合规要求。

robots.txt与服务条款

Google的robots.txt/search 路径设置了 Disallow,这意味着Google从技术声明上不希望自动化爬虫访问搜索结果。你需要自行评估这一声明对你所在司法管辖区的法律影响。

当你需要大规模、持续的Google Shopping数据时,合规路线是使用Google官方的Shopping API合作伙伴或SERP API服务。这些服务通过官方渠道获取数据,承担合规责任。对于小规模、低频率的公开价格监控,住宅代理方案在技术上可行,但你需要:

  • 仅抓取公开价格数据,不存储个人身份信息
  • 遵守合理的请求频率,不对Google服务造成负担
  • 了解你所在地区的法律框架
  • 咨询法律顾问评估具体用例

ProxyHat配置与最佳实践

使用ProxyHat住宅代理抓取Google Shopping时,以下配置建议能最大化成功率:

代理类型选择

代理类型推荐度适用场景成本
住宅代理★★★★★Google Shopping抓取首选,IP信誉高中等
移动代理★★★★☆极高信誉,但成本较高
数据中心代理★☆☆☆☆不推荐,Google易识别并封锁

会话管理

ProxyHat支持通过session ID控制IP粘性。对于Google Shopping抓取,推荐策略是每请求轮换(不指定session ID),让每个请求获得新IP。如果需要保持同一IP来浏览多个页面(如搜索结果→商品详情),则使用相同session ID:

# 每请求轮换IP(推荐用于搜索结果抓取)
http://user-country-US:pass@gate.proxyhat.com:8080

# 粘性会话(用于搜索→详情页的连续浏览)
http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080

更多代理配置和定价信息请查看ProxyHat定价页面。如需了解更广泛的网页抓取用例,可参考网页抓取用例SERP追踪用例。完整API文档请访问ProxyHat文档

关键要点总结

Key Takeaways:

  • Google Content API for Shopping只返回自有商品数据,竞品价格必须通过HTML解析获取
  • 搜索URL格式:google.com/search?tbm=shop&q=KEYWORD&gl=COUNTRY&hl=LANG
  • 核心选择器:.sh-dgr__content(卡片)、.a8Pemb(价格)、h3(标题)
  • 住宅代理是必须的——数据中心IP会在约50-80个请求内被封锁
  • 城市级地理定位确保本地化价格准确:user-country-DE-city-berlin
  • 随机延迟3-8秒、并发不超过5-10、分批处理是稳定运行的关键
  • 检测sorry/index重定向和HTTP 429作为软封锁信号
  • 公开价格数据抓取需评估CFAA、GDPR和robots.txt的法律影响

常见问题

什么是抓取Google Shopping价格?

抓取Google Shopping价格是指通过程序化方式获取Google购物搜索结果页面中的商品价格、卖家、评分等数据。由于Google Shopping Content API只返回商家自己的商品数据,获取竞争对手价格需要解析tbm=shop搜索结果HTML或商品详情页。这通常需要配合住宅代理来绕过Google的反爬机制并获取不同地区的本地化价格。

为什么抓取Google Shopping价格需要使用代理?

Google对搜索结果页面实施了严格的反爬措施,包括reCAPTCHA验证、sorry/index重定向和激进的每IP速率限制。单IP高频请求会在约50-80次请求内触发封锁。住宅代理通过分配真实家庭IP地址,使请求看起来来自普通用户,从而大幅提高抓取成功率。城市级地理定位还能确保获取目标市场的本地化价格和卖家列表。

哪种代理类型最适合抓取Google Shopping?

住宅代理是抓取Google Shopping的最佳选择,因为它们使用真实ISP分配的IP地址,与普通用户流量难以区分。数据中心代理容易被Google识别并封锁。移动代理也可用但成本更高。对于需要本地化价格的场景,支持城市级定位的住宅代理(如ProxyHat的country-DE-city-berlin参数)是理想方案,能确保看到目标地区购物者看到的相同价格和卖家。

如何避免抓取Google Shopping时被封锁?

避免封锁的关键策略包括:使用住宅代理并轮换IP、设置随机化延迟(3-8秒)、分批处理查询而非并发轰炸、检测软封锁信号(如空结果页或重定向到sorry/index)、设置合理的User-Agent和Accept-Language头匹配代理地区。一旦检测到软封锁应立即暂停并切换IP段。建议将并发限制在5-10个会话以内,并监控成功率下降趋势。

准备开始了吗?

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

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