Romania's shopping malls publish their store directories, but they publish them in eight different ways: one operator runs a headless CMS, another a WordPress store list, another a Laravel JSON blob. Nobody publishes the whole country. So I built an actor that crawls every major operator and emits every store as one consistent record.
The gap
If you want the store mix of every mall in Romania — for retail analytics, site selection, or leasing research — you'd normally stitch together NEPI's site, AFI's site, Iulius's site, and so on, and still end up with per-operator formats that don't join. Worse, nobody flags the anchor tenants: the hypermarkets, cinemas and department stores that actually drive foot traffic. That's the gap: a country-wide directory with one schema and anchor flags built in.
The sources
Each operator publishes its own public store data, and each needed a different reverse-engineering pass:
-
NEPI Rockcastle (19 centres, ~2,434 tenants) — their own Strapi CMS JSON API (
cms.<site>/api/tenants), including Mega Mall's 215 stores and Promenada's 182 -
AFI Europe (Cotroceni, Ploiești) — the
evx_retailerssitemap - Iulius Group (Cluj, Iași, Suceava, Iulius Town) — a shopping index mixing category and store links, disambiguated by nesting
- Sun Plaza, Veranda, Colosseum — WordPress store sitemaps
-
Băneasa — a Laravel/Inertia
data-pageJSON payload across 11 pages
The robots.txt lesson deserves a callout: fetching it with Python's default RobotFileParser gets you 403'd by Sun Plaza and Veranda's WAFs — empty rules, everything disallowed. Fetching it with requests and a browser User-Agent works, and the actor then honours the real rules.
The smoke test
Input {"country":"ro","malls":["all"],"includeAnchor":true}:
- HTTP 201, 3,868 well-formed records in ~86 seconds
- 0 empty store names, 0 malformed key sets
- 382 anchor tenants flagged, 2,495 records with floor/unit, 1,499 with phone
- 29 of 30 registered malls covered
- All 10 identity fields (mall, store, brand, category, url, …) 100% filled
Run it again and the first_seen / last_seen / is_closed fields turn the directory into a vacancy and churn time-series — which stores opened, which closed, which anchors moved.
The honest bits
- ParkLake is WAF-gapped from the cloud. Sonae Sierra serves an HTTP 202 JavaScript-challenge page to datacenter IPs for its API, sitemap and archive alike; even curl_cffi impersonation hits the wall. From a residential or proxy IP the REST API returns ~223 stores with full detail. The adapter tries hard, then logs the challenge honestly instead of faking data — attach a residential proxy if you need ParkLake from the cloud.
-
is_closedonly becomes meaningful from the second run — the first run is your baseline. - Fields an operator doesn't publish come back as empty strings, so exports stay clean but sometimes thin.
Try it
👉 Romania Mall Store Directory on Apify Store
More from me
While you're here, these might be worth a read:
- I Stopped Scraping Business Directories and Built an MCP Server on Official Registry Data
- Scraping Romanian Public Contracts: A Native-Language Tender & Awarded Deals Scraper
- Building a 12-City US Building Permits Scraper With Python
- Building an EU Safety Gate (RAPEX) Product Recall Scraper With Python
- How I Built a Water Utility Risk Intelligence Tool With Python and MCP
- Building an Aviation Hub API: Airports, Airlines, Live Flights & Weather From Six Keyless Sources
- I Built a Canada Product Recalls & Safety Alerts Scraper That Reads Open Government Data
- I Built a Telegram Members Scraper That Reads Public Chat Stats Without Login
- Building a WHOIS & DNS Lookup Tool: Domain Intelligence in One...
- Building an AI Web Crawler That Outputs LLM-Ready Content Chunks
- Building a Real-Time Press Release Monitor with Python and RSS...
- Building a Universal Property Listing Scraper with Python and ...
- Tracking Tech Sentiment in Real-Time with VADER and Python
- How I Built a Product Hunt Scraper That Tracks Launches in Rea...
- 5 APIs Every Developer Needs for Content Processing (RSS, Extraction, Sitemaps, AI)
- How to Extract Clean Content From Any Website Sitemap (For SEO...
- Scraping 187,000 Romanian Businesses: Building a B2B Lead Gene...
- Make Any Website AI-Readable: Generating llms.txt Files with
- I Built an RSS Aggregator That Extracts Full Article Content (...
Top comments (0)