Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesScrape 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.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
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.
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.
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:
Rank #3
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.
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.
- 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.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.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Best Value
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.
Recommended Free Tools
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.
Quick Recap
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.

