SeLoger Scraper — France Real Estate Listings | $1.19/1K avatar

SeLoger Scraper — France Real Estate Listings | $1.19/1K

Pricing

from $1.07 / 1,000 seloger scraper — france real estate listings | $1.19/1ks

Go to Apify Store
SeLoger Scraper — France Real Estate Listings | $1.19/1K

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

Vitalii Bondarev

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

8 days ago

Last modified

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

FieldTypeDefaultDescription
searchUrlstring(required)A seloger.com search-results URL. Set your filters on seloger.com, then copy the URL from your browser.
maxItemsinteger100Max listings to return (0 = unlimited)
proxyConfigurationproxyRESIDENTIAL FRApify 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

FieldDescription
listing_idSeLoger internal listing ID
urlDirect URL to the listing (may be null — see caveats)
title / descriptionListing headline / summary
transaction_typesale or rent
property_typeapartment, house, etc.
price / price_per_m2 / monthly_priceEUR
rooms / bedrooms / surface_m2 / floor
energy_class / ges_classDPE/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_linkagency_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_atProvenance/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 initialData field 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.py is defensive by design: every field falls back to None and deducts parse_confidence rather 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 id plus 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 by immoscout24-listings in this fleet.
  • url is never fabricated. If no URL-shaped field is found on a card, url is null with a url_missing warning 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-fetchDetails scope). 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 totalItems count), 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.