# Druni Scraper - Spanish Perfume and Beauty Prices (`studio-amba/druni-scraper`) Actor

Scrape product data from druni.es, the Spanish perfumery and beauty retailer. Get current and list prices, discounts, stock, ratings, review counts and categories for every shade and size of makeup, perfume, skincare and haircare.

- **URL**: https://apify.com/studio-amba/druni-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Druni Scraper

Pull product data from druni.es, the Spanish perfumery and beauty retailer. The actor returns one row per shade or size with the current price, list price, discount, stock status, rating, review count and category.

Druni sells makeup, perfume, skincare, haircare and body care from several thousand products. If you track Spanish beauty prices, this actor gives you a repeatable feed of what Druni charges and what is in stock.

### How to scrape Druni data

There are two ways to tell the actor which products to read.

1. Paste product pages into `productUrls`, for example `https://www.druni.es/fit-me-maybelline-corrector-corrige-ilumina`.
2. Leave `productUrls` empty and fill `urlKeywords`. The actor reads Druni's public sitemap and keeps products whose address contains one of your words, for example `maybelline` or `serum`.

The actor stops at `maxResults`. If you leave everything empty, it reads the first 50 products in the sitemap.

Search result pages are not read. The site's robots.txt does not allow them, so the actor does not request them.

### Input

| Field | Type | Description |
|---|---|---|
| `productUrls` | list of URLs | Druni product pages |
| `urlKeywords` | list of words | Used when no URLs are given. Keeps products whose address contains one of the words |
| `maxResults` | number | Maximum number of rows (default 50) |
| `proxyConfiguration` | proxy | Apify Proxy by default |

A product with seven shades gives seven rows, because each shade has its own SKU and price.

### What you get back

| Field | Description |
|---|---|
| `productId` | Druni product group number |
| `sku` | Variant number, also the number after `?sku=` in `url` |
| `ean` | EAN/GTIN barcode when the page publishes one. Most Druni pages do not, so this is often empty |
| `name` | Product name including shade or size |
| `brand` | Brand name |
| `variant` | Shade or size, empty when the product has only one |
| `price` | Current selling price in EUR |
| `originalPrice` | List price, only when the selling price is lower |
| `discountPercent` | Percent below the list price |
| `currency` | ISO currency code (EUR) |
| `inStock` | Whether this variant is in stock |
| `availability` | Availability as published (InStock or OutOfStock) |
| `rating` | Average review score out of 5 |
| `reviewCount` | Number of reviews on the product |
| `category` | Category path on the site |
| `description` | Short product description |
| `imageUrl` | Main variant image |
| `url` | Product page address for this variant |
| `scrapedAt` | Time of the read |
| `country`, `language` | `es`, `es` |

Rating and review count belong to the whole product, so all shades of one product share them.

### Example output

```json
{
  "productId": "2619",
  "sku": "2616038",
  "ean": null,
  "name": "El Borrador Green",
  "brand": "MAYBELLINE NEW YORK",
  "variant": "Green",
  "price": 6.99,
  "originalPrice": 10.49,
  "discountPercent": 33,
  "currency": "EUR",
  "inStock": true,
  "availability": "InStock",
  "rating": 4.5,
  "reviewCount": 934,
  "category": "Maquillaje > Rostro > Correctores de Maquillaje",
  "description": "Corrector Borrador multiusos: borra ojeras y bolsas, corrige imperfecciones, ilumina la mirada y define el rostro.",
  "imageUrl": "https://www.druni.es/media/catalog/product/2/6/2616038.jpg",
  "url": "https://www.druni.es/el-borrador-maybelline-corrector-ojeras-tratamiento-antiedad?sku=2616038",
  "scrapedAt": "2026-10-30T20:32:35.697Z",
  "country": "es",
  "language": "es"
}
```

### Use cases

- Compare Druni prices to other Spanish and European shops.
- Track list price and discount percent on a brand over time.
- Check which shades of a brand are in stock.
- Build a product catalogue with images, categories and ratings.
- Monitor review counts and ratings for your own brand.

### Cost and speed

The actor reads one product page per product, about 1.5 MB each, with four requests at the same time. Twenty products take about a minute. Pricing is per result, see the pricing box on this page. The usage cost of a run only settles after the run reports SUCCEEDED, so a cost checked during the run is too low.

### Notes and limits

- Prices are in EUR for the Spanish storefront. Other storefronts are not covered.
- The sitemap lists about 40,000 addresses. Some are category pages, which the actor skips.
- Druni does not publish EAN barcodes on its pages. The `ean` field is filled only when a page includes one.
- The actor reads publicly visible pages only. It does not log in and does not use cookies.
- You are responsible for how you use the data. Check Druni's terms and the rules that apply to your use case.

### Frequently asked questions

#### Does it return EAN barcodes?

Only when the product page publishes one. Most Druni pages show a SKU and no barcode.

#### Can I search by keyword?

Yes, with `urlKeywords`. The actor filters the sitemap by product address. It does not use the site's search page, because the site's robots.txt does not allow it.

#### Why are there more rows than products?

Each shade or size is its own row, because each has its own SKU and price.

#### Does it need a proxy?

Druni answers plain requests, so the default Apify Proxy setting is enough.

#### How often can I run it?

As often as you like. Daily runs on a fixed list of product pages give a clean price history.

### Related scrapers

- [Notino Scraper](https://apify.com/studio-amba/notino-scraper) for Notino beauty prices
- [Sephora Scraper](https://apify.com/studio-amba/sephora-scraper) for Sephora France and Spain
- [Douglas DE Scraper](https://apify.com/studio-amba/douglas-de-scraper) for Douglas Germany
- [Lookfantastic Scraper](https://apify.com/studio-amba/lookfantastic-scraper) for Lookfantastic UK
- [dm Scraper](https://apify.com/studio-amba/dm-scraper) for dm drugstore products

# Actor input Schema

## `productUrls` (type: `array`):

Product pages from druni.es, e.g. https://www.druni.es/fit-me-maybelline-corrector-corrige-ilumina. Each shade or size of a product becomes one row.

## `urlKeywords` (type: `array`):

Used when no product URLs are given. The actor reads the shop sitemap and keeps products whose address contains one of these words, e.g. maybelline or serum. Leave empty to read the first products in the sitemap.

## `maxResults` (type: `integer`):

Maximum number of rows (one row per size or shade).

## `proxyConfiguration` (type: `object`):

Proxy used for the requests. Default is Apify Proxy.

## Actor input object example

```json
{
  "urlKeywords": [
    "maybelline"
  ],
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urlKeywords": [
        "maybelline"
    ],
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/druni-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urlKeywords": ["maybelline"],
    "maxResults": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/druni-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urlKeywords": [
    "maybelline"
  ],
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call studio-amba/druni-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/druni-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/TNPXHdFTg7SnAtrz9/builds/0ep0NlzIWc1PHzgvX/openapi.json
