Scrape used-car listings from coches.net, Spain’s #1 car marketplace — price, make, model, year, mileage, fuel, power, transmission, environmental label, seller, location, and photos. Export to JSON or CSV; enrich each listing with extra detail-page fields.
Fix TIMED-OUT customer runs (30-day public success rate 15%, 28/33
TIMED-OUT). Root cause: when a run's Apify Proxy configuration
requests a group the customer's plan can't authorize (RESIDENTIAL with
0 GB quota is common on FREE-tier accounts), Apify Proxy answers with a
permanent proxy-auth rejection for the entire run. curl-cffi
surfaces this as ProxyError (libcurl CURLE_PROXY — HTTP 407-class),
which the old code caught with a broad except (OSError, RuntimeError)
and mapped to HTTP 503 — a transient, retryable status. Every single
search/detail request then burned the full 5-attempt exponential
backoff (up to ~60s of sleeps, compounding across up to 100 pages and
1000 detail-enrichment requests), blowing past the Actor's default run
timeout without ever raising — hence TIMED-OUT, not FAILED, and zero
visibility in our own run history (the failures all belonged to
customers).
Added PermanentProxyError in scraper.py. _try_get now catches
curl_cffi.requests.exceptions.ProxyError specifically and raises it
immediately instead of mapping it to a retryable status — the Actor now
fails loud on the first proxy-auth rejection instead of silently
exhausting the retry budget on a condition that cannot self-heal within
the run.
Added tests/test_proxy_error_fail_fast.py — pins the exact regression
(ProxyError -> fail fast) and confirms genuine transient network errors
keep their existing retry semantics.
Added tests/fixtures/input.qa.json (small, enrichDetails: false) for
cloud QA.
0.4.0 — 2026-06-10
Force-residential proxy guard: _resolve_proxy_configuration now always
injects RESIDENTIAL into apifyProxyGroups when the group is missing,
empty, or set to a datacenter-only group — preventing the HTTP 403 that
customers hit when running without residential proxy.
Fail-fast on proxy unavailable: if Actor.create_proxy_configuration raises
or returns None the Actor exits immediately with a clear RuntimeError
describing the required plan/config, rather than silently returning empty
results from datacenter exits.
country_code (apifyProxyCountry) preserved through the guard.
Updated models.py proxy field description and input_schema.json proxy
description to document the RESIDENTIAL requirement.
Added tests/test_proxy_guard.py with unit coverage for all guard branches.
0.3.0 — 2026-06-05
Config-refresh re-push: RESIDENTIAL proxy group explicitly set in both
input_schema.jsondefault and prefill so Apify auto-QA receives
residential exits rather than datacenter IPs, clearing the 403 / "Under
maintenance" trap triggered by DataDome-class anti-bot on coches.net.
No code changes — build is functionally identical to 0.2; only the
published proxy config is updated.
0.2.0 — 2026-06-03
Per-attempt proxy session rotation: each retry now opens a fresh AsyncSession
with a new session_id (new residential exit IP) and a randomly-picked
browser impersonation profile, defeating persistent IP/fingerprint blocks.
Removed the single static proxy URL resolved at startup; the ProxyConfiguration
object is now threaded through to the scraper for per-request fresh URLs.
Fixed DockerfileCMD to use python -m src (via __main__.py).