# Dan Murphy’s Scraper - Prices, Stock, Ratings & Specials (`abotapi/danmurphys-scraper`) Actor

Scrape Dan Murphy’s products by category, keyword, or specials. Extract 45+ fields, including regular, sale and member prices, case and unit pricing, stock, ratings, reviews, country, variety, and ABV. Incremental mode tracks changes.

- **URL**: https://apify.com/abotapi/danmurphys-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product listings

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Dan Murphy's Scraper

Scrapes [danmurphys.com.au](https://www.danmurphys.com.au) — Australia's largest liquor retailer (Endeavour Group). Products with regular / sale / **member-offer** pricing, case and per-unit prices, ratings, review counts, stock, country, variety, ABV and awards, from the site's own open JSON API — plain HTTP, no browser automation.

**45+ fields per product.** Category browse (13 departments, sub-departments), keyword search, brand facet, specials-only and member-offers-only modes, plus incremental monitoring (NEW / UPDATED / REAPPEARED / EXPIRED) for scheduled price-watch runs.

### Quick start

- **Search mode**: pick a department (beer, red-wine, white-wine, champagne-sparkling, spirits, whisky, fortified-wine, premix, …), optionally a sub-department (`craft beer`, `shiraz`, `scotch whisky`), a keyword, or a brand; toggle `specialsOnly` for current offers.
- **URL mode** — paste any category route (`https://www.danmurphys.com.au/beer/craft-beer`, `/red-wine/shiraz`, `/whisky/scotch-whisky`) or product link; multi-URL supported; pagination walks forward automatically.
- `specialsOnly` / `memberOffersOnly` narrow results to current or member offers. They apply to BOTH modes: in URL mode every category scope gets the same facet filters.
- `maxProducts` (default 20) caps each run; `0` walks the whole department.
- `fetchDetails` adds the rich description + recommendations per product (per-product surcharge — see pricing). Listing tiles already carry prices, offers, ratings, stock and attributes without it.

### Output fields (overview view)

`stockcode, name, brand, department, url, price, wasPrice, isOnSpecial, isOnOffer, isMemberOffer, memberOfferLabel, casePrice, singlePrice, inAnySixPrice, rating, reviewCount, country, style, size, abv, standardDrinks, closure, foodMatch, award, sash, stockQty, isNew, deliveryOnly, imageUrl, imageLarge, description, richDescription, tastingNotes, recommendedStockcodes, packMessage, promotionType, unit, packageSize, purchasable, changeType, changedFields, firstSeenAt, lastSeenAt`

### Incremental mode (recurring monitoring)

Set `incrementalMode` on a scheduled task: the run remembers the previous run of the **same search** (keyed on mode + department + filters, or your own `stateKey`) and classifies every product `NEW` / `UPDATED` / `UNCHANGED` / `REAPPEARED` / `EXPIRED`, with `changedFields` naming what moved. `emitUnchanged` / `emitExpired` return — and bill — extra rows. `resumeFromRunId` instead continues ONE interrupted run by skipping products that run already collected; it cannot be combined with incremental mode.

### Send results into your apps (MCP connectors)

Results can be pushed into any Apify MCP connector (Notion and compatible targets). Authorize a connector under **Apify → Settings → Integrations**, then set `mcpConnectors` (connector ids) in the input, `notionParentPageUrl` for Notion, and `maxNotifyListings` to cap the export (`0`, the default, exports everything pushed). The connector receives a condensed, human-readable summary per item (title + key fields flattened to text). The complete record always stays in the Apify dataset, which the connector does not mirror.

### Pricing

Pay per event: **$0.001 per product listing** (base, every run) + **$0.002 per detail-page enrichment** (only when `fetchDetails` is on). Connection: works out of the box on the default Apify proxy; if you ever see blocks, switch the proxy group in the input (see the Connection section).

### Notes

- Uses the site's internal API; departments are the site's verified slugs — `wine` alone is not one (it splits into red-wine / white-wine / champagne-sparkling / fortified-wine).
- 18+ — you must be of legal purchasing age in your jurisdiction to use this data source.

### Verification note (2026-08-31)

Re-verified against the live site on 2026-08-31, and one defect found and fixed: keyword search terms the site treats as category routes (for example "whisky" or "beer") made the search endpoint answer with a redirect instruction instead of product data, which crashed the run. The walk now follows that redirect and browses the matching department instead, so `specialsOnly`/brand filters keep applying on the browse path. Verified live with the actor's own client: the beer department reported 739 products and the craft-beer sub-department 359, and the "whisky" keyword search that used to crash now browses the whisky department and returns real products. Version bumped with the fix.

# Actor input Schema

## `mode` (type: `string`):

Search mode walks a department (optionally a sub-department, a keyword, a brand, specials-only). URL mode walks any category route or product link you paste — multiple allowed, pagination walks forward automatically.

## `department` (type: `string`):

Verified departments (the API rejects anything else with 'Category does not exist'). Wine splits into red-wine / white-wine / champagne-sparkling / fortified-wine.

## `subDepartment` (type: `string`):

Second path segment, with spaces (e.g. 'craft beer' for /beer/craft-beer, 'shiraz' for /red-wine/shiraz, 'scotch whisky' for /whisky/scotch-whisky). Leave empty for the whole department.

## `searchTerm` (type: `string`):

Free-text search. If given, a keyword scope runs in addition to the department scope.

## `brand` (type: `string`):

Brand facet slug (lowercase, dashes for spaces: 'stone-and-wood', 'four-pines'). Search mode only.

## `urls` (type: `array`):

Category routes (/beer/craft-beer, /red-wine/shiraz, /whisky/scotch-whisky) and/or product links (/product/{code}/{name}). Multi-URL supported. Pagination starts at the pasted URL's first page and walks forward. The specials and member-offers filter toggles in the next section apply to URL scopes too.

## `specialsOnly` (type: `boolean`):

Only products with a current offer (the site's currentoffer facet). Applies to search mode AND to every category URL in url mode.

## `memberOffersOnly` (type: `boolean`):

Only products carrying a member (My Dan Murphy's) offer. Applies to search mode AND to every category URL in url mode.

## `fetchDetails` (type: `boolean`):

Fetch each pushed product's detail payload (tasting/rich description, recommendations). Adds a per-product surcharge — see pricing. Listing tiles already carry prices, member offers, ratings, stock and attributes without this.

## `maxPages` (type: `integer`):

Cap on pages walked per scope. 0 walks until the department is exhausted.

## `maxProducts` (type: `integer`):

The single default cap. 0 = unlimited (a full department can be tens of thousands of products).

## `resumeFromRunId` (type: `string`):

Continue ONE interrupted run: products already collected by that run are skipped. Cannot be combined with incremental mode.

## `incrementalMode` (type: `boolean`):

For scheduled monitoring: the run remembers the previous run of the SAME search and classifies every product NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED. Defaults off — no existing user's runs change until they opt in.

## `stateKey` (type: `string`):

Manual key for the incremental baseline. Leave empty to auto-key on mode + department + filters, so two different filter setups never share a baseline.

## `emitUnchanged` (type: `boolean`):

Incremental mode only. Also return (and bill) products classified UNCHANGED.

## `emitExpired` (type: `boolean`):

Incremental mode only. Also return (and bill) products that vanished since the last complete run.

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

Apify proxy. Datacenter (the default) passes; if you see blocks, switch to Apify Residential with country AU. Free-tier note: this site also works on datacenter, so free plans are fine.

## `mcpConnectors` (type: `array`):

Connector ids (authorized under Apify → Settings → Integrations) to push results into — Notion and compatible MCP targets. Optional.

## `notionParentPageUrl` (type: `string`):

For a Notion MCP connector: the parent page the results are written under. Optional.

## `maxNotifyListings` (type: `integer`):

Cap on items exported to connectors per run. 0 exports everything pushed.

## Actor input object example

```json
{
  "mode": "search",
  "department": "beer",
  "urls": [
    "https://www.danmurphys.com.au/beer/craft-beer"
  ],
  "specialsOnly": false,
  "memberOffersOnly": false,
  "fetchDetails": false,
  "maxPages": 0,
  "maxProducts": 20,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 0
}
```

# Actor output Schema

## `products` (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 = {
    "mode": "search",
    "department": "beer",
    "urls": [
        "https://www.danmurphys.com.au/beer/craft-beer"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/danmurphys-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 = {
    "mode": "search",
    "department": "beer",
    "urls": ["https://www.danmurphys.com.au/beer/craft-beer"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/danmurphys-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 '{
  "mode": "search",
  "department": "beer",
  "urls": [
    "https://www.danmurphys.com.au/beer/craft-beer"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/danmurphys-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/danmurphys-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/kgXW3HReyF4986GSI/builds/E48BdGP9rdGq32Z3o/openapi.json
