Skip to content

About

Scrape Leboncoin (France's largest classifieds site) search results and ads into clean JSON/CSV - price, location, seller, car/property/category attributes, full descriptions - via the ScrapeUnblocker API. Python CLI + library.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Leboncoin Scraper

CI Python 3.9+ License: MIT Powered by ScrapeUnblocker

Scrape Leboncoin - France's largest classifieds site - into clean JSON or CSV. Search any keywords, category and location, filter by price, seller type and delivery, and get every ad with its price, location, seller and category attributes (car brand, mileage and fuel, bike type and size, property surface and energy class, ...). Optionally fetch each ad page for the full description.

Powered by ScrapeUnblocker: Leboncoin blocks plain HTTP clients and headless scripts with an aggressive bot check. The ScrapeUnblocker getPageSource API loads each page in a real browser and returns the HTML; this package reads the JSON data Leboncoin embeds in it, so you get structured fields without brittle CSS selectors.

Features

  • Search with the website's filters - keywords, category, city / department / region, price range, private or pro sellers, delivery available, sort by relevance, newest or price.
  • Any other filter - pass category-specific query parameters straight through (u_car_brand=RENAULT, fuel=4, ...), or scrape a search URL copied from your browser.
  • Rich, typed records - ad ID, title, price in EUR (cent-exact), category, publication / update / expiry dates, city, postcode, district, department, region, latitude / longitude, seller type, name, store ID and SIREN (pros), phone available, shippable, urgent, sponsored and boosted flags, images and every displayed attribute.
  • Ad details - --details (or get_ad()) adds the full description, every image and the favourites count.
  • Multi-page collection - 35 ads per page up to Leboncoin's 100-page limit, with a --max-pages cap, de-duplication by ad ID and several keyword sets merged in one run.
  • Clean results - the promoted "A la une" ads Leboncoin injects at the top of every page (often unrelated to the search) are dropped unless you ask for them.
  • Resilient - timeouts, transient API errors and bot-check pages are retried with doubling backoff.
  • JSON or CSV - CSV gets one attr_<key> column per category attribute, UTF-8 with BOM so Excel shows accents correctly.
  • CLI + Python library, fully typed, tested offline with a mocked client.

Install

git clone https://github.com/ScrapeUnblocker/leboncoin-scraper.git
cd leboncoin-scraper
pip install .

Get an API key at scrapeunblocker.com and expose it as SCRAPEUNBLOCKER_KEY (the official SDK reads it from there):

export SCRAPEUNBLOCKER_KEY=your_key_here        # Windows PowerShell: $env:SCRAPEUNBLOCKER_KEY="your_key_here"

or copy .env.example to .env and load it with your tool of choice.

CLI usage

# Electric bikes in Lyon under 1,500 EUR, newest first
leboncoin-scraper search "velo electrique" --category velos --location Lyon \
    --price-max 1500 --sort newest --limit 50 --pretty

# Several keyword sets, merged and de-duplicated, private sellers only, delivery available
leboncoin-scraper search "nintendo switch" "switch oled" --owner private --shippable \
    --limit 100 --format csv --output switch.csv

# Filters only: used electric cars in Ile-de-France (region r_12), cheapest first
leboncoin-scraper search --category voitures --location r_12 -p fuel=4 \
    --price-min 5000 --sort price-asc --limit 70 -f csv -o electric_cars.csv

# A search URL copied from your browser, with full ad details
leboncoin-scraper url "https://www.leboncoin.fr/recherche?category=55&text=vtt&locations=d_74" \
    --limit 20 --details --pretty

# One or more ad pages, by ID or URL
leboncoin-scraper ad 3279125682 https://www.leboncoin.fr/ad/velos/3262132078 --pretty

# Category slugs accepted by --category
leboncoin-scraper categories
Option Meaning
-c, --category Category slug (voitures, velos, ventes_immobilieres, ... - see categories) or any numeric category ID
-l, --location City (Lyon), department (d_69) or region (r_12); repeat for several
--price-min, --price-max Price range in EUR (either end may be omitted)
--owner private|pro Only private or only professional sellers
--shippable Only ads that offer delivery
-s, --sort relevance (default), newest (latest published or updated first), price-asc, price-desc
-p, --param KEY=VALUE Any other Leboncoin filter from a browser search URL, e.g. u_car_brand=RENAULT, fuel=4
-n, --limit Maximum number of ads (default 35 = one page)
--start-page, --max-pages Where to start and how many pages to fetch at most
--details Fetch every ad page too (full description, all images, favourites)
--include-sponsored Keep the promoted "A la une" ads
-f, --format json|csv, -o, --output Output format and file (CSV needs --output)
--proxy-country Country to route requests through (default FR)
--retries Retries per page on transient errors (default 3)

Keyword search on Leboncoin also matches ad descriptions, so a plain "velo electrique" search also returns e-bike parts, scooters and even property listings. Add --category for tight results.

Run leboncoin-scraper <command> --help for every option. python -m leboncoin_scraper works too.

Library usage

from leboncoin_scraper import LeboncoinScraper, to_csv

lbc = LeboncoinScraper()  # reads SCRAPEUNBLOCKER_KEY; or LeboncoinScraper(api_key="...")

bikes = lbc.search(
    "velo electrique",
    category="velos",
    location="d_69",  # the Rhone department
    price_max=1500,
    owner_type="private",
    sort="newest",
    limit=70,
)
for ad in bikes[:5]:
    print(ad.price, ad.title, ad.city, ad.attributes.get("bicycle_type"))

# Category-specific filters are plain query parameters
renaults = lbc.search(category="voitures", params={"u_car_brand": "RENAULT"}, limit=35)

# Any search URL from your browser
flats = lbc.search_url("https://www.leboncoin.fr/recherche?category=10&locations=Bordeaux")

# Full ad page: description, every image, favourites
ad = lbc.get_ad(bikes[0].url)
print(ad.description)

to_csv(bikes, "bikes.csv")

search_many(["velo", "vtt"], location="Lyon") runs several keyword sets and removes duplicates; pass a shared seen=set() to search() to de-duplicate across your own calls.

Examples

Script What it does
examples/search_to_json.py Search and save the ads as JSON
examples/used_cars_csv.py Electric cars in Ile-de-France to CSV, with year and mileage columns
examples/new_listings_alert.py Print only the ads that appeared since the last run (one request per run)

Example output

leboncoin-scraper ad 3279125682 --pretty (seller details redacted, images and description shortened):

[
  {
    "list_id": "3279125682",
    "url": "https://www.leboncoin.fr/ad/voitures/3279125682",
    "title": "Nissan leaf",
    "price": 5000,
    "currency": "EUR",
    "category_id": "2",
    "category_name": "Voitures",
    "ad_type": "offer",
    "status": "active",
    "published_at": "2026-09-29 18:06:14",
    "updated_at": "2026-09-29 18:06:14",
    "expires_at": "2026-11-28 17:06:14",
    "city": "Fontains",
    "zipcode": "77370",
    "district": null,
    "department_id": "77",
    "department_name": "Seine-et-Marne",
    "region_id": "12",
    "region_name": "Ile-de-France",
    "latitude": 48.52641,
    "longitude": 3.00171,
    "seller_type": "private",
    "seller_name": "<seller display name>",
    "seller_id": "<store id>",
    "siren": null,
    "has_phone": true,
    "shippable": null,
    "urgent": false,
    "sponsored": false,
    "boosted": false,
    "image_count": 3,
    "image_url": "https://img.leboncoin.fr/api/v1/lbcpb1/images/da/b5/ec/dab5ec7da57723cb8f953a818da7ff2a70bb9ca0.jpg?rule=ad-large",
    "images": ["https://img.leboncoin.fr/api/v1/lbcpb1/images/da/b5/ec/dab5ec7da57723cb8f953a818da7ff2a70bb9ca0.jpg?rule=ad-large", "..."],
    "attributes": {
      "u_car_brand": "NISSAN",
      "u_car_model": "Leaf",
      "regdate": "2014",
      "mileage": "127479 km",
      "fuel": "Électrique",
      "gearbox": "Automatique",
      "doors": "5",
      "seats": "5",
      "issuance_date": "10/2014",
      "vehicle_type": "Berline",
      "vehicule_color": "Blanc",
      "horsepower": "3 Cv",
      "horse_power_din": "109 Ch",
      "vehicle_vsp": "Avec permis"
    },
    "description": "Petit voiture electrique encore une capacité de 100km baterie a 75 pourcent très bien pour la ville ...",
    "favorites": 3,
    "query": null
  }
]

Field notes:

  • price is in euros, taken from Leboncoin's cent-exact value (449.9, not 450).
  • Dates are Leboncoin's local time (Europe/Paris), YYYY-MM-DD HH:MM:SS. updated_at changes when the ad is edited or republished; newest sorts by it.
  • attributes holds the criteria shown on the ad page, as {key: label}; keys depend on the category. Search results already include them.
  • description and favorites come from the ad page only (--details / get_ad()), and search results may list only the first image.
  • sponsored marks the promoted "A la une" placements; boosted marks ads that bought extra visibility.

Project layout

leboncoin-scraper/
├── src/leboncoin_scraper/
│   ├── __init__.py      # public API + __version__
│   ├── scraper.py       # LeboncoinScraper: fetching, retries, pagination, dedupe
│   ├── parsing.py       # __NEXT_DATA__ JSON -> Ad records, error detection
│   ├── urls.py          # search / ad URL builders, categories, sorts
│   ├── models.py        # Ad and SearchPage dataclasses
│   ├── export.py        # JSON and CSV export
│   ├── cli.py           # argparse CLI (leboncoin-scraper)
│   └── __main__.py      # python -m leboncoin_scraper
├── examples/            # runnable scripts
├── tests/               # offline tests with a mocked client (no API calls)
├── pyproject.toml
├── Makefile
└── .github/workflows/ci.yml

Development

python -m venv .venv && source .venv/bin/activate
make install      # pip install -e ".[dev]"
make lint         # ruff check
make format       # ruff format
make test         # pytest (offline, no API key needed)
pre-commit install

The tests replay synthetic Leboncoin pages through a fake client, so they spend no API credit and run in CI on Python 3.9 and 3.12.

Responsible use

Scrape at a reasonable pace, respect Leboncoin's terms of use, and remember that ads from private sellers can contain personal data: if you store or process it, the GDPR applies. This project is not affiliated with or endorsed by Leboncoin.

Links

License

MIT - Copyright (c) 2026 ScrapeUnblocker

About

Scrape Leboncoin (France's largest classifieds site) search results and ads into clean JSON/CSV - price, location, seller, car/property/category attributes, full descriptions - via the ScrapeUnblocker API. Python CLI + library.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages