What the Montblanc scraper collects
Scrapes montblanc.com category listings, keyword searches and product pages, with one row per variant in product mode. Rows carry the market's own price and currency, stock, collection, colour, size and special-edition flags, and the locale they came from. Output is JSON and CSV with a .meta.json sidecar recording the catalogue's own result count.
Category listings
Input: A category URL, or --category with --localeOne row per product: price, currency, stock from the tile itself, collection, colour, size and image, in the market the URL names.
Keyword search
Input: A search term and a market localeSearch results in the same row shape as a category listing.
Product variant tables
Input: One product page URLOne row per variant, each with its own sku and price, plus base_sku and variant_of linking it to its group — a sixteen-nib pen is sixteen rows.
From zero to Montblanc data in 3 steps
Install
Clone the repository and install one browser engine. Python 3.9+.
$ git clone https://github.com/2scraper/montblanc-scraper.git && cd montblanc-scraper $ python -m venv .venv-playwright $ .venv-playwright/bin/pip install -r requirements.txt -r requirements-playwright.txt $ .venv-playwright/bin/playwright install chromium
Run a scraper
Pick what you need and run it. Every flag is documented in the README.
$ python playwright_scraper.py --url "https://www.montblanc.com/en-us/writing-instruments" --pages 3 --format both$ python playwright_scraper.py --mode search --query "fountain pen" --locale en-us$ python playwright_scraper.py --mode product --url "https://www.montblanc.com/en-us/meisterstuck-gold-coated-legrand-fountain-pen-MB132460.html"Get structured data
Rows land in JSON or CSV (
--format), with a.meta.jsonsidecar recording status, pages fetched and why the run stopped.
Montblanc data fields
24 columns per row in a predictable schema. The most useful ones:
| Field | What it holds |
|---|---|
sku | Montblanc product or variant code, e.g. MB128502 |
title | Product name |
price | The market's own price as a number |
currency | Currency of that market |
price_source | jsonld, or dom_range for a "From $515" minimum over a variant group |
in_stock | Read from the tile's own availability, not the structured-data default |
locale | The market the row came from, e.g. en-us or de-de |
category | Category name |
collection | Collection, e.g. Fountain Pen |
sub_collection | Sub-collection where stated |
color | Colour |
size | Watch case width or belt length, where it applies |
special_edition | Whether the product is a special edition |
base_sku | The product group's base code |
variant_of | Product mode: the group a variant belongs to |
sort | The ordering requested for the run |
[
{
"source": "montblanc.com",
"scraped_at": "2026-09-17T22:36:53.099719+00:00",
"url": "https://www.montblanc.com/en-us/piston-converter-starwalker-MB128502.html",
"sku": "MB128502",
"title": "Piston Converter StarWalker",
"brand": "montblanc",
"price": 15.0,
"currency": "USD",
"in_stock": true,
"image_url": "https://www.montblanc.com/dw/image/v2/BHDB_PRD/on/demandware.static/-/Sites-montblanc-m…",
"category": "Fountain Pen Accessories",
"price_source": "jsonld",
"page": 1,
"position": 1,
"mode": "category",
"locale": "en-us",
"base_sku": "MB128502",
"collection": "Fountain Pen",
"sub_collection": null,
"color": "Black",
"size": null,
"special_edition": false,
"variant_of": null,
"sort": "price-asc"
},
{
"source": "montblanc.com",
"scraped_at": "2026-09-17T22:36:53.099780+00:00",
"url": "https://www.montblanc.com/en-us/ink-bottle-great-characters-homage-to-enzo-ferrari-purp…",
"sku": "MB128080",
"title": "Ink Bottle, Great Characters Homage to Enzo Ferrari, Purple - 50ml",
"brand": "montblanc",
"price": 55.0,
"currency": "USD",
"in_stock": false,
"image_url": "https://www.montblanc.com/dw/image/v2/BHDB_PRD/on/demandware.static/-/Sites-montblanc-m…",
"category": "Ink bottles",
"price_source": "jsonld",
"page": 1,
"position": 2,
"mode": "category",
"locale": "en-us",
"base_sku": "MB128080",
"collection": "Fountain Pen",
"sub_collection": "Ink Bottle",
"color": "Purple",
"size": "50 ml",
"special_edition": false,
"variant_of": null,
"sort": "price-asc"
}
]First 2 of 12 rows from a real run — sample_output.json. Long values shortened here.
Handles what breaks naive Montblanc scrapers
Per-market prices kept apart
Montblanc sets prices per market rather than converting them — one backpack was EUR 2000 on en-fi and EUR 1900 on de-de. Every row carries its locale, and diff_runs.py refuses to compare runs from different markets.
Price ranges labelled, not passed off as prices
Variant groups omit a price from the JSON-LD and render "From $515". That minimum is recorded with price_source dom_range so it can be excluded from comparisons, and --mode product gives each variant's real price.
Stock from the tile, not a template default
offers.availability said InStock on 192 of 192 rows; the tile said sold out on 7 of 384. The scraper reads the tile, and leaves in_stock null where there is none.
A stable default ordering
The site's default is a sales-velocity sort that shares 0 of 24 page-1 products with price-ascending. The scraper defaults to --sort price-asc so multi-page runs and price diffs are stable; --sort recommended reproduces the visitor view.
Scraping infrastructure included
The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.
CAPTCHA handling
Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.
Proxy rotation
Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.
Fingerprints
Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.
Honest run metadata
Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.
Diff two runs
diff_runs.py compares two complete Montblanc snapshots by id — new, removed and changed rows for monitoring.
What teams do with Montblanc data
Cross-market price comparison
Scrape the same products in several locales and compare prices that Montblanc sets per market, joined on sku.
Luxury price monitoring
Track price and stock changes across writing instruments, leather goods and watches with diff_runs.py.
Variant and configuration data
Use product mode to get every nib, colour or size variant of a product with its own sku and price.
Assortment and collection tracking
Follow which collections and special editions appear, sell out or disappear in a category over time.
Free to run. Pay only for what the site requires.
Runs with no key, proxy or account
Measured on 2026-09-17 from a bare datacentre address with no key and no proxy, category, search and product pages all returned HTTP 200 with no challenge. Montblanc runs Akamai Bot Manager, which did not challenge. The paid 2Captcha products mainly buy a specific market's default landing behaviour (the bare host geo-redirects on exit address), volume from many addresses, and no local browser via the Scraping Browser API or the Scraper API — not access.
Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.
Good to know
- Rows priced from a "From …" range (price_source dom_range) are a minimum over variants, not a variant's price.
- The site never states which ordering it applied, so the sort column records what was requested.
- Selenium cannot use an authenticated CDP endpoint or proxy; pyppeteer has no --concurrency.
2scraper vs. hosted scraper APIs
| 2scraper | Typical hosted API | |
|---|---|---|
| Code | Open source, MIT — read and patch it | Closed |
| Cost | Free; optional services billed only when used | Subscription or per request / per result |
| Runs on | Your machine, server or CI | The vendor's infrastructure |
| Output | JSON/CSV files + run metadata | API responses |
| When the site changes | Fix it yourself or open an issue / PR | Wait for the vendor |
Montblanc scraper FAQ
Do I need a 2Captcha account, proxy or key?
No. All page kinds were served from a datacentre address with no challenge, and the daily canary runs with no credentials.
How do I scrape a different market?
Put the locale in the URL or pass --locale. Category paths differ between markets (German uses /de-de/lederwaren/…), so swapping only the locale segment can 404.
Is there a page cap?
No. Pagination uses start/sz and is planned from the catalogue's own result count; a walk of /en-fi/writing-instruments returned exactly the 280 results it stated.
Why does my own HTTP script time out?
Montblanc's edge kills connections whose User-Agent names an HTTP client library, such as curl or python-requests. Set a browser-shaped User-Agent; the three browser engines never meet this.
What output formats does it write?
JSON, CSV or both, plus a .meta.json sidecar. A run that finds nothing writes nothing, so the previous good output is kept.
Is scraping Montblanc legal?
It reads the same public product pages a browser does, with no login and no personal data. Check robots.txt and the site's terms, keep --delay sane, and follow the law where you operate.