Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.15.6] - 2026-07-07

### Added

- Add Leboncoin Scraper API client (France) — 10 endpoints: search, ad detail, similar ads, seller profile + listings, markets/regions/departments/categories/location search.

## [0.15.5] - 2026-07-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "scrapebadger"
version = "0.15.5"
version = "0.15.6"
description = "Official Python SDK for ScrapeBadger - Async web scraping APIs for Twitter and more"
readme = "README.md"
license = { text = "MIT" }
Expand Down
93 changes: 92 additions & 1 deletion src/scrapebadger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,73 @@ async def main():
SellerProfileResponse as EbaySellerProfileResponse,
)
from scrapebadger.google.client import GoogleClient
from scrapebadger.leboncoin.client import LeboncoinClient
from scrapebadger.leboncoin.models import (
Ad as LeboncoinAd,
)
from scrapebadger.leboncoin.models import (
AdResponse as LeboncoinAdResponse,
)
from scrapebadger.leboncoin.models import (
Attribute as LeboncoinAttribute,
)
from scrapebadger.leboncoin.models import (
CategoriesResponse as LeboncoinCategoriesResponse,
)
from scrapebadger.leboncoin.models import (
Category as LeboncoinCategory,
)
from scrapebadger.leboncoin.models import (
Department as LeboncoinDepartment,
)
from scrapebadger.leboncoin.models import (
DepartmentsResponse as LeboncoinDepartmentsResponse,
)
from scrapebadger.leboncoin.models import (
FeedbackScores as LeboncoinFeedbackScores,
)
from scrapebadger.leboncoin.models import (
Images as LeboncoinImages,
)
from scrapebadger.leboncoin.models import (
Location as LeboncoinLocation,
)
from scrapebadger.leboncoin.models import (
LocationSearchResponse as LeboncoinLocationSearchResponse,
)
from scrapebadger.leboncoin.models import (
LocationSuggestion as LeboncoinLocationSuggestion,
)
from scrapebadger.leboncoin.models import (
MarketsResponse as LeboncoinMarketsResponse,
)
from scrapebadger.leboncoin.models import (
Owner as LeboncoinOwner,
)
from scrapebadger.leboncoin.models import (
Region as LeboncoinRegion,
)
from scrapebadger.leboncoin.models import (
RegionsResponse as LeboncoinRegionsResponse,
)
from scrapebadger.leboncoin.models import (
SearchResponse as LeboncoinSearchResponse,
)
from scrapebadger.leboncoin.models import (
Seller as LeboncoinSeller,
)
from scrapebadger.leboncoin.models import (
SellerListingsResponse as LeboncoinSellerListingsResponse,
)
from scrapebadger.leboncoin.models import (
SellerResponse as LeboncoinSellerResponse,
)
from scrapebadger.leboncoin.models import (
SimilarResponse as LeboncoinSimilarResponse,
)
from scrapebadger.leboncoin.models import (
StoreRatingReview as LeboncoinStoreRatingReview,
)
from scrapebadger.realtor.client import RealtorClient
from scrapebadger.realtor.models import (
Address as RealtorAddress,
Expand Down Expand Up @@ -481,7 +548,7 @@ async def main():
Video as YoutubeVideo,
)

__version__ = "0.15.5"
__version__ = "0.15.6"

__all__ = [
# TikTok core models
Expand Down Expand Up @@ -542,6 +609,30 @@ async def main():
"GoogleClient",
"InsufficientCreditsError",
"ItemDetailResponse",
# Leboncoin
"LeboncoinAd",
"LeboncoinAdResponse",
"LeboncoinAttribute",
"LeboncoinCategoriesResponse",
"LeboncoinCategory",
"LeboncoinClient",
"LeboncoinDepartment",
"LeboncoinDepartmentsResponse",
"LeboncoinFeedbackScores",
"LeboncoinImages",
"LeboncoinLocation",
"LeboncoinLocationSearchResponse",
"LeboncoinLocationSuggestion",
"LeboncoinMarketsResponse",
"LeboncoinOwner",
"LeboncoinRegion",
"LeboncoinRegionsResponse",
"LeboncoinSearchResponse",
"LeboncoinSeller",
"LeboncoinSellerListingsResponse",
"LeboncoinSellerResponse",
"LeboncoinSimilarResponse",
"LeboncoinStoreRatingReview",
"MarketInfo",
"MarketsResponse",
"NewReleasesResponse",
Expand Down
2 changes: 1 addition & 1 deletion src/scrapebadger/_internal/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
T = TypeVar("T")

# User agent for SDK requests
SDK_VERSION = "0.15.5"
SDK_VERSION = "0.15.6"
USER_AGENT = f"scrapebadger-python/{SDK_VERSION}"


Expand Down
30 changes: 30 additions & 0 deletions src/scrapebadger/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from scrapebadger.amazon.client import AmazonClient
from scrapebadger.ebay.client import EbayClient
from scrapebadger.google.client import GoogleClient
from scrapebadger.leboncoin.client import LeboncoinClient
from scrapebadger.realtor.client import RealtorClient
from scrapebadger.reddit.client import RedditClient
from scrapebadger.tiktok.client import TikTokClient
Expand Down Expand Up @@ -126,6 +127,7 @@ def __init__(
self._youtube: YoutubeClient | None = None
self._tiktok: TikTokClient | None = None
self._realtor: RealtorClient | None = None
self._leboncoin: LeboncoinClient | None = None

@property
def config(self) -> ClientConfig:
Expand Down Expand Up @@ -327,6 +329,34 @@ def realtor(self) -> RealtorClient:
self._realtor = RealtorClient(self._base_client)
return self._realtor

@property
def leboncoin(self) -> LeboncoinClient:
"""Access Leboncoin Scraper API operations.

Returns:
LeboncoinClient providing access to all 10 Leboncoin endpoints
(search, ad detail, similar ads, seller profile/listings,
categories, regions, departments, location search, markets).

Example:
```python
# Search for ads
results = await client.leboncoin.search.search("velo")

# Get ad detail
detail = await client.leboncoin.ads.get_ad(2812345678)

# Get a seller profile
seller = await client.leboncoin.sellers.get_seller("12345678")

# Reference regions
regions = await client.leboncoin.reference.list_regions()
```
"""
if self._leboncoin is None:
self._leboncoin = LeboncoinClient(self._base_client)
return self._leboncoin

@property
def tiktok(self) -> TikTokClient:
"""Access TikTok Scraper API operations.
Expand Down
83 changes: 83 additions & 0 deletions src/scrapebadger/leboncoin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Leboncoin API module for ScrapeBadger SDK.

This module provides a comprehensive async client for scraping Leboncoin data
through the ScrapeBadger API. All methods are async and return strongly-typed
Pydantic models.

Example:
```python
from scrapebadger import ScrapeBadger

async with ScrapeBadger(api_key="your-key") as client:
# Search for ads
results = await client.leboncoin.search.search("velo")
for ad in results.ads:
print(f"{ad.subject}: {ad.price_eur}")

# Get ad detail
detail = await client.leboncoin.ads.get_ad(2812345678)
print(detail.ad.subject)

# Get a seller profile
seller = await client.leboncoin.sellers.get_seller("12345678")
print(f"{seller.seller.name}: {seller.seller.total_ads} ads")
```
"""

from scrapebadger.leboncoin.client import LeboncoinClient
from scrapebadger.leboncoin.models import (
Ad,
AdResponse,
Attribute,
CategoriesResponse,
Category,
Department,
DepartmentsResponse,
FeedbackScores,
Images,
Location,
LocationSearchResponse,
LocationSuggestion,
MarketsResponse,
Owner,
Region,
RegionsResponse,
SearchResponse,
Seller,
SellerListingsResponse,
SellerResponse,
SimilarResponse,
StoreRatingReview,
)

__all__ = [
# Ad
"Ad",
"AdResponse",
"Attribute",
# Reference
"CategoriesResponse",
"Category",
"Department",
"DepartmentsResponse",
# Seller
"FeedbackScores",
# Shared
"Images",
# Client
"LeboncoinClient",
"Location",
"LocationSearchResponse",
"LocationSuggestion",
"MarketsResponse",
"Owner",
"Region",
"RegionsResponse",
# Search
"SearchResponse",
"Seller",
"SellerListingsResponse",
"SellerResponse",
"SimilarResponse",
"StoreRatingReview",
]
80 changes: 80 additions & 0 deletions src/scrapebadger/leboncoin/ads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""Leboncoin Ads API client.

Provides methods for fetching a single ad's full detail and its similar ads.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from scrapebadger.leboncoin.models import AdResponse, SimilarResponse

if TYPE_CHECKING:
from scrapebadger._internal.client import BaseClient


class AdsClient:
"""Client for Leboncoin ad endpoints (detail, similar).

Example:
```python
async with ScrapeBadger(api_key="key") as client:
detail = await client.leboncoin.ads.get_ad(2812345678)
print(detail.ad.subject)

similar = await client.leboncoin.ads.get_similar(2812345678)
print(f"{len(similar.ads)} similar ads")
```
"""

def __init__(self, client: BaseClient) -> None:
"""Initialize ads client.

Args:
client: The base HTTP client.
"""
self._client = client

async def get_ad(self, list_id: int) -> AdResponse:
"""Get a single Leboncoin ad's full detail.

Args:
list_id: The Leboncoin ad id.

Returns:
Ad detail response including images, attributes, location, and owner.

Raises:
NotFoundError: If the ad doesn't exist.
AuthenticationError: If the API key is invalid.

Example:
```python
detail = await client.leboncoin.ads.get_ad(2812345678)
ad = detail.ad
print(f"{ad.subject}: {ad.price_eur} {ad.currency}")
```
"""
response = await self._client.get(f"/v1/leboncoin/ads/{list_id}")
return AdResponse.model_validate(response)

async def get_similar(self, list_id: int, *, limit: int | None = None) -> SimilarResponse:
"""Get ads similar to a given Leboncoin ad.

Args:
list_id: The Leboncoin ad id.
limit: Maximum number of similar ads to return.

Returns:
Similar response with the source list id and matching ads.

Example:
```python
result = await client.leboncoin.ads.get_similar(2812345678, limit=10)
for ad in result.ads:
print(ad.subject)
```
"""
params: dict[str, Any] = {"limit": limit}
response = await self._client.get(f"/v1/leboncoin/ads/{list_id}/similar", params=params)
return SimilarResponse.model_validate(response)
Loading
Loading