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.5] - 2026-07-02

### Added

- **Realtor sub-client** (`client.realtor`) — real-estate listings across realtor.com (US) and realtor.ca (Canada) behind a single `market` parameter. Four endpoints: `search.search()`, `search.autocomplete()`, `properties.get_property()`, `reference.list_markets()`, with fully-typed Pydantic models (`RealtorSearchResponse`, `RealtorPropertyDetail`, etc.). (SCR-98)

## [0.15.4] - 2026-06-30

### 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.4"
version = "0.15.5"
description = "Official Python SDK for ScrapeBadger - Async web scraping APIs for Twitter and more"
readme = "README.md"
license = { text = "MIT" }
Expand Down
86 changes: 84 additions & 2 deletions src/scrapebadger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,67 @@ async def main():
SellerProfileResponse as EbaySellerProfileResponse,
)
from scrapebadger.google.client import GoogleClient
from scrapebadger.realtor.client import RealtorClient
from scrapebadger.realtor.models import (
Address as RealtorAddress,
)
from scrapebadger.realtor.models import (
Agent as RealtorAgent,
)
from scrapebadger.realtor.models import (
AutocompleteResponse as RealtorAutocompleteResponse,
)
from scrapebadger.realtor.models import (
Coordinate as RealtorCoordinate,
)
from scrapebadger.realtor.models import (
DetailGroup as RealtorDetailGroup,
)
from scrapebadger.realtor.models import (
Estimate as RealtorEstimate,
)
from scrapebadger.realtor.models import (
Flags as RealtorFlags,
)
from scrapebadger.realtor.models import (
MarketInfo as RealtorMarketInfo,
)
from scrapebadger.realtor.models import (
MarketsResponse as RealtorMarketsResponse,
)
from scrapebadger.realtor.models import (
Office as RealtorOffice,
)
from scrapebadger.realtor.models import (
OpenHouse as RealtorOpenHouse,
)
from scrapebadger.realtor.models import (
Phone as RealtorPhone,
)
from scrapebadger.realtor.models import (
Photo as RealtorPhoto,
)
from scrapebadger.realtor.models import (
PriceEvent as RealtorPriceEvent,
)
from scrapebadger.realtor.models import (
Property as RealtorProperty,
)
from scrapebadger.realtor.models import (
PropertyDetail as RealtorPropertyDetail,
)
from scrapebadger.realtor.models import (
School as RealtorSchool,
)
from scrapebadger.realtor.models import (
SearchResponse as RealtorSearchResponse,
)
from scrapebadger.realtor.models import (
Suggestion as RealtorSuggestion,
)
from scrapebadger.realtor.models import (
TaxRecord as RealtorTaxRecord,
)
from scrapebadger.reddit.models import (
PostCommentsResponse,
PostDetailResponse,
Expand Down Expand Up @@ -420,7 +481,7 @@ async def main():
Video as YoutubeVideo,
)

__version__ = "0.15.4"
__version__ = "0.15.5"

__all__ = [
# TikTok core models
Expand Down Expand Up @@ -496,6 +557,28 @@ async def main():
"Product",
"ProductDetailResponse",
"RateLimitError",
"RealtorAddress",
"RealtorAgent",
"RealtorAutocompleteResponse",
# TikTok client
"RealtorClient",
"RealtorCoordinate",
"RealtorDetailGroup",
"RealtorEstimate",
"RealtorFlags",
"RealtorMarketInfo",
"RealtorMarketsResponse",
"RealtorOffice",
"RealtorOpenHouse",
"RealtorPhone",
"RealtorPhoto",
"RealtorPriceEvent",
"RealtorProperty",
"RealtorPropertyDetail",
"RealtorSchool",
"RealtorSearchResponse",
"RealtorSuggestion",
"RealtorTaxRecord",
# Reddit core models
"RedditAward",
"RedditComment",
Expand Down Expand Up @@ -536,7 +619,6 @@ async def main():
"TikTokAd",
"TikTokAdVideo",
"TikTokAuthor",
# TikTok client
"TikTokClient",
"TikTokComment",
# TikTok response envelopes
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.1"
SDK_VERSION = "0.15.5"
USER_AGENT = f"scrapebadger-python/{SDK_VERSION}"


Expand Down
23 changes: 23 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.realtor.client import RealtorClient
from scrapebadger.reddit.client import RedditClient
from scrapebadger.tiktok.client import TikTokClient
from scrapebadger.twitter.client import TwitterClient
Expand Down Expand Up @@ -124,6 +125,7 @@ def __init__(
self._ebay: EbayClient | None = None
self._youtube: YoutubeClient | None = None
self._tiktok: TikTokClient | None = None
self._realtor: RealtorClient | None = None

@property
def config(self) -> ClientConfig:
Expand Down Expand Up @@ -304,6 +306,27 @@ def youtube(self) -> YoutubeClient:
self._youtube = YoutubeClient(self._base_client)
return self._youtube

@property
def realtor(self) -> RealtorClient:
"""Access Realtor Scraper API operations.

Returns:
RealtorClient providing access to all 4 Realtor endpoints
(search, property detail, autocomplete, markets) across
realtor.com (US) and realtor.ca (Canada).

Example:
```python
results = await client.realtor.search.search("Austin, TX")
detail = await client.realtor.properties.get_property("1234567890")
hits = await client.realtor.search.autocomplete("toronto", market="ca")
markets = await client.realtor.reference.list_markets()
```
"""
if self._realtor is None:
self._realtor = RealtorClient(self._base_client)
return self._realtor

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

This module provides a comprehensive async client for scraping real-estate
listings through the ScrapeBadger API, unifying realtor.com (US) and
realtor.ca (Canada) behind a single ``market`` parameter. 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 listings
results = await client.realtor.search.search("Austin, TX")
for prop in results.results:
print(prop.property_id, prop.list_price)

# Get property detail
detail = await client.realtor.properties.get_property("1234567890")
print(detail.beds, detail.baths, detail.sqft)
```
"""

from scrapebadger.realtor.client import RealtorClient
from scrapebadger.realtor.models import (
Address,
Agent,
AutocompleteResponse,
Coordinate,
DetailGroup,
Estimate,
Flags,
MarketInfo,
MarketsResponse,
Office,
OpenHouse,
Phone,
Photo,
PriceEvent,
Property,
PropertyDetail,
School,
SearchResponse,
Suggestion,
TaxRecord,
)

__all__ = [
"Address",
"Agent",
"AutocompleteResponse",
"Coordinate",
"DetailGroup",
"Estimate",
"Flags",
"MarketInfo",
"MarketsResponse",
"Office",
"OpenHouse",
"Phone",
"Photo",
"PriceEvent",
"Property",
"PropertyDetail",
"RealtorClient",
"School",
"SearchResponse",
"Suggestion",
"TaxRecord",
]
111 changes: 111 additions & 0 deletions src/scrapebadger/realtor/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Realtor API client combining all sub-clients.

This module provides the main RealtorClient class that serves as the
entry point for all Realtor API operations.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from scrapebadger.realtor.properties import PropertiesClient
from scrapebadger.realtor.reference import ReferenceClient
from scrapebadger.realtor.search import SearchClient

if TYPE_CHECKING:
from scrapebadger._internal.client import BaseClient


class RealtorClient:
"""Client for all Realtor API operations.

This class provides access to all Realtor scraping endpoints through
organized sub-clients for different resource types. It unifies realtor.com
(US) and realtor.ca (Canada) behind a single ``market`` parameter.

Attributes:
search: Client for property search and location autocomplete.
properties: Client for single-property detail.
reference: Client for reference data (markets).

Example:
```python
from scrapebadger import ScrapeBadger

async with ScrapeBadger(api_key="your-key") as client:
# Search for listings
results = await client.realtor.search.search("Austin, TX")
for prop in results.results:
print(prop.property_id, prop.list_price)

# Get property detail
detail = await client.realtor.properties.get_property("1234567890")
print(detail.beds, detail.baths, detail.sqft)

# Location autocomplete
hits = await client.realtor.search.autocomplete("toronto", market="ca")

# Get supported markets
markets = await client.realtor.reference.list_markets()
```

Note:
This client is not instantiated directly. Instead, access it through
the `realtor` property of the main `ScrapeBadger` client.
"""

def __init__(self, client: BaseClient) -> None:
"""Initialize Realtor client with all sub-clients.

Args:
client: The base HTTP client for making API requests.
"""
self._client = client

# Initialize sub-clients
self._search = SearchClient(client)
self._properties = PropertiesClient(client)
self._reference = ReferenceClient(client)

@property
def search(self) -> SearchClient:
"""Access property search and autocomplete endpoints.

Returns:
SearchClient for property search and location autocomplete.

Example:
```python
results = await client.realtor.search.search("Miami, FL")
hits = await client.realtor.search.autocomplete("miami")
```
"""
return self._search

@property
def properties(self) -> PropertiesClient:
"""Access the single-property detail endpoint.

Returns:
PropertiesClient for fetching full property detail.

Example:
```python
detail = await client.realtor.properties.get_property("1234567890")
```
"""
return self._properties

@property
def reference(self) -> ReferenceClient:
"""Access reference data endpoints.

Returns:
ReferenceClient for fetching supported markets.

Example:
```python
markets = await client.realtor.reference.list_markets()
```
"""
return self._reference
Loading
Loading