Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Scrape each product offer as a market-specific record, not as a price attached only to a product name. Keep the country, source URL, language, price, currency, availability, condition, and any displayed shipping destination or cost with every offer. First check for a supported feed, API, or structured product data; scrape the rendered table only when those sources do not meet your needs.

This distinction matters because the same product may have different prices, currencies, availability, and delivery terms in different markets. A price without its currency and market is not reliably comparable.

Define what counts as an offer before collecting data

“Product price” can refer to a store’s displayed price, a particular seller’s listing, or a checkout price for a specified destination. Those values need not be the same. Decide which one you want before writing a scraper, and record the evidence the page actually exposes rather than treating a displayed price as a checkout-verified total.

Make a market matrix for the countries you intend to cover. Include each storefront or localized URL, target country, expected language, and expected currency. Decide whether you need shipping and tax information, product condition, seller identity, and availability. Google’s Merchant Center localization guidance ties target-country setup to language, currency, delivery information, and taxes: target countries and localization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep product identity separate from offer identity. A product may have several market-specific URLs or offers. Use an observed SKU or GTIN when available, but do not merge records solely because their translated titles look alike.

Choose the least brittle source you can use

Before parsing a visible offer table, look for a documented data source and compare its market coverage and fields with what you need. Google supports product structured data and product feeds; eBay and Shopify document feed or API mechanisms for product and market data. A feed or API may avoid layout parsing, but it is not automatically complete or current for your particular markets.

Source What to check When it fits
Documented feed or API Market and language coverage, fields, update mechanism, access conditions, and whether it represents the offer you intend to compare. When a supported source covers your target markets and required fields.
Structured product data Whether the page exposes product and offer data, including price, currency, availability, and shipping details where applicable. When the page’s markup provides useful offer fields and you can validate them against the localized page.
Rendered offer table Market-specific URL, page state, localization, dynamic loading, and the stability of the table’s markup. When no suitable feed, API, or structured data source supplies the fields you need.

Google’s product snippet guidance describes Product and Offer markup for a single product or its variants, rather than a general category listing, and recommends distinct URLs when a product is offered in multiple currencies: product snippet guidance. Google also describes structured data and product feeds as ways to provide product information: product structured data. For a category page containing many items, do not assume its markup is equivalent to a dedicated product page’s Offer data.

The documented schemas illustrate why field checks matter: Google’s Offer properties include price, priceCurrency, and availability, with three-letter ISO 4217 currency codes; its shipping information can include a destination country. eBay’s product feed schema includes price, marketplace currency, availability, condition, and item URL. Shopify describes country-specific prices through Markets and country/language localization objects. WooCommerce’s documented feed configuration can create feeds by country, language, and currency combination, and excludes products missing the market language translation from that market feed. Amazon’s Creators API locale reference describes marketplace locale and currency awareness for some item-price response elements; that describes its API localization design, not whether it is an appropriate general-purpose source for your use case.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build a market-aware record model

Store one row per observed offer, not one row per product with an ambiguous price column. Preserve the original values before parsing or normalizing them. The following fields are useful starting points:

  • Identity: your product key, observed SKU or GTIN if present, and the source’s product or seller identifier where available.
  • Market context: country or marketplace, language or locale, and the exact URL observed.
  • Offer values: original displayed price text, parsed numeric price, ISO 4217 currency code, availability label, condition, and shipping destination and cost when exposed.
  • Collection trace: retrieval timestamp and parser version. These are implementation recommendations: they help you distinguish changed source data from a changed extraction method.

Keep raw and derived values side by side. For example, store a page’s original “1.234,56 €” string as well as a parsed number and its currency code. A parsed number alone loses the locale clues needed to catch a mistaken decimal or thousands separator. Likewise, retain the original availability label instead of silently reducing every source’s wording to “in stock” or “out of stock.”

A practical row might look like this:

{
  "product_key": "observed-sku-123",
  "market": "DE",
  "language": "de-DE",
  "source_url": "https://shop.example/de/item-123",
  "price_text": "1.234,56 €",
  "price_value": 1234.56,
  "currency": "EUR",
  "availability_text": "Auf Lager",
  "condition": "new",
  "shipping_destination": "DE",
  "shipping_cost_text": null,
  "retrieved_at": "2026-09-29T12:00:00Z",
  "parser_version": "1"
}

The example illustrates a schema only; it is not a claim about a real store or page. Use null or a separate “not exposed” status when the page does not provide a field. Do not invent a shipping charge or infer one from another country’s page.

Scrape a rendered offer table with Python

If you must read a rendered page, use its exact localized URL and a market-specific parser. This compact example requests a page, reads a conventional HTML table with pandas, and adds market context. It is intentionally a starting point: replace the table selector and column names for the source you are allowed to access, and verify whether JavaScript rendering or a documented source is preferable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import pandas as pd
import requests
from bs4 import BeautifulSoup

url = "https://shop.example/de/offers"
market = "DE"
language = "de-DE"

response = requests.get(
    url,
    headers={"User-Agent": "OfferResearchBot/1.0 contact: [email protected]"},
    timeout=30,
)
response.raise_for_status()

soup = BeautifulSoup(response.text, "html.parser")
table = soup.select_one("table#offers")  # Replace with the inspected table selector.
if table is None:
    raise RuntimeError("Offer table not found; verify the URL and page markup")

df = pd.read_html(str(table))[0]
df["market"] = market
df["language"] = language
df["source_url"] = response.url
print(df.to_json(orient="records", force_ascii=False, indent=2))

Install the dependencies with python -m pip install requests beautifulsoup4 pandas lxml. A successful HTTP response does not prove you received the intended localized page: redirects, consent screens, bot checks, or an alternate locale can produce valid HTML with no offer table. Inspect the response URL and page content, then fail clearly rather than saving an empty or misleading dataset.

Extract structured data when it is present

For a product page, inspect JSON-LD blocks for Product and Offer values before falling back to visible text. A basic inspection step is:

import json

for script in soup.select('script[type="application/ld+json"]'):
    try:
        data = json.loads(script.string or script.get_text())
    except json.JSONDecodeError:
        continue
    print(data)

Structured data may be a list, a graph, a product with multiple offers, or incomplete for your use case. Traverse those shapes deliberately; do not assume the first JSON object is the sole offer. Compare extracted fields with what a visitor sees on that exact market page.

Handle client-rendered tables deliberately

If the table is absent from the returned HTML but appears in a browser, determine whether the site documents an API or feed before automating a browser. If browser rendering is necessary and permitted, wait for the specific offer element rather than sleeping an arbitrary long interval. Record which selector or readiness condition was used so markup changes can be diagnosed.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Normalize cross-country values without losing meaning

Parse numbers according to the page locale, not the machine running the scraper. In many locales a comma separates decimals; in others it separates groups of thousands. Keep the original formatted value and attach an explicit currency code to every numeric amount. Never compare raw values such as 1000 and 900 as though they share a unit when one is EUR and one is USD.

If you need a common-currency comparison, create a derived field rather than overwriting source prices. Record the conversion rate source and date, and state whether the comparison includes taxes and shipping. Do not silently treat tax-inclusive and tax-exclusive prices as equivalent. Google’s target-country guidance addresses localized price, currency, delivery, and tax requirements; those differences can affect whether two displayed amounts are comparable.

Availability and shipping are market-dependent too. An in-stock label or shipping rate observed on one country page should not be copied to another. Preserve the source wording and destination for delivery details. If the page does not expose a field, mark it as unavailable or not stated in your own data model.

Validate the result in every market

Run a small validation sample for each country and language before a full collection. Compare records with the localized page or feed and check:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • The response URL remains the expected market URL rather than redirecting to a default storefront.
  • Currency codes are present and agree with the displayed price.
  • Locale parsing handles decimal and thousands separators correctly.
  • Availability, condition, and shipping values match the source’s actual wording and destination.
  • Multiple sellers or product variants are represented as separate offers where appropriate.
  • Rows are not duplicated, empty, stale, or accidentally generated from a consent or bot-check page.
  • A parser change is distinguishable from a change in the page’s underlying offer data.

Repeat validation after a source redesign or a parser update. These checks are operational safeguards, not a guarantee that a site will keep the same markup or update cadence.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Permission, reliability, and operating cost

Before collecting from a particular site, assess its terms, robots directives, access controls, and the laws applicable to your activity and jurisdictions. These conditions vary; no general statement here establishes that scraping a given site is permitted. Prefer documented feeds and APIs when they offer the fields and access model you need.

Plan for ordinary failures: timeouts, transient server errors, redirects, missing tables, and rate limits. Use bounded retries with backoff for transient failures, but do not turn retries into a way to evade access controls. Log the URL, market, response status, retrieval time, and parser version. Separate failed retrievals from legitimate “no offer shown” records so downstream comparisons do not mistake missing data for zero price or out of stock.

There is no universal scraping accuracy, speed, or cost figure established for this workflow. Actual effort depends on source count, page rendering, market variation, validation needs, and the reliability of feeds or markup. Measure your own collection’s failure and change rates, and budget time for maintaining parsers as well as running them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your remaining task is to capture a localized page for visual checking, ScreenshotNeo can return a screenshot or PDF with one GET request. A screenshot is useful for auditing what the page displayed; it is not a substitute for extracting structured offer rows, currency codes, or shipping fields. Its cookie/consent handling can accept banners and remove 60+ known consent platforms, newsletter popups, and chat widgets before capture, with each step optional. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses report the page verdict and billing status. Its MCP server provides screenshot tools for AI agents, and the API supports options such as full-page capture, CSS selectors, custom headers, cookies, waits, PDF output, and bulk capture.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://shop.example/de/offers -o offer-page.webp

See the ScreenshotNeo API documentation for authentication and request options. The same endpoint can be called from Python or Node.js:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://shop.example/de/offers"},
    timeout=90,
)
open("offer-page.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://shop.example/de/offers'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('offer-page.webp', new Uint8Array(await res.arrayBuffer()));

ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. Its free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for the free plan.

Frequently Asked Questions

How do I compare product prices in different countries?

Compare only after each price is paired with its market, currency, and any relevant tax and shipping context; preserve the original amount and record conversion details for derived comparisons.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I scrape prices in different currencies?

Collect each localized URL separately, preserve its displayed price text, and store the parsed number with an explicit ISO 4217 currency code.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.