DEV Community

Cover image for How to Scrape El Corte Inglés Prices and Discounts with Python
ReventaData
ReventaData

Posted on Originally published at apify.com

How to Scrape El Corte Inglés Prices and Discounts with Python

By the end of this tutorial, you will have a working Python script that extracts catalog listings from Spanish department store El Corte Inglés (elcorteingles.es) into structured JSON: product titles, prices in euros, original prices, discount percentages, brands, GTIN barcodes, and marketplace sellers.

Manual extraction across pages is tedious, while direct, datacenter, and residential requests received an "Access Denied" response in tests conducted on 2026-10-21. Apify Unblocker returned the real category pages.

In this guide, we use Python and the El Corte Inglés Scraper (reventadata/elcorteingles-scraper) Actor on Apify. The sample data cited here comes from a capture dated 2026-10-21 parsed with the Actor's own engine.

⏱️ Time estimate: About 15 minutes.


Prerequisites

To follow this tutorial, you will need:

  1. Python 3.11+ installed on your local machine (apify-client 3.x requires Python 3.11 or newer).
  2. An Apify account to run cloud scrapers and access datasets.
  3. Your Apify API token, which you can find under API & Integrations in Apify Console.

Install the official Apify API client library:

pip install -U "apify-client~=3.0"
Enter fullscreen mode Exit fullscreen mode

Next, export your API token as an environment variable in your terminal session:

export APIFY_API_TOKEN="your_apify_token_here"
Enter fullscreen mode Exit fullscreen mode

What you'll achieve

By completing this tutorial, you will extract structured product records from El Corte Inglés category listings directly into clean JSON datasets. Each record captures:

  • Identifiers: Internal product code (A prefix for retail stock, MP_ for marketplace items), canonical URL, and GTIN barcode.
  • Pricing: Current offer price in EUR, original reference price, calculated discount percentage, and discount amount.
  • Merchandising: Brand name, breadcrumb categories, colour variant counts, and new arrival flags.
  • Vendor identification: Explicit seller name and a boolean flag indicating whether the item is fulfilled by a third-party marketplace seller.

Example use case: Suppose you want to monitor footwear discounts across Spanish retail. By pointing the Actor at the women's shoes category, you can isolate products discounted by 25% or more and differentiate direct retail stock from third-party marketplace partners.


Step 1: Access El Corte Inglés Scraper

Start by heading over to the El Corte Inglés Scraper page on the Apify Store.

From the Actor store page, you can review available parameters, sample output schemas, and documentation. You can test runs directly inside the Apify Console workspace or integrate them programmatically into your Python projects. In this guide, we will automate everything through the Python API client.


Step 2: Configure category URLs

The primary input for this Actor is categoryUrls. You provide one or more category listing URLs from elcorteingles.es, such as https://www.elcorteingles.es/electronica/moviles-y-smartphones/ or https://www.elcorteingles.es/moda-mujer/zapatos/.

The site's robots.txt disallows internal search result paths (/search-nwx/, /*/search) and parameterised filter URLs (such as brand:: or price::). To respect site rules, the Actor refuses query strings and search paths up front. It fetches clean category paths and applies all your brand, price, and discount filters post-fetch.

In your Python script, initialize ApifyClient and define your target category and page limits:

import os
from apify_client import ApifyClient

# 1. Initialize ApifyClient with the token from the environment
client = ApifyClient(os.environ["APIFY_API_TOKEN"])

# 2. Configure El Corte Inglés category URL: 2 pages, up to 24 items
run_input = {
    "categoryUrls": [
        "https://www.elcorteingles.es/electronica/moviles-y-smartphones/"
    ],
    "maxPagesPerCategory": 2,
    "maxItems": 24,
}
Enter fullscreen mode Exit fullscreen mode

Each category page displays 12 products. Setting maxPagesPerCategory: 2 instructs the crawler to process at most two consecutive listing pages (up to 24 products).


Step 3: Configure optional settings and filters

El Corte Inglés Scraper supports comprehensive post-fetch filtering. Because URL query parameters are disallowed by the site, filters are evaluated locally within the Actor:

Parameter Type Default Description
categoryUrls array Required List of category page URLs on elcorteingles.es. Query strings and search paths are disallowed.
maxItems integer 100 Total products to save across all requested categories before stopping.
maxPagesPerCategory integer 50 Maximum pages to read per category (12 products per page, capped at the site ceiling of 833 pages).
minPrice & maxPrice number None Price boundaries in EUR. Products without prices are excluded when set.
onlyDiscounted boolean false When set to true, keeps only products where an original price is present.
minDiscountPercent integer None Minimum percentage discount required (at least 1).
brands array [] List of brand names to retain, matched case- and accent-insensitively.
sellerType string "any" Filter by vendor: "any", "elcorteingles" (direct retail), or "marketplace" (third-party).
includeKeywords array [] Retain only items whose name, brand, or category contains all specified words.
excludeKeywords array [] Drop items matching any of these keywords.
proxyConfiguration object Unblocker Defaults to Apify Proxy with the Unblocker group to ensure reach through bot mitigation.

Pro Tip on Budget Caps: maxItems acts as an absolute ceiling across your run. Even if you supply multiple categories, the crawler halts immediately once maxItems records have been stored in your dataset.


Step 4: Run the Actor

With your configuration dictionary ready, trigger the execution using the Apify Python client:

# 3. Start the Actor run and wait for it to finish
print("Starting El Corte Inglés extraction...")
run = client.actor("reventadata/elcorteingles-scraper").call(run_input=run_input)
if run is None or run.status != "SUCCEEDED":
    status = run.status if run else "unknown"
    raise SystemExit(f"Run did not succeed (status: {status}).")

# 4. Fetch the saved products
items = client.dataset(run.default_dataset_id).list_items().items
print(f"Retrieved {len(items)} products.\n")
Enter fullscreen mode Exit fullscreen mode

Behind the scenes, the Actor accesses each category URL using Apify Unblocker. Category pages render an inline state object (window.__MOONSHINE_STATE__) holding product data. The Actor parses this state, joins product details with data layer attributes, applies your filters, and streams structured rows into your default dataset.


Step 5: View and download results

Once execution finishes, iterate through your dataset items to display the extracted product information:

for item in items:
    print(item["name"])
    print(f"  Brand: {item.get('brand')} | Seller: {item.get('seller')} | Marketplace: {item.get('isMarketplace')}")
    print(f"  Price: {item.get('price')} {item.get('currency')} | Original: {item.get('originalPrice')}")
    print(f"  Discount: {item.get('discountPercent')}% | On sale: {item.get('onSale')}")
    print(f"  Barcode: {item.get('gtin')} | Status: {item.get('status')}")
    print(f"  {item['url']}")
    print("-" * 40)
Enter fullscreen mode Exit fullscreen mode

The sample record below represents a real product captured from page 16 of /moda-mujer/zapatos/, parsed with the Actor's own engine from a verbatim fixture dated 2026-10-21:

{
  "id": "MP_0623819_252BZ131810522",
  "name": "Zapatillas deportivas de mujer retro 13 18 con cordones Marrón",
  "brand": "Bimba y Lola",
  "url": "https://www.elcorteingles.es/moda-mujer/MP_0623819_252BZ131810522-marron-pr-zapatillas-deportivas-de-mujer-retro-13-18-con-cordones/",
  "image": "https://dam.elcorteingles.es/producto/www-8445394427095-00.jpg",
  "gtin": "8445394427149",
  "price": 68.6,
  "currency": "EUR",
  "originalPrice": 98.0,
  "discountPercent": 30,
  "discountAmount": 29.4,
  "onSale": true,
  "category": "Moda mujer > Zapatos > Zapatillas > Zapatillas deportivas",
  "categories": [
    "Moda mujer",
    "Zapatos",
    "Zapatillas",
    "Zapatillas deportivas"
  ],
  "seller": "BIMBA & LOLA",
  "isMarketplace": true,
  "colourCount": 1,
  "status": "ADD",
  "isNew": false,
  "categoryPath": "/moda-mujer/zapatos/",
  "page": 16,
  "position": 1
}
Enter fullscreen mode Exit fullscreen mode

In addition to these fields, records saved during live runs carry a scrapedAt ISO 8601 timestamp added automatically when pushed to the dataset.


Understanding your results

Every item saved in the dataset provides rich commercial attributes extracted directly from the page state:

  • Product identifiers (id, gtin): The id clearly reflects product origin. Retail inventory sold directly by El Corte Inglés begins with A followed by digits (such as A200977771), whereas marketplace inventory uses the format MP_<seller>_<sku> (such as MP_0623819_252BZ131810522). The gtin barcode allows cross-referencing items against external retail catalogs.
  • Accurate price tracking (price, originalPrice, discountPercent): When an item is discounted, onSale evaluates to true, and both originalPrice and discountPercent are populated. In our sample shoe capture from page 16, 9 out of 12 items carried discounts ranging from 16% to 31%. Non-discounted items retain null for original price and discount values.
  • Seller transparency (seller, isMarketplace): The seller field provides the registered commercial name of the merchant (such as "El Corte Ingles, S.A.", "BIMBA & LOLA", or "GIOSEPPO"). Setting sellerType to "marketplace" or "elcorteingles" lets you separate direct store stock from independent retailers.
  • Taxonomy and availability: categories provides full hierarchical navigation breadcrumbs, while status indicates ordering availability (such as ADD or RESERVE).

Pro tips

Here are five practical recommendations for optimizing your El Corte Inglés scraping workflows:

  1. Provide clean category paths: Always supply canonical paths like /moda-mujer/zapatos/. Do not append query strings, filter parameters, or search paths: the Actor refuses them before starting, and robots.txt disallows search and filter URLs.
  2. Understand the 833-page ceiling: El Corte Inglés enforces a hard ceiling of 833 pages per category (12 products per page, yielding 9,996 total products). Requests for page 834 return HTTP 404. For large categories, configure maxPagesPerCategory accordingly.
  3. Use post-fetch discount filtering: If your goal is deal monitoring, set onlyDiscounted: true or define minDiscountPercent: 20. Rows dropped by filters are discarded before storage, keeping your dataset focused on genuine bargains.
  4. Leverage GTIN for cross-store price comparison: Use the extracted gtin values to link El Corte Inglés products to competitors across European retail datasets without relying on fuzzy title matching.
  5. Schedule recurring runs: Automate runs through Apify Schedules (for example, using a cron expression like 0 8 * * * for daily morning sweeps) to monitor price fluctuations over time.

Troubleshooting

When building your extraction pipeline, keep these common issues and solutions in mind:

  • ValueError on a category URL: The Actor refuses URLs with search segments (like /search/ or /search-nwx/), filter parameters (brand::), or query strings (?), each rejected before any request is made. Strip the URL down to the base category path.
  • RuntimeError: 0 rows for categories...: The Actor intentionally fails when zero records are saved. Check whether your filter criteria (such as restrictive brand names, high minimum discounts, or narrow price bands) filtered out all candidate items.
  • Fewer rows than requested: If the category has fewer items than your maxItems target, the Actor stops at the last page once the product grid is exhausted.
  • Checking logs: Inspect logs via Apify Console or retrieve them with client.log(run.id).get(). Each page logs its product count, and the final line tallies the filter rejections.

Next steps

Now that you have automated El Corte Inglés data extraction, you can integrate your dataset into wider automated workflows. You can configure Apify Webhooks to notify your backend when an extraction completes, or export datasets from Apify Console in JSON, CSV, or Excel.

For current pricing and details, see the Store page.

What categories on El Corte Inglés are you planning to extract? Drop a comment below! 💬

Top comments (0)