Luxury Asset Price Extraction & Database Management
Publicada el 2026-07-21
Descripción de la oferta
# Data Engineer / Web Scraping Specialist — Luxury Asset Price Index (Watches, Handbags, Prints) — 10-Year Historical Dataset + Ongoing Pipeline ## Overview I run a luxury-asset price index project. I need help sourcing **transaction-level historical price data** across **three independent categories**: Few exemples : 1. **Watches** — Rolex, Patek Philippe, Audemars Piguet, Omega, Cartier, Vacheron Constantin, Richard Mille, etc. 2. **Handbags** — Hermès (Birkin / Kelly), Chanel (Classic Flap), Louis Vuitton, Dior, etc. 3. **Prints / editions** — Picasso, Warhol, Chagall, Miró, Basquiat, Hockney, Banksy, etc. Each category is a **separate dataset** feeding a separate database table. I also need a **system that keeps pulling new completed sales automatically** going forward. This is a data-quality-critical project. The single most important rule is below — please read it before applying. --- ## #1 RULE — completed transactions ONLY (non-negotiable) Every row must be a **confirmed, completed sale** (hammer price paid / transaction closed). **Exclude:** active/current listings, asking prices, estimates without a realized result, unsold/withdrawn/passed/"bought-in" lots, and upcoming auction lots. If a source mixes sold and unsold items, **you filter to sold-only before delivery.** I will not accept raw scraped listings for me to filter myself. *(One narrow exception for handbag resale platforms — see the note under section B.)* --- ## Deliverable 1 — Historical dataset (2016–2026), one-time Each category maps directly to one of our database tables — **please use these exact field names** so your delivery can be imported with no remapping. **Currency — important:** always deliver each sale in its **original transaction currency** and do **not** pre-convert to EUR/USD/etc. Provide `sale_price` + `currency` as sold. We handle all FX conversion on our side. ### A. Watches → table `auction_results` | Column | Description | Status | |---|---|---| | source | Platform/auction house name (e.g. "Christie's", "Chrono24") | Mandatory | | auction_house | Same as source if it's an auction; leave empty for resale platforms | If applicable | | brand | e.g. Rolex, Patek Philippe | Mandatory | | model | e.g. Daytona, Nautilus | Mandatory | | reference | Exact factory reference, full raw string, never abbreviated (e.g. `116500LN`, `5711/1A-010`) | **Mandatory — our #1 matching key** | | sale_price | Realized / hammer price | Mandatory | | currency | Original transaction currency — do not pre-convert (see note above) | Mandatory | | auction_date | Exact sale date | Mandatory | | source_link | Direct link to the specific lot/listing | Mandatory | | condition | As stated by source | If available | | case_material | Steel, gold, platinum, two-tone… | If available | | case_size_mm | Case diameter | If available | | box_and_papers | Full set / watch only / papers only | Nice to have (not yet in our schema — we'll add the column if you can supply it) | | year_of_production | Manufacture year, distinct from sale date | Nice to have (same as above) | | dial_color | — | Nice to have (same as above) | > **`brand` + `reference` are how we match a sale to our index basket** (prefix-match on the reference string). A wrong or truncated reference silently drops the row from the index — it matters more than the price itself. ### B. Handbags → table `bag_prices` | Column | Description | Status | |---|---|---| | source | Platform/auction house name | Mandatory | | auction_house | Leave empty for resale platforms (Fashionphile, Rebag, etc.) | If applicable | | brand | Hermès, Chanel, Louis Vuitton, Dior… | Mandatory | | model | Must contain the recognizable model name as a substring, e.g. "Birkin 30", "Classic Flap" | **Mandatory — our matching key** | | size | e.g. Birkin 25/30/35, Kelly 28 | If available | | sale_price | Realized price | Mandatory | | currency | Original transaction currency — do not pre-convert | Mandatory | | snapshot_date | Exact date of the sale (or, for resale marketplaces, the date the listing/price was recorded) | Mandatory | | source_link | Direct link to the item | Mandatory | | condition | As stated by source | If available | | material | Togo, Epsom, caviar, canvas… | If available | | full_name | Full listing title, as a fallback description | If available | | color, hardware, box_and_authenticity, year_or_datestamp | — | Nice to have (not yet in our schema — flag if consistently available and we'll add columns) | > **Note on resale marketplaces (Fashionphile, Rebag, Collector Square, etc.):** if the platform doesn't publish a "sold" archive, the **current listed price of a specific, already-authenticated, uniquely identified item** is acceptable — that's how we currently treat Collector Square. What's **not** acceptable is a generic "starting from" or aggregated price. If the platform has an actual completed-sales feed (Vestiaire Collective "sold", The RealReal), prefer that. ### C. Prints / editions → table `art_prices` | Column | Description | Status | |---|---|---| | source | Auction house name | Mandatory | | artist_name | Full recognizable name (e.g. "Pablo Picasso") | **Mandatory — our matching key** | | artwork_title | Title of the work/edition | Mandatory | | sale_price + currency | Realized price in original currency — do not pre-convert (we store this as `sold_price_eur` after conversion, but you deliver raw `sale_price` + `currency`) | Mandatory | | is_sold | Should always be True in your delivery — see Rule #1 | Mandatory | | sale_date | Exact auction date | Mandatory | | url | Direct link to the lot | Mandatory | | lot_number, sale_title, sale_id | Auction lot reference info | If available | | technique | Lithograph, screenprint, etching, giclée… | If available | | edition | e.g. `12/100`, or "AP" (artist's proof) | If available | | signed | e.g. "Signed", "Unsigned", "Stamp" (free text, not just True/False) | If available | | dimensions | Sheet / image size | If available | | year_created | Year the work/edition was created | If available | | image_url | — | Nice to have | | condition, provenance | — | Nice to have | --- ## Deliverable 2 — Ongoing extraction system A maintainable pipeline (Python preferred, to fit our existing stack) that periodically pulls **newly completed sales** from the same sources and appends them to the correct table, **without creating duplicates**. Ideally runnable on a schedule. Clean, documented, handover-friendly code. *You may quote for Deliverable 1 only, or both — tell me in your proposal.* --- ## Where to look (examples, not exhaustive) **Auction houses (highest quality — public "prices realized" archives, all 3 categories):** Christie's, Sotheby's, Phillips (watches: Bacs & Russo), Bonhams, Antiquorum (watches), Artcurial, Drouot. - **Watches — resale / secondary:** Chrono24, WatchBox, Bob's Watches, Crown & Caliber, WatchFinder, eBay "sold" filter. Aggregators: WatchCharts, Subdial. - **Handbags — resale (see the section B note on what counts):** Fashionphile, Rebag, Collector Square, The RealReal, Vestiaire Collective (sold), plus auction "Handbags & Accessories" departments. - **Prints — auction results only:** the auction houses above (Prints & Multiples departments); aggregators like Artnet, MutualArt, Artprice may offer paid historical result databases. If any aggregator offers a **paid historical sold-price API or dataset**, **flag it** with the cost — I may buy access instead of scraping. ## Data quality standards - One row = one unique, verifiable transaction (no duplicates). - Every row traceable to its **exact source URL** (`source_link` / `url`) — I need to audit any row. - Reference numbers (watches) and model names (bags) in raw format, never truncated — they are the matching keys. - Deliver original currency, never pre-converted. - 10-year coverage as continuous as sources allow — **flag any gaps**. - Structured output only (CSV / Excel / JSON). No PDFs or screenshots. ## Skills I'm looking for - Python web scraping (requests / BeautifulSoup / Playwright or similar), handling JS-rendered pages and embedded JSON. - Structured data cleaning and de-duplication. - Bonus: familiarity with Supabase / PostgreSQL, and with luxury / auction data. ## Before you start — confirm back to me 1. Which sources you'll use per category, and expected row count / coverage per source. 2. Whether any source needs a paid API / subscription (I'll decide buy vs. scrape). 3. Your timeline and delivery approach (incremental vs. one batch). ## How to apply In your proposal, please include: - A one-line answer to: *how do you make sure only completed/sold transactions are captured?* - One example of a similar scraping / data project you've done. - Your quote for **Deliverable 1**, and separately for **Deliverable 2** if you want it. Proposals that ignore the #1 rule or the "confirm back to me" points will not be considered.
Skills
Fuente original: freelancer