druni.es - Prices, Ofertas Flash, Variants & Reviews avatar

druni.es - Prices, Ofertas Flash, Variants & Reviews

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
druni.es - Prices, Ofertas Flash, Variants & Reviews

druni.es - Prices, Ofertas Flash, Variants & Reviews

Scrape Druni beauty, cosmetics and perfume products. Search by keyword, category, Ofertas Flash deals or paste product and listing URLs. Extract prices, original prices, discounts, images, product details, and format or colour variants with individual prices and availability.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Druni Scraper: Prices, Ofertas Flash Deals, Variants and Reviews

Druni Scraper turns Druni (druni.es), a Spanish beauty and perfumery retailer, into structured product data. Search by keyword, browse a real Druni catalog category, or pull the site's own Ofertas Flash discount feed, or paste product and listing links directly. Listing-derived records include the current price, the strike-through original price with computed discount when a product is marked down, and format or colour variants with their own price and availability when you ask for full detail, plus the product's own rating and recent reviews. Export to JSON, CSV, or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Was-price and discount, structured, not scraped from a badge. Search, category, and Ofertas Flash listings return the current price alongside the strike-through original price, plus the computed discount amount and percentage, whenever a product is marked down.
  • Ofertas Flash, first class. A specialsOnly toggle keeps only currently marked-down products, the site's real markdown signal, not a guessed category. With no keyword or category set, this browses Druni's own live Ofertas Flash feed directly; with a keyword or category, it filters that search down to the marked-down items within it.
  • Format and colour variants. Perfumes, creams and similar products return every size (for example 20ML/30ML/50ML/100ML) or shade as its own variant, each with its own price and availability, plus a computed unit price per 100 ml/g where the pack size is a single unambiguous value.
  • Reviews straight from the product page. Overall rating, review count, and the product's own most recent reviews (author, date, rating, body), not a third-party review vendor.
  • Two ways in. Keyword or category search with real site filters (brand, price range, Ofertas Flash, sort), or paste any product or listing link and continue pagination automatically.
  • Resume and recurring updates. Continue one interrupted run without paying twice, or turn on Incremental mode to get only new and changed products on a scheduled re-run of the same search.
  • Optional export to your apps. Send results into Notion, Linear, Airtable, or any Apify MCP connector alongside the dataset.

Use Cases

  • Price and discount monitoring: track Ofertas Flash markdowns and was-price changes on the products or categories you care about, and get alerted only when something actually changes.
  • Catalogue and marketplace enrichment: pull structured brand, category, format, and pricing data to enrich a retailer or marketplace listing.
  • Review and reputation research: collect rating and review trends for personal-care products across brands and categories.
  • Competitive and market research: compare pricing, discount depth, and pack-size economics (unit price per 100 ml/g) across brands.
  • Deal-hunting tools and bots: build a feed of currently discounted products straight from Druni's own Ofertas Flash taxonomy.

Data You Get

FieldExample
productId / sku845210
name"Sample Hydrating Night Cream"
brand"SAMPLE BRAND CARE"
category / categoryPath"Cosmética Corporal", ["Druni", "Cosmética", "Cuidado Facial", "Cosmética Corporal"]
url"https://www.druni.es/sample-hydrating-night-cream-sample-brand-care"
price / currency18.75, "EUR"
originalPrice / discountAmount / discountPercent24.99, 6.24, 25.0
isOnSpecialtrue
onlineAvailabletrue
image / images["https://www.druni.es/media/catalog/product/sample/sample-night-cream.jpg"]
descriptionfull product description text
variants[{"sku": "845211", "name": "Sample Hydrating Night Cream 50G", "size": "50G", "price": 18.75, "currency": "EUR", "onlineAvailable": true, "unitPrice": 37.5, "unitPriceBasis": "100 g"}]
rating / reviewCount4.4, 57
reviews.averageRating / reviews.totalReviewCount4.4, 57
reviews.items[][{"rating": 4, "body": "Sample review text.", "author": "Usuario verificado", "date": "2026-03-18"}]

Sample shape: values above are illustrative placeholders, not from a live product.

category/categoryPath and the current-price fields above come from two different places depending on how a product was reached. A record found through a keyword or category search carries category from the search index itself. A record reached by pasting a category or Ofertas Flash listing link, or by browsing the Ofertas Flash feed without a keyword/category, only gets category/categoryPath once Fetch full product detail is also on. A record reached by pasting a single product link never carries a top-level price/currency/originalPrice/isOnSpecial/onlineAvailable at all: pricing and availability for that path live only inside each entry of variants, or are absent entirely for a product with no declared size/colour variants. When incrementalMode is on, every returned record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED), changedFields (non-empty only for UPDATED), firstSeenAt, and lastSeenAt. Change detection is based on every field the record carries except the nested reviews.items list itself, which is deliberately excluded, since the product page only ever surfaces the site's most-recent 10 reviews, so a brand-new review silently pushes an older one out of that window without the product itself having changed. In practice this means rating and review count only affect change detection when they're actually present as top-level fields, which needs Fetch full product detail on (or a pasted single product link); on a default search or category run with detail off, rating lives only inside the excluded reviews object, so a rating or review-count change alone never turns the product UPDATED there. unitPrice/unitPriceBasis are computed by this scraper (price divided by that variant's own pack size) only when the size is a single unambiguous value, and are left empty otherwise rather than guessed, since Druni does not display a per-unit price itself.

How to Use

  1. Pick a mode: search (keyword and/or a real Druni category, plus Ofertas Flash) or url (paste product, category, or Ofertas Flash listing links).
  2. Fill in the fields for that mode, and switch on Fetch full product detail and/or Fetch reviews for more than identity and price.
  3. Set Max products total (and Max pages per search for a hard page cap) to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Keyword search, first page, default settings:

{
"mode": "search",
"searchTerm": "perfume mujer",
"maxItems": 20
}

Keyword search, only currently marked-down items, sorted by price:

{
"mode": "search",
"searchTerm": "crema",
"specialsOnly": true,
"sortBy": "PRICE_ASC",
"maxItems": 20,
"maxPages": 5
}

Full product detail and reviews for a pasted product link:

{
"mode": "url",
"urls": ["https://www.druni.es/my-devotion-dolce-gabbana-eau-parfum-intense-mujer"],
"fetchDetails": true,
"fetchReviews": true
}

Paste the Ofertas Flash listing and keep paginating forward:

{
"mode": "url",
"urls": ["https://www.druni.es/ofertas-flash"],
"maxItems": 100,
"maxPages": 10
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/druni-es-scraper").call(run_input={"mode": "search", "searchTerm": "perfume mujer", "maxItems": 20})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["name"], product["price"], product["currency"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/druni-es-scraper').call({ mode: 'search', searchTerm: 'perfume mujer', maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

How Max pages and Max products shape a run

Max products total (maxItems) counts products returned, not pages scanned. Max pages per search (maxPages) caps result pages per search/category/URL entry; 0 or empty walks every page. Left unlimited, a walk stops naturally once a page repeats what the walk already found, once the site's own listing signals a short/last page, or once the page comes back empty; it never grinds on past the real end of a search or listing.

Resume and recurring updates

Resume (resumeFromRunId) continues one specific interrupted or previous run: paste a run ID or dataset ID and this run skips products already collected there, returning only the remaining new products, whether they came from a search, a category, or a pasted link.

Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return NEW and UPDATED products by default; unchanged products are suppressed and not billed unless emitUnchanged is on. REAPPEARED and EXPIRED are a pair: a product is only ever reported EXPIRED once a run has fully scanned the tracked search (not capped by Max products/Max pages, not a Resume run) with emitExpired on, and only then does a later sighting of that same product come back as REAPPEARED. Turning emitExpired on for a search is therefore what starts expiry and reappearance tracking for it; leaving it off means a product that truly disappears and comes back will simply read as UPDATED or UNCHANGED like any other product, never REAPPEARED.

Cap note. maxItems counts products returned, not products scanned. On an incremental run that suppresses most products as UNCHANGED, the walk keeps going past the suppressed ones to backfill the quota with unseen or changed products, so a capped quiet run does not by itself mean the bill drops to near zero (a suppressed row is never billed regardless of the cap). The real reason to leave maxItems at 0 (unlimited) is EXPIRED detection, which requires a run that reaches the natural end of the search without ever hitting the cap; a capped run, quiet or not, never counts as a complete scan.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the mcpConnectors field. Each connector receives a condensed, human-readable summary per product (name plus key fields), while the complete record always stays in the Apify dataset. For Notion, set notionParentPageUrl to the page the item pages should be created under, and use maxNotifyListings to cap how many items are exported per connector per run. Supported connectors: Notion, Linear, Airtable, and Apify. Leave the field empty to skip; it never changes the dataset output.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch or url.
searchTermstring(none)Keyword (search mode only). Prefilled with perfume mujer as a starting example, not a real default.
categorystring(none)A real druni.es catalog category, e.g. Fragancias Femeninas (search mode only).
sortBystringRELEVANCERELEVANCE, PRICE_ASC, or PRICE_DESC (search mode only).
urlsarray(none)Product, category, or Ofertas Flash listing URLs to scrape (url mode only). Prefilled with the Ofertas Flash feed link as a starting example, not a real default.
specialsOnlybooleanfalseKeep only currently marked-down products (search and url mode). With no keyword or category set, this browses Druni's own Ofertas Flash feed directly; with a keyword or category, it filters that search down to the marked-down items within it.
brandsarray(none)Exact brand names to keep (search and url mode). Prefilled empty.
minPricenumber(none)EUR price band, lower bound (search and url mode). A record reached by pasting a single product link has no top-level price, so it is filtered out whenever this is set.
maxPricenumber(none)EUR price band, upper bound (search and url mode). Same caveat as Minimum price for a pasted single product link.
fetchDetailsbooleanfalseAdds the full breadcrumb category path, complete description, image gallery, and every format/colour variant. For a pasted single product link the full detail fetch always runs regardless of this toggle.
fetchReviewsbooleantrueFetch the product's own reviews. On by default, so most runs are billed the detail and review enrichment charge described under Plan Requirement, even for a product with no reviews at all.
maxReviewsPerProductinteger10Cap on reviews per product when Fetch reviews is on, up to the site's own 10-review page limit.
maxPagesinteger0Cap on result pages per search/category/URL entry; 0 or empty = unlimited (walks every page).
maxItemsinteger20Cap on total products returned (pushed to the dataset), not pages scanned; 0 = unlimited.
resumeFromRunIdstring(none)Previous run id or dataset id to resume from, skipping every product already collected and returning only the delta, without re-billing it.
incrementalModebooleanfalseDaily/recurring monitoring of this same search. First run returns everything as NEW; later runs return only NEW/UPDATED by default. See "Resume and recurring updates" above for exactly when REAPPEARED/EXPIRED can appear.
stateKeystring(none)Incremental mode only. Name this monitoring campaign, or deliberately share state across differently configured runs. Leave empty to derive one automatically.
emitUnchangedbooleanfalseIncremental mode only. Also return (and bill) products unchanged since the last run, marked UNCHANGED.
emitExpiredbooleanfalseIncremental mode only. Also return (and bill) products from a previous run no longer found, marked EXPIRED, once a run has fully scanned the search. Turning this on for a search is also what makes a later reappearance of that product classify as REAPPEARED.
proxyobject{"useApifyProxy": true}Connection settings.
mcpConnectorsarray(none)Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify).
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items exported to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values above are illustrative placeholders, not from a live product.

{
"productId": "845210",
"sku": "845210",
"name": "Sample Hydrating Night Cream",
"brand": "SAMPLE BRAND CARE",
"category": "Cosmética Corporal",
"url": "https://www.druni.es/sample-hydrating-night-cream-sample-brand-care",
"price": 18.75,
"currency": "EUR",
"originalPrice": 24.99,
"discountAmount": 6.24,
"discountPercent": 25.0,
"isOnSpecial": true,
"onlineAvailable": true,
"image": "https://www.druni.es/media/catalog/product/sample/sample-night-cream.jpg",
"categoryPath": ["Druni", "Cosmética", "Cuidado Facial", "Cosmética Corporal"],
"description": "Sample product description as shown on the site.",
"variants": [
{ "sku": "845211", "name": "Sample Hydrating Night Cream 50G", "size": "50G", "price": 18.75, "currency": "EUR", "onlineAvailable": true, "unitPrice": 37.5, "unitPriceBasis": "100 g" },
{ "sku": "845212", "name": "Sample Hydrating Night Cream 100G", "size": "100G", "price": 29.9, "currency": "EUR", "onlineAvailable": false, "unitPrice": 29.9, "unitPriceBasis": "100 g" }
],
"rating": 4.4,
"reviewCount": 57,
"reviews": {
"averageRating": 4.4,
"totalReviewCount": 57,
"items": [
{ "rating": 4, "body": "Sample review text.", "author": "Usuario verificado", "date": "2026-03-18" }
]
}
}

Plan Requirement

The default connection works out of the box, and the run automatically retries with a different connection when one is refused. For large or frequent runs, the residential proxy group gives more headroom; pick it under Connection.

FAQ

How much does it cost?

You pay a per-product charge for every product returned, plus a one-time detail and review enrichment charge for each product whose page is fetched for full detail and/or reviews. That enrichment charge applies by default on most runs because Fetch reviews is on by default, and it always applies for a pasted single product link regardless of any toggle. The Pricing tab shows the current rates. Use Max products total to cap the cost of any run.

This actor collects only publicly available product data. You are responsible for how you use it: follow druni.es's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated products by default, and unchanged ones are not billed. A product only comes back as REAPPEARED once an earlier run, with Emit expired products on, fully scanned that search and recorded the product as gone; without that step first, a product that disappears and returns simply reads as UPDATED or UNCHANGED.

A record reached by pasting a single product link carries identity, description, category path, rating and reviews from the product page, but no top-level price/originalPrice/isOnSpecial/onlineAvailable. Current price and availability for that path live inside each entry of variants (size or colour options), or are absent entirely for a product with no declared variants. To get a top-level price, reach the product through a search, category, or Ofertas Flash listing instead.

Why did my run fail instead of returning an empty dataset?

If the connection is refused for the whole run, the run stops with a clear message so "no products matched" is never confused with "nothing could be read". Run it again in a few minutes. If only some pages could not be read, you still get what was found.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

🔗 Want more e-commerce data?

Pair this actor with these related scrapers from the same team:

🥦 El Corte Inglés Scraper
Scrape El Corte Inglés elcorteingles.es products across fashion, electronics, home...
🛒 Decathlon.es
Scrape Decathlon Spain (decathlon.es) sporting goods: current price plus strike-through...
🔌 LeroyMerlin.es Scraper
Scrape Leroy Merlin Spain (leroymerlin.es) DIY and home-improvement products: price...
🛒 MediaMarkt.es Scraper
Scrape MediaMarkt Spain (mediamarkt.es) products: current price, strike-through original...
🥦 Mercadona Scraper
Scrape Mercadona products by delivery-area postal code. Search by keyword or category, or...
🛒 PcComponentes Scraper
Scrape PcComponentes (pccomponentes.com) products: current price plus strike-through...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.