地理定向价格监控:跨市场价格追踪

利用地理目标代理监测全球各市场的产品价格。 Python和Node.js代码用于多市场价格比较,货币正常化,以及竞争对手定价策略检测.

地理定向价格监控:跨市场价格追踪

为何价格因地点而异

电子商务公司根据客户的地理位置定期调整价格。 在美国耗资49.99美元的产品在德国的定价为59.99欧元,在日本为5 499日元,在印度为39.99美元。 这些差异超越了货币转换——它们反映了区域购买力、竞争性景观、税收、航运成本和蓄意定价战略。

对于竞争情报,了解这些区域价格变化至关重要。 一个竞争者可能会在一个市场中严重削弱你,而另一个市场却在收取溢价。 没有地理目标监测,你对一半的竞争情况视而不见。 本指南涵盖如何利用地理目标代币建立多市场价格监测系统。 关于基本监测结构,见我们的指南: 自动监测竞争者价格。 。 。

地理定价如何运作

网站通过几个信号确定您的位置,并相应调整内容.

信号如何运作对定价的影响
IP 地理位置通过数据库将IP地址映射到国家/城市主要因素——决定您看到的哪个区域存储/定价
货币/语言浏览器 Access-Language 和以前的选择可能触发特定区域目录和定价
饼干以前存储在会话中的区域选择取代以后访问时基于IP的检测
URL 结构国别领域(amazon.de)或路径(/de/)直接确定区域目录
全球定位系统/设备位置移动设备定位服务用于超本地定价(交货区)

通用地理定价模式

  • 市场本地化: 亚马逊,eBay等类似平台以独立的定价运行独立的区域商店前端.
  • 动态地理定价 : SaaS公司和旅行场所根据游客的原籍国调整价格。
  • 航运调整定价: 产品包括基于地点的不同运输成本,改变有效价格.
  • 兼顾税收的定价: 欧洲价格一般包括增值税,而美国价格则显示税前金额.
  • 购买力平价: 一些公司在发展中市场提供较低的价格,以最大限度地扩大无障碍。

多市场监测的代理配置

核心要求是每个目标国家的住宅代理。 ProxyHat的地理目标设定允许您指定每个请求的具体国家.

代理服务器设置

# US pricing
http://USERNAME-country-US:PASSWORD@gate.proxyhat.com:8080
# German pricing
http://USERNAME-country-DE:PASSWORD@gate.proxyhat.com:8080
# UK pricing
http://USERNAME-country-GB:PASSWORD@gate.proxyhat.com:8080
# Japanese pricing
http://USERNAME-country-JP:PASSWORD@gate.proxyhat.com:8080
# Brazilian pricing
http://USERNAME-country-BR:PASSWORD@gate.proxyhat.com:8080
# City-level targeting for hyperlocal pricing
http://USERNAME-country-US-city-newyork:PASSWORD@gate.proxyhat.com:8080
http://USERNAME-country-DE-city-berlin:PASSWORD@gate.proxyhat.com:8080

在跨区域价格监测方面,采用每个国家内按要求轮换的做法,以避免发现,但始终保持每个市场一致的地理目标。 检查 代理哈特的完整位置列表 195+支助国。

Python 执行

这里有一个多市场价格监测系统,使用 代理哈特的 Python SDK。 。 。

地理标价

import requests
from bs4 import BeautifulSoup
import json
import time
import random
from dataclasses import dataclass, asdict
from datetime import datetime
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
]
PROXY_TEMPLATE = "http://USERNAME-country-{country}:PASSWORD@gate.proxyhat.com:8080"
@dataclass
class GeoPrice:
    product_id: str
    country: str
    price: float | None
    currency: str
    url: str
    in_stock: bool
    scraped_at: str
def get_geo_proxy(country_code: str) -> dict:
    """Get proxy configured for a specific country."""
    proxy = PROXY_TEMPLATE.format(country=country_code)
    return {"http": proxy, "https": proxy}
def scrape_price_for_region(product_url: str, country_code: str,
                             price_selector: str, currency: str) -> GeoPrice:
    """Scrape a product price from a specific geographic region."""
    headers = {
        "User-Agent": random.choice(USER_AGENTS),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": get_accept_language(country_code),
    }
    proxies = get_geo_proxy(country_code)
    try:
        response = requests.get(product_url, headers=headers,
                                proxies=proxies, timeout=30)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, "html.parser")
        price_el = soup.select_one(price_selector)
        price = None
        if price_el:
            price_text = price_el.get_text(strip=True)
            cleaned = "".join(c for c in price_text if c.isdigit() or c in ".,")
            # Handle European comma as decimal separator
            if "," in cleaned and "." in cleaned:
                cleaned = cleaned.replace(".", "").replace(",", ".")
            elif "," in cleaned:
                cleaned = cleaned.replace(",", ".")
            price = float(cleaned) if cleaned else None
        return GeoPrice(
            product_id=product_url,
            country=country_code,
            price=price,
            currency=currency,
            url=product_url,
            in_stock=True,
            scraped_at=datetime.utcnow().isoformat(),
        )
    except Exception as e:
        return GeoPrice(
            product_id=product_url,
            country=country_code,
            price=None,
            currency=currency,
            url=product_url,
            in_stock=False,
            scraped_at=datetime.utcnow().isoformat(),
        )
def get_accept_language(country_code: str) -> str:
    """Return appropriate Accept-Language for a country."""
    lang_map = {
        "US": "en-US,en;q=0.9",
        "GB": "en-GB,en;q=0.9",
        "DE": "de-DE,de;q=0.9,en;q=0.5",
        "FR": "fr-FR,fr;q=0.9,en;q=0.5",
        "JP": "ja-JP,ja;q=0.9,en;q=0.5",
        "BR": "pt-BR,pt;q=0.9,en;q=0.5",
        "IN": "en-IN,hi;q=0.9,en;q=0.5",
        "IT": "it-IT,it;q=0.9,en;q=0.5",
        "ES": "es-ES,es;q=0.9,en;q=0.5",
    }
    return lang_map.get(country_code, "en-US,en;q=0.9")

多市场监视器

class MultiMarketMonitor:
    """Monitor prices across multiple geographic markets."""
    def __init__(self):
        self.markets = {}
        self.results = []
    def add_market(self, country_code: str, marketplace_url: str,
                   price_selector: str, currency: str):
        """Register a market for monitoring."""
        self.markets[country_code] = {
            "url": marketplace_url,
            "selector": price_selector,
            "currency": currency,
        }
    def monitor_product(self, product_urls: dict[str, str]) -> list[GeoPrice]:
        """
        Monitor a product across all configured markets.
        product_urls: {"US": "https://amazon.com/dp/...", "DE": "https://amazon.de/dp/..."}
        """
        prices = []
        for country, url in product_urls.items():
            market = self.markets.get(country)
            if not market:
                continue
            price = scrape_price_for_region(
                url, country,
                market["selector"],
                market["currency"]
            )
            prices.append(price)
            print(f"  {country}: {price.currency} {price.price}")
            time.sleep(random.uniform(2, 5))
        return prices
    def compare_prices(self, prices: list[GeoPrice], base_currency_rates: dict) -> dict:
        """Compare prices across markets normalized to USD."""
        normalized = {}
        for p in prices:
            if p.price:
                rate = base_currency_rates.get(p.currency, 1.0)
                normalized[p.country] = {
                    "local_price": p.price,
                    "currency": p.currency,
                    "usd_equivalent": round(p.price / rate, 2),
                }
        if not normalized:
            return {}
        usd_prices = [v["usd_equivalent"] for v in normalized.values()]
        cheapest = min(usd_prices)
        most_expensive = max(usd_prices)
        return {
            "prices": normalized,
            "cheapest_market": [k for k, v in normalized.items()
                                if v["usd_equivalent"] == cheapest][0],
            "most_expensive_market": [k for k, v in normalized.items()
                                      if v["usd_equivalent"] == most_expensive][0],
            "price_spread_pct": round(
                (most_expensive - cheapest) / cheapest * 100, 1
            ) if cheapest > 0 else 0,
        }
# Example: Monitor a product across Amazon marketplaces
monitor = MultiMarketMonitor()
# Configure markets
monitor.add_market("US", "amazon.com", "span.a-price-whole", "USD")
monitor.add_market("DE", "amazon.de", "span.a-price-whole", "EUR")
monitor.add_market("GB", "amazon.co.uk", "span.a-price-whole", "GBP")
monitor.add_market("JP", "amazon.co.jp", "span.a-price-whole", "JPY")
# Monitor a specific product
prices = monitor.monitor_product({
    "US": "https://www.amazon.com/dp/B0CHX3QBCH",
    "DE": "https://www.amazon.de/dp/B0CHX3QBCH",
    "GB": "https://www.amazon.co.uk/dp/B0CHX3QBCH",
    "JP": "https://www.amazon.co.jp/dp/B0CHX3QBCH",
})
# Compare prices in USD
comparison = monitor.compare_prices(prices, {
    "USD": 1.0, "EUR": 0.92, "GBP": 0.79, "JPY": 149.5,
})
print(json.dumps(comparison, indent=2))

节点.js 执行

使用 Node.js 多市场监视器 代理哈特节点 SDK。 。 。

const axios = require("axios");
const cheerio = require("cheerio");
const { HttpsProxyAgent } = require("https-proxy-agent");
function getGeoProxy(countryCode) {
  return `http://USERNAME-country-${countryCode}:PASSWORD@gate.proxyhat.com:8080`;
}
const LANG_MAP = {
  US: "en-US,en;q=0.9",
  GB: "en-GB,en;q=0.9",
  DE: "de-DE,de;q=0.9,en;q=0.5",
  FR: "fr-FR,fr;q=0.9,en;q=0.5",
  JP: "ja-JP,ja;q=0.9,en;q=0.5",
};
async function scrapeGeoPrice(url, countryCode, priceSelector, currency) {
  const agent = new HttpsProxyAgent(getGeoProxy(countryCode));
  try {
    const { data } = await axios.get(url, {
      httpsAgent: agent,
      headers: {
        "User-Agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": LANG_MAP[countryCode] || "en-US,en;q=0.9",
      },
      timeout: 30000,
    });
    const $ = cheerio.load(data);
    let priceText = $(priceSelector).first().text().trim();
    let price = parseFloat(priceText.replace(/[^0-9.,]/g, "").replace(",", ".")) || null;
    return {
      country: countryCode,
      price,
      currency,
      url,
      inStock: true,
      scrapedAt: new Date().toISOString(),
    };
  } catch (err) {
    return { country: countryCode, price: null, currency, url, inStock: false, scrapedAt: new Date().toISOString() };
  }
}
async function monitorMultiMarket(productUrls, markets) {
  const results = [];
  for (const [country, url] of Object.entries(productUrls)) {
    const market = markets[country];
    if (!market) continue;
    const result = await scrapeGeoPrice(url, country, market.selector, market.currency);
    results.push(result);
    console.log(`${country}: ${result.currency} ${result.price}`);
    await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));
  }
  return results;
}
function comparePrices(results, rates) {
  const normalized = {};
  for (const r of results) {
    if (r.price) {
      const rate = rates[r.currency] || 1;
      normalized[r.country] = {
        localPrice: r.price,
        currency: r.currency,
        usdEquivalent: Math.round((r.price / rate) * 100) / 100,
      };
    }
  }
  const usdPrices = Object.values(normalized).map((v) => v.usdEquivalent);
  const cheapest = Math.min(...usdPrices);
  const mostExpensive = Math.max(...usdPrices);
  return {
    prices: normalized,
    cheapestMarket: Object.keys(normalized).find((k) => normalized[k].usdEquivalent === cheapest),
    mostExpensiveMarket: Object.keys(normalized).find(
      (k) => normalized[k].usdEquivalent === mostExpensive
    ),
    priceSpreadPct: cheapest > 0 ? Math.round(((mostExpensive - cheapest) / cheapest) * 1000) / 10 : 0,
  };
}
// Usage
const markets = {
  US: { selector: "span.a-price-whole", currency: "USD" },
  DE: { selector: "span.a-price-whole", currency: "EUR" },
  GB: { selector: "span.a-price-whole", currency: "GBP" },
  JP: { selector: "span.a-price-whole", currency: "JPY" },
};
monitorMultiMarket(
  {
    US: "https://www.amazon.com/dp/B0CHX3QBCH",
    DE: "https://www.amazon.de/dp/B0CHX3QBCH",
    GB: "https://www.amazon.co.uk/dp/B0CHX3QBCH",
    JP: "https://www.amazon.co.jp/dp/B0CHX3QBCH",
  },
  markets
).then((results) => {
  const comparison = comparePrices(results, { USD: 1.0, EUR: 0.92, GBP: 0.79, JPY: 149.5 });
  console.log(JSON.stringify(comparison, null, 2));
});

多市场监测战略

货币正常化

为了有意义地比较价格,将所有价格与基准货币正常化。 采用可靠的汇率API(开放汇率,欧洲央行汇率),每日更新汇率. 储存当地价格和正常价格,以便准确分析历史。

税务处理

不同市场的价格包括不同的税收水平:

市场典型税务处理审议情况
美国税前价格实际成本因州而异(0-10.25%)
欧洲联盟价格包括增值税(19-27%)将增值税减作类似比较
联合王国价格包括20%的增值税减去增值税进行净比较
日本价格包括10%的消费税净额比较的减法税

监测时间表

并非所有市场都需要相同的检查频率. 根据业务影响确定优先次序:

  • 主要市场: 你们的主要销售区——每1-2小时检查一次.
  • 扩大目标: 你进入的市场——每4-6小时检查一次。
  • 参考市场: 仅用于基准的市场——每日检查。

探测地球定价战略

通过多市场数据,可以识别竞争对手定价策略:

  • 全球统一定价: 各地价格相同(货币兑换后). 常见于数字产品.
  • 购买力平价调整后的定价: 低收入市场价格下降。 常见于SaaS和软件.
  • 竞争驱动定价: 根据当地竞争压力,价格因市场而异。
  • 成本加定价: 不同的价格反映了不同的航运、仓储和税收成本。
关键外卖:多市场监测揭示单一市场分析所看不到的定价战略。 在一个市场提供30%低价的竞争者,要么是积极扩张,要么是值得调查的不同成本结构。

处理共同挑战

区域方向

一些网站根据IP重新引导用户到区域版本. 有了地理目标代号,你想要这个方向——它需要你去正确的区域定价。 不跟踪跨区域重定向,因为显示IP位置与目标市场不符.

内容差异

产品供应情况因区域而异。 在amazon.com上销售的产品可能不存在在amazon.de上. 处理404个响应 和没有产品 优雅地在你的监测管道。

擦伤

在监视多个区域时,您正在有效刮去多个独立的网站。 应用 避免区块的最佳做法 每个市场独立。 atamazon.com的可行内容可能需要不同的调音. amazon.co.jp.

多市场数据的数据存储

CREATE TABLE geo_price_history (
    id SERIAL PRIMARY KEY,
    product_id VARCHAR(100) NOT NULL,
    country_code VARCHAR(2) NOT NULL,
    local_price DECIMAL(12, 2),
    currency VARCHAR(3),
    usd_equivalent DECIMAL(12, 2),
    exchange_rate DECIMAL(10, 6),
    in_stock BOOLEAN,
    scraped_at TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_geo_price_product_country
    ON geo_price_history (product_id, country_code, scraped_at DESC);
-- Query: Price spread across markets for a product
SELECT
    country_code,
    AVG(usd_equivalent) AS avg_usd_price,
    MIN(usd_equivalent) AS min_usd_price,
    MAX(usd_equivalent) AS max_usd_price
FROM geo_price_history
WHERE product_id = 'B0CHX3QBCH'
  AND scraped_at >= now() - INTERVAL '7 days'
GROUP BY country_code
ORDER BY avg_usd_price;

关键外卖

  • 电子商务价格因地理不同而有很大差异——对一个市场进行监测后发现竞争情况不完全。
  • 以地理为目标的住宅代用品至关重要:利用ProxyHat的国家一级目标获取真实的区域定价.
  • 将价格正常化为基准货币,进行有意义的跨市场比较。
  • 在比较价格时考虑税收差异(包含VAT与税前).
  • 匹配目标国家的 Accept-Langage 信头以获取准确结果 。
  • 按市场重要性优先安排监测频率,优化代理使用.

准备好监测整个市场的价格了吗? 开始 代理哈特的住宅代理 加上195+国家选项,并阅读我们的 电子商务刮刮指南 为整个战略。 关于实时能力,见我们的指南 实时价格监测基础设施。 。 。

准备开始了吗?

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

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