# Changelog of SeLoger France Real Estate Scraper (`devilscrapes/seloger-france-real-estate-scraper`) Actor

- **URL**: https://apify.com/devilscrapes/seloger-france-real-estate-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/seloger-france-real-estate-scraper.md

## SeLoger France Real Estate Scraper — Changelog

### 0.2 — 2026-08-20

- **Fix**: SeLoger killed the `/immobilier/{achat|location}/immo-{location}/
  bien-{property}/` redirect-URL scheme this Actor's `location`-mode search
  built (build 0.0.1's live cloud run `Fa0Wmd2VehBbcAvPk` — every request to
  it now returns HTTP 410 Gone, so the Actor's own prefilled/QA-default input
  (`location="paris-75000"`) failed with zero rows on every customer run).
  Full recon in `docs/specs/seloger-france-real-estate-scraper/notes.md`.
- `config.build_search_url()` replaces `build_immobilier_url()` — builds the
  still-live `/recherche/{achat|location}/{property}/{region}/{location}/{code}`
  shape (re-verified end to end against current markup, including
  `parser.extract_search_cards()`) from a new live-probed `LOCATION_CODES`
  allowlist (`"paris-75000"` confirmed) and a trimmed
  `PROPERTY_TYPE_PATH_SLUGS` (apartment/house/land/parking reconfirmed;
  `commercial` dropped — no confirmed slug, every guess 410s).
  `UnresolvableLocationError`/`UnsupportedPropertyTypeError` replace the old
  silent dead-URL build; `main._resolve_run_urls()` catches both and turns
  them into a clear shortfall-note status message instead of crashing on a
  raw HTTP 410 (REQ-4/REQ-12).
- `search_urls` (direct customer-pasted URLs) was never affected by this bug
  — it already carries SeLoger's resolved location code.
- `src/recon_cloud.py` updated to call the new builder (still not on the
  runtime path).
- `input_schema.json`/`models.py` field descriptions updated to state the
  `location`/`property_type` support scope plainly instead of the stale
  "needs-cloud-recon" framing.

### 0.1 — 2026-08-13

- Real implementation lands (T02-T11, T14; LOCAL-GREEN ONLY, no `apify
  push`/cloud calls this pass): `src/models.py` (`ActorInput` with the
  search\_urls-or-location validator, `ResultRow` — 26-field spec.md Output
  Shape table, `extra="forbid"`); `src/config.py` (pure `achat`/`location`
  and property-type slug tables, `PAGE_SIZE=30`, `build_immobilier_url()`,
  `is_detail_url()` — deliberately no page-2+ URL helper, REQ-4);
  `src/geo_guard.py` (host + `lang="fr"` + `og:locale fr_FR` guard, all
  three required, REQ-9); `src/parser.py` (two independent extraction
  shapes — `title`-attribute search cards and JSON-LD/inline-GeoJSON detail
  pages, REQ-5/REQ-7; `energy_rating`/`agency_phone` ship as permanent
  `None` stubs with a regression test pinning that an `Organization`
  JSON-LD block's corporate phone number never leaks into `agency_phone`);
  `src/scraper.py` (`SelogerSession` — one curl-cffi session/run, rotating
  `chrome131`/`chrome124`/`firefox147`/`safari180` impersonation, retry +
  exponential backoff on 408/429/503/network errors and DataDome-class
  challenges alike, `WEBSHARE_PROXY_URL` env fallback, run-wide
  `listing_id` dedup, per-URL and per-listing fault isolation, REQ-3/4/6/8/
  9/10/11/13/15); `src/main.py` (SDK wiring, PPE charging, fail-loud
  zero-rows exit, shortfall-note status messaging, REQ-1/2/12/14).
- Found and fixed a regex bug during TDD: a naive `[\d\s.,]+` price/area
  pattern let whitespace bridge two unrelated digit tokens (the trailing
  "3" of "T3/F3" bleeding into "53 m²"), mis-parsing the spec's own
  literal confirmed title text as `area_sqm=353.0` instead of `53.0`.
  Fixed with a stricter "number token" regex (contiguous digit run, or
  digits grouped in threes by a thousands-separator space) and pinned
  with a regression test.
- `.actor/dataset_schema.json`, `.actor/output_schema.json`,
  `.actor/pay_per_event.json` added (`actor-start` $0.05, `result-row`
  $0.0018, verbatim from spec.md's Pricing table); `.actor/actor.json`
  updated to reference `output`/`storages.dataset`.
- `src/recon_cloud.py` written (T08) but **not executed** — probes the
  Apify-egress DataDome posture and 2-3 candidate page-2+ query-param
  guesses, dumps to the default KVS via `Actor.set_value`. Execution is
  deferred to a future cycle (this account is over its FREE-tier $5/mo
  cap until 2026-08-15).
- Test suite: 114 tests across `test_models.py`, `test_config.py`,
  `test_geo_guard.py`, `test_parser.py`, `test_scraper.py` — all pure/mocked,
  no real network calls. `pytest`, `ruff check`, and `pyright` all green.
- `tests/fixtures/input.qa.json` (5-result, proxy-path-exercising) added
  per the org hard rule — validated offline via
  `scripts/verify_input_prefill.py`; not yet run against `apify run` or
  the cloud (deferred to a future `actor-tester`/`actor-qa-engineer`
  cycle, alongside publish).
- Deferred to a future cycle: cloud recon execution, `apify push`,
  publish, and cloud QA — this pass ends at "tests green locally" per
  `docs/specs/seloger-france-real-estate-scraper/design.md`'s "Build
  scope for this pass: LOCAL-GREEN ONLY".

### 0.0 — 2026-08-13

- Scaffolded (T01, LOCAL-GREEN ONLY): `.actor/` (`actor.json`,
  `input_schema.json`, `Dockerfile`, icon stub), `src/__init__.py`,
  `src/__main__.py` (boots, validates nothing yet, pushes one
  `{"placeholder": true, ...}` row, exits — no real crawler), `pyproject.toml`
  (`apify`, `curl-cffi`, `pydantic`, `selectolax` pinned per
  `docs/specs/seloger-france-real-estate-scraper/tasks.md` T01), `.actorignore`,
  `scaffold.json`, README skeleton.
- `uv sync` materializes cleanly and `apify run --purge` boots the scaffold
  end to end: reads `Actor.get_input()`, logs it, pushes one
  `{"placeholder": true, ...}` dataset record, exits code 0.
- Real implementation (`src/models.py`, `src/config.py`, `src/geo_guard.py`,
  `src/parser.py`, `src/scraper.py`, `src/main.py`, `.actor/dataset_schema.json`,
  `.actor/output_schema.json`, `.actor/pay_per_event.json`) is pending — see
  `docs/specs/seloger-france-real-estate-scraper/tasks.md` T02-T14. Cloud
  recon (Apify-egress DataDome posture + page-2+ pagination scheme), `apify
  push`, publish, and cloud QA are explicitly deferred to a future cycle per
  `docs/specs/seloger-france-real-estate-scraper/design.md` ("Build scope
  for this pass: LOCAL-GREEN ONLY").
