SeLoger Scraper — France Real Estate Listings | $1.19/1K
Pricing
from $1.07 / 1,000 seloger scraper — france real estate listings | $1.19/1ks
SeLoger Scraper — France Real Estate Listings | $1.19/1K
Scrape SeLoger.com (France's #1 real estate portal) from a search-results URL you paste. Returns title, price, transaction type, property type, rooms, surface m², location, agency contact, photos, and listing URL.
Pricing
from $1.07 / 1,000 seloger scraper — france real estate listings | $1.19/1ks
Rating
0.0
(0)
Developer
Vitalii Bondarev
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
3
Monthly active users
8 days ago
Last modified
Categories
Share
SeLoger Listings Scraper
Scrape SeLoger.com (France's #1 real estate portal) from a search-results URL you paste — no need to configure filters in this actor, just set them on seloger.com and copy the resulting URL.
Features
- Scrape any SeLoger search (sale or rent, any city/price/room filter you set on their site)
- Returns per-listing: price, transaction type, property type, rooms/bedrooms, surface m², location, agency/contact, photos, and listing URL
- Uses SeLoger's own embedded search-results JSON (
window["initialData"]) — no HTML scraping, no browser - Pay per result — you only pay for listing records actually extracted
- Automatic pagination up to
maxItems, with residential-proxy session rotation on a block
Input
| Field | Type | Default | Description |
|---|---|---|---|
searchUrl | string | (required) | A seloger.com search-results URL. Set your filters on seloger.com, then copy the URL from your browser. |
maxItems | integer | 100 | Max listings to return (0 = unlimited) |
proxyConfiguration | proxy | RESIDENTIAL FR | Apify Residential proxy, France — required for reliable access |
Why a search URL instead of filter fields?
SeLoger's location filter uses opaque internal place/geo IDs, not plain postal codes or city names — several of the Store's own traction-proven SeLoger scrapers (azzouzana/seloger-mass-products-scraper-by-search-url, memo23/seloger-scraper) use the same "paste your search URL" contract for exactly this reason. Guessing the ID scheme wrong would silently return 0 or wrong-city results, which is worse than asking the buyer to copy a URL.
Output fields
| Field | Description |
|---|---|
listing_id | SeLoger internal listing ID |
url | Direct URL to the listing (may be null — see caveats) |
title / description | Listing headline / summary |
transaction_type | sale or rent |
property_type | apartment, house, etc. |
price / price_per_m2 / monthly_price | EUR |
rooms / bedrooms / surface_m2 / floor | |
energy_class / ges_class | DPE/GES letter grade (search-card level; full detail needs the listing page) |
city / district / postal_code / department | |
latitude / longitude | |
agency_id / agency_name / agency_phone / agency_link | agency_name is the contact display name shown on the search card, which may be an individual agent rather than the agency brand |
photos / photo_count / virtual_visit_url | |
is_new / is_exclusive / tags | |
publication_date | |
page_number / source / parse_confidence / warnings / scraped_at | Provenance/QA fields |
Access path
SeLoger has no public search API. Its search-results page is server-rendered and ships the full result set as a double-encoded JSON literal inside an inline <script> tag: window["initialData"] = JSON.parse("...") — the argument is itself a JSON-encoded string, so it decodes twice (JS-string-unescape, then json.loads). This actor fetches that page with curl_cffi (Chrome TLS impersonation, no browser) and decodes it directly — no HTML/CSS-selector parsing on the happy path.
Third-party scraping vendors document SeLoger as running anti-bot fingerprinting/CAPTCHA challenges (DataDome-class) against non-residential traffic, so Apify RESIDENTIAL (FR) proxy is required for production reliability, per this fleet's access-ladder convention (see _shared/transport.py).
Honest caveats (read before relying on this in production)
- Field-name mapping is unverified against a live SeLoger response. The
initialDatafield names used here (price,surface,cardType,cityLabel,zipCode,contactName,phoneNumber,classifiedURL, …) come from ScrapFly's public engineering write-up on scraping SeLoger, not from an authenticated cloud run against the live site (out of scope for this build — no live/paid access path was exercised).normalize.pyis defensive by design: every field falls back toNoneand deductsparse_confidencerather than raising, so a wrong/renamed key degrades gracefully instead of crashing the run — but the exact field set should be spot-checked against a real cloud run (with a real RESIDENTIAL FR proxy) before this actor is published or relied on for paid delivery. - The exact top-level "cards" container key is unconfirmed. The parser locates the listing array by a tolerant structural walk (first list of dicts that "look like" listing cards — has an
idplus signal fields), not a hardcoded dotted path, specifically because the wrapper key wasn't confirmed live. This is the same tolerant-fallback pattern already used byimmoscout24-listingsin this fleet. urlis never fabricated. If no URL-shaped field is found on a card,urlisnullwith aurl_missingwarning rather than guessing a possibly-wrong deep-link scheme.- Full DPE/GES, exact address, and co-ownership charges live on the detail page, not the search-card payload — this actor is search-summary-only (matching the sibling
immoweb-properties-scraper's pre-fetchDetailsscope). Detail-page enrichment (also JSON-embedded, via__NEXT_DATA__on the property page per the same ScrapFly source) is a straightforward v2 addition once the search-card path is verified live. - Termination is by empty-page detection (not a parsed
totalItemscount), since the exact total-count key name is also unconfirmed — this trades a slightly less precise pagination estimate for correctness under an unverified schema.
Tests
Unit tests (tests/) run entirely offline against synthetic fixtures — no live network calls: cd actors/REAL_ESTATE/seloger-listings-scraper && python3 -m pytest -q.
Usage statistics
This Actor creates a small, content-free summary at the end of each run. It is used only to monitor reliability and improve this Actor. A copy is saved as USAGE_STATS in your own Apify key-value store, so you can see the exact record created for your run.
Set disableUsageStats to true in the input to opt out. Nothing is sent then; your USAGE_STATS record only says that statistics were disabled.
Only these fields are recorded:
- schema version, Actor name and build number;
- UTC start and finish hour (not a precise timestamp);
- run duration, number of results and time to the first result, each as a coarse range;
- whether the result was empty, the end status, and an error type from a fixed list;
- memory setting and counts of charged events;
- names of the input fields you set, never their values;
- the selected option for input fields that offer a fixed list of choices (for example a sort order).
We do not collect input text, search terms, URLs, domains, usernames, email addresses, names, proxy credentials, tokens, scraped records, output items, raw error messages, stack traces, or hashes of any of those values. Records are kept for no longer than 13 months, used only as aggregated operational statistics, and never sold or shared.
Additional fields (Phase 2)
This Actor also records your Apify user ID, whether Apify marks the account as paying, the size range of list inputs, the selected country when the input offers a fixed list of countries, and one category from a fixed Actor taxonomy. We use these fields only for aggregate reliability, repeat-use and cross-Actor analysis; reports suppress any cell with fewer than five distinct users.
The same disableUsageStats: true input flag turns these fields off too. The user ID is removed after 13 months; we do not export, sell, share, or attempt to re-identify this data.
Run-outcome signals (v2)
To learn whether a run did what it was asked to do, the record also holds a few more coarse ranges and yes/no flags. None of them contains content:
- the result limit you asked for (a range, when the input has one) and what share of it was delivered;
- results delivered per input item you listed (a range);
- output quality as ranges: how fully the result fields were filled, the share of rows that look like errors, the share of duplicate rows, and how many different fields appeared. These are counted in memory while results are saved; no result content is kept;
- how the run was started (console, API, schedule, webhook, another Actor);
- how it ended: stopped by you, timed out, reached the requested limit, stopped by the charge limit, and how many times the platform moved the run;
- if this Actor reports it: how many items to process worked or failed (ranges) and one failure reason from a fixed list;
- a short code made from the names of the input fields you set, never their values.
Repeat-run fingerprint (v2)
When your Apify user ID is recorded (see above), the record also holds an 8-character one-way code made from your input (proxy settings left out) and this Actor's name. It only lets us see that the same account ran the same input again soon after an unsatisfying run; we never see the input itself. It is stored only in the database, never published, and reports use it in aggregate with the same five-user minimum. It is the one exception to the statement above that no hashes are collected, and disableUsageStats: true turns it off.