Bien'ici Property Scraper (France) avatar

Bien'ici Property Scraper (France)

Pricing

from $0.84 / 1,000 results

Go to Apify Store
Bien'ici Property Scraper (France)

Bien'ici Property Scraper (France)

Scrapes flats and houses for sale or rent from Bien'ici, France's #3 real estate portal. Search any city, district or postal code; returns price, surface area, rooms, bedrooms, floor, energy class, full description, photos and seller details.

Pricing

from $0.84 / 1,000 results

Rating

0.0

(0)

Developer

Ibnu Adzim

Ibnu Adzim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Scrapes flats and houses for sale or rent from Bien'ici — France's #3 real estate portal (after SeLoger and Leboncoin Immo), and one of the few in this portfolio where a single search call returns everything: no separate detail-page fetch exists or is needed.

Public data only. No login, no cookies, no browser.

What you get

Two record types share one dataset, told apart by recordType.

PROPERTY — one row per listing

Every field Bien'ici's own search response carries, passed through verbatim: price, surface area, rooms, bedrooms, floor, energy/greenhouse-gas classification, full description, the complete photo set, and the seller/agency name — all in one row, no includePropertyDetails toggle because there is nothing more to fetch.

SEARCH_SUMMARY — one row per location searched

Upstream's own match total, how many rows this run returned, and whether it hit Bien'ici's from/size result-window ceiling.

Input

FieldWhat it does
Buy / rentwhich side of the market
Property typeflat or house
Locationsfree text resolved through Bien'ici's own geocoder: Paris, Paris 15e, 75015, Lyon… one search per entry
Price / bedroomsmin–max filters, verified to actually shift the match count
Max properties per location0 = unlimited (up to Bien'ici's own ~2,400-row ceiling)
Results per requestpage size, default 24

Example

{
"transactionType": "buy",
"propertyType": "flat",
"locations": ["Paris 11e", "Paris 20e"],
"minPrice": 300000,
"maxPrice": 600000,
"minBedrooms": 2,
"maxItems": 500
}

Two things this actor is honest about

1. An unrecognised transactionType is a silent-widen trap upstream, so this actor refuses it instead. Bien'ici does not error on a bad value — it answers 200 with total equal to buy-count plus rent-count, quietly mixing both transaction types into one result set. Confirmed live (buy=7,591 + rent=1,234 ≈ bogus-value total of 8,826). Only buy/rent are accepted; anything else is refused before the first request rather than risk a dataset that looks filtered but isn't.

2. Bien'ici stops around 2,400–2,500 rows per query, with an honest error. Past that, realEstateAds.json answers HTTP 400 "Too many ads requested" — not a silent empty page, not a clamp to the last page. A run that hits it gets resultCapReached: true and a log line telling you to narrow by price/bedrooms or search a smaller area:

WARN buy/flat/paris: upstream reports 7592 matches but Bien'ici's realEstateAds.json
refuses from > 2400 ('Too many ads requested') -- narrow by price/bedrooms
or search a smaller area to reach the rest.

That is exactly why Locations is a list — several narrow searches return far more data than one broad one.

Notes on reliability

  • No WAF challenge. Serves data cold on every TLS profile tested. The whole HTML site is a client-side SPA (every URL serves the same ~15KB shell) — the two JSON endpoints this actor calls are the same unauthenticated, unthrottled ones the SPA itself uses.
  • Runs unattended. No human-captured session, no expiring token.
  • Unknown locations fail cleanly as not_found — the geocoder answers an empty array, never a fallback to a nationwide search.
  • minSurface is not offered. Tried during recon and confirmed silently ignored by the API (match count did not move) — not shipped as a broken-looking option.
  • Residential proxy by default on cloud runs.

Output envelope

Every record carries _input, _source and _scrapedAt. Upstream field names pass through verbatim — no renaming, no nested propertyDetails object (there is nothing to nest; the search row IS the full record). _source is S1-json-search on every row.

Note propertyType/transactionType on a property row are upstream's own fields; the location/filters you searched with are propertyTypeQueried/ transactionTypeQueried/locationQueried instead, so the two never collide.

propertyUrl is constructed from the listing id (https://www.bienici.com/annonce/<id>) as a convenience human link — it resolves to the same client-side app shell as every other Bien'ici URL, so fetching it yourself will not return more data than this actor already gives you.

See CRAWLING_METHOD.md for the full reverse-engineering trail, including the geocoder discovery and the pagination-ceiling bisection.