# Troostwijk Scraper - Architecture & Data Flow ## System Overview The scraper follows a **3-phase hierarchical crawling pattern** to extract auction and lot data from Troostwijk Auctions website. ## Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────────┐ │ TROOSTWIJK SCRAPER │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ PHASE 1: COLLECT AUCTION URLs │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Listing Page │────────▶│ Extract /a/ │ │ │ │ /auctions? │ │ auction URLs │ │ │ │ page=1..N │ └──────────────┘ │ │ └──────────────┘ │ │ │ ▼ │ │ [ List of Auction URLs ] │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ PHASE 2: EXTRACT LOT URLs FROM AUCTIONS │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Auction Page │────────▶│ Parse │ │ │ │ /a/... │ │ __NEXT_DATA__│ │ │ └──────────────┘ │ JSON │ │ │ │ └──────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Save Auction │ │ Extract /l/ │ │ │ │ Metadata │ │ lot URLs │ │ │ │ to DB │ └──────────────┘ │ │ └──────────────┘ │ │ │ ▼ │ │ [ List of Lot URLs ] │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ PHASE 3: SCRAPE LOT DETAILS │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Lot Page │────────▶│ Parse │ │ │ │ /l/... │ │ __NEXT_DATA__│ │ │ └──────────────┘ │ JSON │ │ │ └──────────────┘ │ │ │ │ │ ┌─────────────────────────┴─────────────────┐ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Save Lot │ │ Save Images │ │ │ │ Details │ │ URLs to DB │ │ │ │ to DB │ └──────────────┘ │ │ └──────────────┘ │ │ │ ▼ │ │ [Optional Download] │ └─────────────────────────────────────────────────────────────────┘ ``` ## Database Schema ```sql ┌──────────────────────────────────────────────────────────────────┐ │ CACHE TABLE (HTML Storage with Compression) │ ├──────────────────────────────────────────────────────────────────┤ │ cache │ │ ├── url (TEXT, PRIMARY KEY) │ │ ├── content (BLOB) -- Compressed HTML (zlib) │ │ ├── timestamp (REAL) │ │ ├── status_code (INTEGER) │ │ └── compressed (INTEGER) -- 1=compressed, 0=plain │ └──────────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────┐ │ AUCTIONS TABLE │ ├──────────────────────────────────────────────────────────────────┤ │ auctions │ │ ├── auction_id (TEXT, PRIMARY KEY) -- e.g. "A7-39813" │ │ ├── url (TEXT, UNIQUE) │ │ ├── title (TEXT) │ │ ├── location (TEXT) -- e.g. "Cluj-Napoca, RO" │ │ ├── lots_count (INTEGER) │ │ ├── first_lot_closing_time (TEXT) │ │ └── scraped_at (TEXT) │ └──────────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────┐ │ LOTS TABLE │ ├──────────────────────────────────────────────────────────────────┤ │ lots │ │ ├── lot_id (TEXT, PRIMARY KEY) -- e.g. "A1-28505-5" │ │ ├── auction_id (TEXT) -- FK to auctions │ │ ├── url (TEXT, UNIQUE) │ │ ├── title (TEXT) │ │ ├── current_bid (TEXT) -- "€123.45" or "No bids" │ │ ├── bid_count (INTEGER) │ │ ├── closing_time (TEXT) │ │ ├── viewing_time (TEXT) │ │ ├── pickup_date (TEXT) │ │ ├── location (TEXT) -- e.g. "Dongen, NL" │ │ ├── description (TEXT) │ │ ├── category (TEXT) │ │ └── scraped_at (TEXT) │ │ FOREIGN KEY (auction_id) → auctions(auction_id) │ └──────────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────┐ │ IMAGES TABLE (Image URLs & Download Status) │ ├──────────────────────────────────────────────────────────────────┤ │ images ◀── THIS TABLE HOLDS IMAGE LINKS│ │ ├── id (INTEGER, PRIMARY KEY AUTOINCREMENT) │ │ ├── lot_id (TEXT) -- FK to lots │ │ ├── url (TEXT) -- Image URL │ │ ├── local_path (TEXT) -- Path after download │ │ └── downloaded (INTEGER) -- 0=pending, 1=downloaded │ │ FOREIGN KEY (lot_id) → lots(lot_id) │ └──────────────────────────────────────────────────────────────────┘ ``` ## Sequence Diagram ``` User Scraper Playwright Cache DB Data Tables │ │ │ │ │ │ Run │ │ │ │ ├──────────────▶│ │ │ │ │ │ │ │ │ │ │ Phase 1: Listing Pages │ │ │ ├───────────────▶│ │ │ │ │ goto() │ │ │ │ │◀───────────────┤ │ │ │ │ HTML │ │ │ │ ├───────────────────────────────▶│ │ │ │ compress & cache │ │ │ │ │ │ │ │ │ Phase 2: Auction Pages │ │ │ ├───────────────▶│ │ │ │ │◀───────────────┤ │ │ │ │ HTML │ │ │ │ │ │ │ │ │ │ Parse __NEXT_DATA__ JSON │ │ │ │────────────────────────────────────────────────▶│ │ │ │ │ INSERT auctions │ │ │ │ │ │ │ Phase 3: Lot Pages │ │ │ ├───────────────▶│ │ │ │ │◀───────────────┤ │ │ │ │ HTML │ │ │ │ │ │ │ │ │ │ Parse __NEXT_DATA__ JSON │ │ │ │────────────────────────────────────────────────▶│ │ │ │ │ INSERT lots │ │ │────────────────────────────────────────────────▶│ │ │ │ │ INSERT images│ │ │ │ │ │ │ │ Export to CSV/JSON │ │ │ │◀────────────────────────────────────────────────┤ │ │ Query all data │ │ │◀──────────────┤ │ │ │ │ Results │ │ │ │ ``` ## Data Flow Details ### 1. **Page Retrieval & Caching** ``` Request URL │ ├──▶ Check cache DB (with timestamp validation) │ │ │ ├─[HIT]──▶ Decompress (if compressed=1) │ │ └──▶ Return HTML │ │ │ └─[MISS]─▶ Fetch via Playwright │ │ │ ├──▶ Compress HTML (zlib level 9) │ │ ~70-90% size reduction │ │ │ └──▶ Store in cache DB (compressed=1) │ └──▶ Return HTML for parsing ``` ### 2. **JSON Parsing Strategy** ``` HTML Content │ └──▶ Extract