lbc-rs

Crates.iolbc-rs
lib.rslbc-rs
version0.1.1
created_at2025-08-23 14:12:36.855928+00
updated_at2025-08-23 14:28:21.447183+00
descriptionUnofficial client for Leboncoin API, inspired by the Python implementation etienne-hd/lbc
homepage
repositoryhttps://github.com/lheintzmann1/lbc-rs
max_upload_size
id1807542
size130,189
Lucas Heintzmann (lheintzmann1)

documentation

README

lbc-rs

Apache License MIT License Crates.io docs.rs

Unofficial Rust client for Leboncoin API

This project is heavily inspired by the excellent Python implementation: etienne-hd/lbc

use lbc::{Client, City, Category, Sort, AdType};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    let location = City::new(
        48.85994982004764,
        2.33801967847424,
        Some(10_000), // 10 km radius
        Some("Paris".to_string())
    );

    let result = client.search()
        .text("maison")
        .locations(vec![location.into()])
        .page(1)
        .limit(35)
        .sort(Sort::Newest)
        .ad_type(AdType::Offer)
        .category(Category::Immobilier)
        .square(200, 400)
        .price(300_000, 700_000)
        .execute()
        .await?;

    for ad in result.ads {
        if let (Some(url), Some(subject), price) = (ad.url, ad.subject, ad.price()) {
            println!("{} - {} - {:?}", url, subject, price);
        }
    }

    Ok(())
}

lbc-rs is not affiliated with, endorsed by, or in any way associated with Leboncoin or its services. Use at your own risk.

This project is heavily inspired by the excellent Python implementation: etienne-hd/lbc

Installation

Add this to your Cargo.toml:

[dependencies]
lbc-rs = "0.1"
tokio = { version = "1.0", features = ["full"] }

Usage

Creating a Client

use lbc::Client;

// Basic client
let client = Client::new();

// Client with proxy
use lbc::Proxy;
let proxy = Proxy::with_auth(
    "proxy.example.com".to_string(),
    8080,
    "username".to_string(),
    "password".to_string()
);

let client = Client::builder()
    .proxy(proxy)
    .timeout(std::time::Duration::from_secs(60))
    .max_retries(10)
    .build()?;

Searching for Ads

Basic Search

let result = client.search()
    .text("smartphone")
    .category(Category::Electronique)
    .execute()
    .await?;

println!("Found {} ads", result.ads.len());

Advanced Search with Filters

use lbc::{City, Region, Department, Sort, AdType, OwnerType};

let paris = City::new(48.8566, 2.3522, Some(5_000), Some("Paris".to_string()));
let idf = Region::IleDeFrance;

let result = client.search()
    .text("appartement")
    .category(Category::ImmobilierVentes)
    .locations(vec![paris.into(), idf.into()])
    .sort(Sort::Cheapest)
    .ad_type(AdType::Offer)
    .owner_type(OwnerType::Private)
    .price(200_000, 500_000)
    .square(40, 80)
    .rooms(2, 4)
    .page(1)
    .limit(50)
    .execute()
    .await?;

Search with URL

You can also search using a full Leboncoin URL:

let result = client.search()
    .url("https://www.leboncoin.fr/recherche?category=9&text=maison&locations=Paris__48.86023250788424_2.339006433295173_9256&square=100-200&price=500000-1000000".to_string())
    .execute()
    .await?;

Getting User Information

let user = client.get_user("57f99bb6-0446-4b82-b05d-a44ea7bcd2cc").await?;

if let Some(name) = user.name {
    println!("User: {}", name);
}

if user.is_pro() {
    println!("This is a professional user");
    if let Some(pro) = user.pro {
        if let Some(store_name) = pro.online_store_name {
            println!("Store: {}", store_name);
        }
    }
}

Getting Ad Details

let ad = client.get_ad("2391847319").await?;

if let Some(subject) = ad.subject {
    println!("Title: {}", subject);
}

if let Some(body) = ad.body {
    println!("Description: {}", body);
}

if let Some(price) = ad.price() {
    println!("Price: €{:.2}", price);
}

// Get the seller's information
if let Ok(Some(user)) = ad.get_user().await {
    if let Some(name) = user.name {
        println!("Seller: {}", name);
    }
}

Location Types

The library supports three types of location filters:

City with Coordinates

use lbc::City;

let city = City::new(
    48.8566,  // latitude
    2.3522,   // longitude
    Some(10_000), // radius in meters (optional)
    Some("Paris".to_string()) // city name (optional)
);

Region

use lbc::Region;

let region = Region::IleDeFrance;
let location = region.into(); // Convert to Location

Department

use lbc::Department;

let department = Department::Paris;
let location = department.into(); // Convert to Location

Error Handling

The library provides detailed error types:

use lbc::LbcError;

match client.search().text("test").execute().await {
    Ok(result) => {
        println!("Found {} ads", result.ads.len());
    }
    Err(LbcError::DatadomeError(msg)) => {
        eprintln!("Blocked by anti-bot protection: {}", msg);
        // Consider using a proxy or reducing request frequency
    }
    Err(LbcError::NotFoundError(msg)) => {
        eprintln!("Resource not found: {}", msg);
    }
    Err(LbcError::RequestError(msg)) => {
        eprintln!("Request failed: {}", msg);
    }
    Err(e) => {
        eprintln!("Other error: {}", e);
    }
}

403 Error (Datadome Protection)

If you encounter a 403 Forbidden error, it usually means your requests are being blocked by Datadome. To resolve this:

  1. Reduce request frequency: Add delays between requests
  2. Use a clean proxy: Preferably located in France
  3. Use residential or mobile proxies: These are less likely to be detected
  4. Rotate user agents: The client automatically uses random user agents
// Example with delays
use tokio::time::{sleep, Duration};

for page in 1..=5 {
    let result = client.search()
        .text("voiture")
        .page(page)
        .execute()
        .await?;
    
    // Process results...
    
    // Add delay between requests
    sleep(Duration::from_secs(2)).await;
}

Categories

The library includes all Leboncoin categories:

use lbc::Category;

// Main categories
Category::ToutesCategories
Category::Vehicules
Category::Immobilier
Category::Electronique
Category::MaisonJardin
Category::Mode
Category::Loisirs
Category::Animaux
Category::Emploi

// Subcategories
Category::VehiculesVoitures
Category::ImmobilierVentes
Category::ElectroniqueOrdinateurs
// ... and many more

Features

  • Async/await support - Built with Tokio
  • Comprehensive search filters - Price, location, category, etc.
  • Location support - Cities, regions, departments
  • User information - Get seller profiles and ratings
  • Ad details - Full ad information including images
  • Proxy support - HTTP proxy configuration
  • Error handling - Detailed error types
  • Rate limiting protection - Automatic retries for 403 errors

Requirements

  • Rust 1.70+
  • Tokio runtime

License

This project is licensed under either of

at your option.

Acknowledgments

This project is heavily inspired by the excellent Python implementation: etienne-hd/lbc

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Disclaimer

This is an unofficial client and is not affiliated with Leboncoin. Use responsibly and respect the website's terms of service.

Commit count: 11

cargo fmt