# Changelog of Fotocasa Spain Property Scraper (`devilscrapes/fotocasa-spain-property-scraper`) Actor

- **URL**: https://apify.com/devilscrapes/fotocasa-spain-property-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/fotocasa-spain-property-scraper.md

## Fotocasa Spain Property Scraper — Changelog

### 0.1 — 2026-09-25

Initial real build (T02–T06, T08, T09, T11 — see
`docs/specs/fotocasa-spain-property-scraper/tasks.md`):

- `src/models.py` — `ActorInput` (search\_url-or-location\_slug, min/max
  price bound, RESIDENTIAL/ES proxy default) and `ResultRow` (29-field
  output shape, `extra="forbid"`).
- `src/parser.py` — pure extract/map/filter/URL-build. `extract_initial_props`
  never raises; `listings_and_count` raises `FotocasaParseError` only when
  the `initialSearch.result` path itself is absent (REQ-3), distinct from a
  genuinely-empty `realEstates=[]`/`count=0` payload (REQ-2).
  `build_result_row` maps every spec field (nested `features[key=...]`
  lookup, flattened address, image-type-filtered multimedia, `detail_url`
  prefixing) and raises `pydantic.ValidationError` on a malformed listing
  (REQ-4). `passes_price_bounds` (REQ-7), `build_search_url` (REQ-10).
- `src/scraper.py` — curl-cffi `AsyncSession`, fresh proxy `session_id`
  per attempt, exponential backoff on 408/429/503/network errors only
  (REQ-8), impersonation rotation `chrome131` → `firefox133` after 2
  consecutive non-retryable failures (REQ-12), pagination bounded by
  `count`/`len(realEstates)` and `max_pages`/`max_results` (REQ-5/6).
- `src/main.py` — input validated before the `actor-start` PPE charge;
  batched `push_data`/`result-scraped` charge every 25 rows; REQ-3 dumps
  raw HTML to the KVS (`UNPARSEABLE_PAGE_HTML`) before re-raising to a
  non-zero exit; REQ-2 finishes SUCCEEDED with 0 rows and a status
  message naming the search parameters.
- **Live-probe bug fix**: `reducedPrice` arrives as a formatted string
  (e.g. `"75.000 €"`), not the raw int spec.md's one confirmed-null
  example implied — `_parse_eur_amount` strips non-digits so discounted
  listings no longer fail validation and get silently dropped.
- 82 tests (models/parser/scraper/main), `ruff check` and `pyright` both
  clean. Local `apify run` against the live site returns real,
  fully-shaped rows.

Detail-page fetches remain out of scope for v1 (spec.md "Out of Scope") —
the search-results page already carries price, address, coordinates,
features, description, and photo URLs per listing.

### 0.0 — 2026-09-25

- Actor scaffolded: `.actor/` config (actor.json, input\_schema.json,
  dataset\_schema.json, output\_schema.json, pay\_per\_event.json), pyproject.toml,
  Dockerfile, README skeleton with real PPE pricing, promo.json, and a
  boot-only `src/main.py` stub. No scraping logic yet — see
  `docs/specs/fotocasa-spain-property-scraper/tasks.md` (T02–T06) for the
  models/parser/scraper/main.py implementation work that follows.
