DEV Community

Cover image for How to Scrape Sainsbury's Grocery Prices with Python
ReventaData
ReventaData

Posted on Originally published at apify.com

How to Scrape Sainsbury's Grocery Prices with Python

By the end of this tutorial, you will have a Python script that pulls grocery prices and promotional offers from Sainsbury's into structured JSON: product name, shelf price in GBP, Nectar card price, promotional text, unit price and unit measure, customer rating, category names, EAN barcodes, and product URL.

Sainsbury's is a UK supermarket where shoppers buy groceries online. Tracking grocery prices or checking promotional discounts by hand across dozens of products is tedious, and copying product cards manually into spreadsheets takes hours.

In this guide, we use Python and the Apify Actor Sainsbury's Scraper (reventadata/sainsburys-scraper). Our benchmark run (configured with searchQueries: ["coffee"], maxItems: 60, maxPages: 3, onlyPromotions: true, exactMatchesOnly: true) finished in 10.6 seconds and returned 50 products.

Time estimate: About 30 minutes.


Prerequisites

To follow this tutorial, you will need:

  1. Python 3.11+ installed locally on your system.
  2. The Apify API client for Python (pip install apify-client).
  3. An Apify account and its API token.

Copy your API token from API & Integrations in the Apify Console settings, and then install the official Apify client library in your terminal:

pip install apify-client
Enter fullscreen mode Exit fullscreen mode

What you'll achieve

You will run the Actor from Python and receive clean, structured JSON records for every matching grocery item on Sainsbury's. The scraper reads product records embedded directly in search results, so individual product pages do not need to be opened separately.

Note on pricing structures: Sainsbury's displays both standard retail prices and discounted loyalty prices. When a product has a Nectar card discount, price gives that discounted price, priceIsNectar is set to true, and regularPrice stores the standard price before the promotion.

Example use case: Suppose you want to track promotional coffee deals across Sainsbury's online catalog. Setting searchQueries: ["coffee"] alongside onlyPromotions: true and exactMatchesOnly: true collects discounted coffee products, up to the maxPages and maxItems caps, with its promotional dates and unit pricing.


Step 1: Access Sainsbury's Scraper

Open the Sainsbury's Scraper page on Apify Store. The store listing details available input fields, output attributes, and pricing. You can click Try for free to inspect the Actor in the web interface. In this guide, we will invoke the scraper directly using Python code.


Step 2: Configure search parameters

The primary configuration property is searchQueries, an array of grocery search terms. Each term searches the UK online store at sainsburys.co.uk. Here is a Python script with the same input we used for our benchmark run:

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run_input = {
    "searchQueries": ["coffee"],
    "maxItems": 60,
    "maxPages": 3,
    "onlyPromotions": True,
    "exactMatchesOnly": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
    },
}

run = client.actor("reventadata/sainsburys-scraper").call(run_input=run_input)

for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["name"], item["price"], item["currency"], item["unitPrice"], item["url"])
Enter fullscreen mode Exit fullscreen mode

This code uses the exact settings behind the metrics in this article. Setting maxPages: 3 limits pagination to three search result pages, while maxItems: 60 caps saved records across the query.


Step 3: Configure optional settings and filters

The Actor provides multiple configuration options and filtering switches:

Parameter Type Default What it does
searchQueries array none List of grocery terms to search on sainsburys.co.uk.
maxItems integer 100 Maximum number of products to save across all search queries.
maxPages integer 6 Maximum result pages to walk per query (1 to 20, up to 60 products per page).
sort string RELEVANCE Sort order: RELEVANCE, PRICE_ASC, PRICE_DESC, or RATING.
minPrice, maxPrice number none Price limits in GBP, evaluated after extraction.
minRating number none Minimum average customer rating (0 to 5); unrated products are dropped.
onlyPromotions boolean false Keeps only items that carry at least one active promotion.
exactMatchesOnly boolean false Drops related products appended by search (rows with relevance: 2).
includeKeywords array none Words the product name or category must contain.
excludeKeywords array none Words the product name or category must not contain.
proxyConfiguration object Apify Unblocker Proxy settings; Apify Unblocker is required for sainsburys.co.uk requests.

Three operational details help you configure these filters effectively:

  • onlyPromotions: true keeps both Nectar discounts and multibuys. Fixed-price promotions report their pre-promotion price in regularPrice. Multibuy deals (such as "Buy any 2 for £7.50 with Nectar") leave regularPrice as null while marking onPromotion: true.
  • exactMatchesOnly: true excludes related search recommendations. The Actor flags exact hits as relevance: 1 and related products as relevance: 2.
  • Filters run locally on extracted page records. Keyword inclusion, price boundaries, rating thresholds, and promotional checks filter rows before dataset insertion.

Step 4: Run the Actor

Replace <YOUR_APIFY_TOKEN> with your actual token, save the file, and execute it. Calling .call() starts the Actor in the Apify cloud and waits for completion. The scraper walks the requested result pages, applies your filtering criteria, and stores saved products into the default dataset.

Allow the script to execute until completion. Our benchmark run finished in 10.6 seconds, extracting 50 products across three pages. Each line printed by the script shows the product title, shelf price in GBP, unit price, and product page link.


Step 5: View and download results

The script loops through items in the dataset using .iterate_items(). In the Apify Console, you can also download dataset records as JSON, CSV, Excel or JSONL.

Here is the first product record from our benchmark run (id: "7620344"), verbatim:

{
  "id": "7620344",
  "name": "Nescafé Azera Americano Instant Coffee 90g",
  "url": "https://www.sainsburys.co.uk/groceries/product/nescaf-azera-americano-instant-coffee-90g",
  "price": 3.5,
  "currency": "GBP",
  "unitPrice": 38.89,
  "unitMeasure": "kg",
  "regularPrice": 7.25,
  "priceIsNectar": true,
  "onPromotion": true,
  "promotions": [
    {
      "type": "SIMPLE_FIXED_PRICE",
      "text": "Better than Half Price with Nectar",
      "isNectar": true,
      "regularPrice": 7.25,
      "startsAt": "2026-10-14T23:00:00Z",
      "endsAt": "2026-11-03T00:00:00Z"
    }
  ],
  "rating": 4.61,
  "reviewCount": 191,
  "categories": [
    "Instant coffee"
  ],
  "image": "https://assets.sainsburys-groceries.co.uk/gol/7620344/image.jpg",
  "eans": [
    "7613034065520",
    "8445290044822"
  ],
  "isAvailable": true,
  "relevance": 1,
  "matchedKeyword": "coffee",
  "page": 1,
  "scrapedAt": "2026-10-23T19:42:19.809562+00:00"
}
Enter fullscreen mode Exit fullscreen mode

Understanding your results

The dataset provides several key pricing and catalog attributes:

  • price: the current shelf price in GBP. When a Nectar price is active, this reflects that loyalty price.
  • regularPrice: the shelf price before a fixed-price promotion, or null for multibuys.
  • unitPrice and unitMeasure: cost per kg or ltr enabling direct comparisons across package sizes.
  • promotions: array with promotion type, text, Nectar requirements, and validity dates.
  • eans: barcode identifiers for matching products against other retailers.

Our benchmark run extracted 50 products, yielding clear insights into the coffee category:

  • All 50 products had numeric prices ranging from 1.75 GBP to 16.50 GBP, with a median price of 4.80 GBP.
  • All 50 items were on promotion: 47 had fixed-price Nectar deals with regularPrice populated, and 3 featured multibuy deals (such as "Buy any 2 for £7.50 with Nectar").
  • 48 products had customer ratings ranging from 3.37 to 5.0 with a median rating of 4.53, backed by 2,897 total reviews across the dataset. 2 products had no customer reviews.
  • All 50 items were exact search matches (relevance: 1), and all 50 items carried EAN barcodes across 15 distinct categories.

Pro tips and advanced usage

  1. Tune page counts to category volume. Each Sainsbury's search page contains up to 60 products. The default setting of maxPages: 6 checks up to roughly 360 items. For broad categories, increase maxPages up to 20 to capture more results.
  2. Standardize price comparisons with unit measures. Rather than comparing raw pack prices, use unitPrice and unitMeasure to evaluate costs per kilogram or per litre across varying brand packaging.
  3. Automate alerts with webhooks. You can configure Apify webhooks to trigger downstream HTTP endpoints when a scrape finishes. The payload's resource object contains the run details (docs.apify.com/platform/integrations/webhooks/actions), including defaultDatasetId.
  4. Cross-reference catalogs using EAN barcodes. The Actor extracts all EAN barcodes into the eans array, allowing reliable product matching against external retail databases.
  5. For current pricing and details, see the Store page.

Troubleshooting common issues

  • The run fails with "0 rows for queries...". The Actor raises a runtime error when zero rows are pushed to the dataset. This occurs if your search terms yielded no products on the site or if strict filters (such as narrow price boundaries or rating thresholds) rejected every candidate item.
  • The run fails with "searchQueries is empty". You must provide at least one grocery search term in searchQueries. If the list is empty or contains only whitespace, the Actor raises this error before requesting any pages.
  • Input rejected with invalid sort option. The sort parameter accepts only RELEVANCE, PRICE_ASC, PRICE_DESC, or RATING. Any other string is refused before the run starts.

For technical support or feature requests, visit the Actor's Store page.


Next steps

Now that you can extract grocery prices programmatically, you can schedule recurring runs to track supermarket price fluctuations, build inflation trackers, or monitor competitive promotions over time. Explore the Apify Python client documentation and the Store page to learn more.

What grocery items are you planning to track on Sainsbury's? Drop a comment below!

Top comments (0)