1. 2scraper
  2. E-commerce & retail
  3. MediaMarkt
Open source · MITNeeds a residential exit or the Scraping Browser API

MediaMarkt Scraper

Category grids, search results and product pages from ten MediaMarkt country sites — prices, RRP, 30-day low and EAN.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
mediamarkt-scraper
# Category grid
$ python3 playwright_scraper.py --url "https://www.mediamarkt.de/de/category/grills-116.html" --pages 3
✓ 5 sample rows · 22 columns in sample_output.json
10country sites, all live-verified (Sep 2026)
2modes: listing and product
100%rows confirmed against the rendered tile in live runs (Sep 2026)
$0.0005per page via the Scraper API with a residential exit (Sep 2026)
Available MediaMarkt scrapers

What the MediaMarkt scraper collects

Scrapes MediaMarkt category grids, search results and product pages across the group's ten country sites. Prices come from structured data confirmed against the rendered tile, with the RRP and the EU 30-day lowest price kept in separate columns; product mode adds brand, EAN, description and the full image list. Output is JSON or CSV plus a run-metadata sidecar.

Category grid

Input: A leaf category URL

One row per product, twelve per page: title, price, currency, RRP, discount, 30-day low, rating, review count and stock, paginated with ?page=N.

Search results

Input: A MediaMarkt search URL

The same row schema for search results, which paginate the same way as categories.

Product page

Input: A MediaMarkt product URL

One row with everything from a listing plus brand, EAN, description and the full image list.

Quick start

From zero to MediaMarkt data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/mediamarkt-scraper
    $ cd mediamarkt-scraper
    $ pip install -r requirements.txt -r requirements-playwright.txt
    $ playwright install chromium
    $ python3 smoke_test.py
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --url "https://www.mediamarkt.de/de/category/grills-116.html" --pages 3
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

MediaMarkt data fields

22 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
skuMediaMarkt article number
titleProduct title
urlProduct page URL
priceCurrent price as a number
currencyISO currency: EUR, CHF, PLN, HUF or TRY depending on the site
original_priceManufacturer's recommended price (UVP/RRP) when shown
discount_pctDiscount computed from price and original_price; null with no RRP
lowest_price_30dThe EU-mandated lowest price of the last 30 days, kept apart from the RRP
ratingStar rating; null for unrated products rather than 0
review_countNumber of reviews
in_stockAvailability
price_sourcejsonld+dom when structured data and the tile agree, jsonld or dom otherwise
categoryCategory from the URL
brandBrand (--mode product; listings publish none)
eanEAN barcode (--mode product)
imagesFull image list (--mode product)
[
  {
    "source": "mediamarkt.de",
    "scraped_at": "2026-09-09T09:32:33.779503+00:00",
    "url": "https://www.mediamarkt.de/de/product/_gorenje-rk518e2s4-kuhlgefrierkombination-e-269-l-…",
    "sku": "3047256",
    "title": "GORENJE RK518E2S4 Kühlgefrierkombination (E, 269 l, 1800 mm hoch, Silber)",
    "brand": null,
    "price": 279.0,
    "currency": "EUR",
    "original_price": 459.0,
    "discount_pct": 39.2,
    "rating": 4.2,
    "review_count": 5,
    "in_stock": true,
    "image_url": "https://assets.mmsrg.com/isr/166325/c1/-/ASSET_MMS_180626469",
    "category": "kühlen-gefrieren",
    "price_source": "jsonld+dom",
    "page": 2,
    "position": 1,
    "lowest_price_30d": null,
    "ean": null,
    "description": null,
    "images": null
  },
  {
    "source": "mediamarkt.de",
    "scraped_at": "2026-09-09T09:32:29.335391+00:00",
    "url": "https://www.mediamarkt.de/de/product/_koenic-kfk-631-1-c-in-kuhlgefrierkombination-c-14…",
    "sku": "2882323",
    "title": "KOENIC KFK 631-1 C IN Kühl-Kombi statisch (C, 315 l, 185,5 cm hoch, Edelstahl)",
    "brand": null,
    "price": 349.0,
    "currency": "EUR",
    "original_price": null,
    "discount_pct": null,
    "rating": 4.5966,
    "review_count": 119,
    "in_stock": true,
    "image_url": "https://assets.mmsrg.com/isr/166325/c1/-/ASSET_MMS_167152757",
    "category": "kühlen-gefrieren",
    "price_source": "jsonld+dom",
    "page": 1,
    "position": 1,
    "lowest_price_30d": 299.0,
    "ean": null,
    "description": null,
    "images": null
  }
]

First 2 of 5 rows from a real run — sample_output.json. Long values shortened here.

Built for MediaMarkt

Handles what breaks naive MediaMarkt scrapers

RRP and 30-day low told apart

MediaMarkt renders two struck-through prices that mean opposite things: the RRP above the price, and the EU 30-day lowest price usually below it. They get separate columns, so no row reports a negative discount.

German round prices parsed

Prices like "349,– €", percent badges written before the number in Turkish, split euro and cent nodes, and instalment lines inside the price block are all handled, and pinned by offline tests on real captures.

Refusals told apart from empty categories

A 403 refusal is MediaMarkt's own branded error page with no vendor markers; it is detected by status and by the absence of the shop's own assets. A hub category with no grid is exit 4, a correct empty answer, not a block.

Every row confirmed against its tile

Structured prices are checked against the rendered tile and recorded in price_source, and diff_runs.py reports a price difference that comes with a source change as source_changed, not as a price change.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete MediaMarkt snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with MediaMarkt data

Consumer electronics price monitoring

Track prices, RRP discounts and 30-day lows for categories or search queries across MediaMarkt's European sites.

Cross-country price comparison

Compare the same products on mediamarkt.de, .at, .nl, .es, mediaworld.it and five more sites, in EUR, CHF, PLN, HUF and TRY.

Product catalogue enrichment

Use --mode product to collect brand, EAN, description and image lists for matching against your own catalogue.

Promotion and compliance checks

Watch how advertised discounts relate to the published 30-day lowest price over time.

Access & pricing

Free to run. Pay only for what the site requires.

Needs a residential exit or the Scraping Browser API

MediaMarkt refuses every datacentre and VPN address with HTTP 403 (measured Sep 2026), so a residential exit is required, and it should be in the site's own country: one German address was refused by seven of the ten sites. Residential proxies are therefore the requirement, not an optimisation; the Scraping Browser API gives the same thing as one endpoint with a chosen country. The refusal page carries no captcha, so captcha solving is not what gets you in here. With a residential exit, the 2Captcha Scraper API is the cheapest path at about $0.0005 a page.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • A residential exit in the site's own country is required; datacentre addresses get 403.
  • brand and ean are only filled by --mode product.
  • --concurrency is available in the Playwright engine only.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

MediaMarkt scraper FAQ

Why do I get exit 3 on every page?

MediaMarkt refuses datacentre, VPS, CI and most VPN addresses. Use a residential proxy or the Scraping Browser API, with an exit in the country of the site you are reading.

Which MediaMarkt countries are supported?

Ten: mediamarkt.de, .at, .ch, .nl, .be, .es, .pl, .hu, .com.tr and mediaworld.it. mediamarkt.lu runs on a different platform and Saturn is unverified, so both are refused with that reason.

Why does a category return zero products?

Some MediaMarkt categories are hubs that list sub-categories and have no product grid. That is exit 4, a correct answer; pick a leaf category.

Why is brand null on listing rows?

MediaMarkt's listing tiles and JSON-LD publish no brand. --mode product reads the brand and the EAN from the detail page.

How does pagination work?

Twelve products per page, addressed directly with ?page=N. The run stops when a page adds no new product, and --concurrency can fetch pages in parallel with a proxy pool.

Is scraping MediaMarkt legal?

It reads publicly rendered product listings and nothing behind an account. Public data scraping is generally lawful, but follow MediaMarkt's terms, robots.txt and the law where you operate.