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

### Added

- **Zillow sub-client** (`client.zillow`) — real-estate listings, property detail, and agent profiles from zillow.com (US + Canadian inventory). Five endpoints: `search.search()`, `search.autocomplete()`, `properties.get_property()`, `agents.get_agent()`, `reference.list_markets()`, with fully-typed maximal-coverage Pydantic models (`ZillowSearchResponse`, `ZillowProperty` incl. nested `home_facts`/`price_history`/`tax_history`/`schools`/`zestimate_history`, `ZillowAgent`, etc.). (SCR-99)

## [0.15.6] - 2026-07-07

### 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.6"
version = "0.15.7"
description = "Official Python SDK for ScrapeBadger - Async web scraping APIs for Twitter and more"
readme = "README.md"
license = { text = "MIT" }
Expand Down
125 changes: 124 additions & 1 deletion src/scrapebadger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,99 @@ async def main():
from scrapebadger.youtube.models import (
Video as YoutubeVideo,
)
from scrapebadger.zillow.client import ZillowClient
from scrapebadger.zillow.models import (
Address as ZillowAddress,
)
from scrapebadger.zillow.models import (
Agent as ZillowAgent,
)
from scrapebadger.zillow.models import (
AgentAttribution as ZillowAgentAttribution,
)
from scrapebadger.zillow.models import (
AgentLicense as ZillowAgentLicense,
)
from scrapebadger.zillow.models import (
AgentResponse as ZillowAgentResponse,
)
from scrapebadger.zillow.models import (
AgentReview as ZillowAgentReview,
)
from scrapebadger.zillow.models import (
AutocompleteResponse as ZillowAutocompleteResponse,
)
from scrapebadger.zillow.models import (
AutocompleteResult as ZillowAutocompleteResult,
)
from scrapebadger.zillow.models import (
HomeFacts as ZillowHomeFacts,
)
from scrapebadger.zillow.models import (
LatLong as ZillowLatLong,
)
from scrapebadger.zillow.models import (
Listing as ZillowListing,
)
from scrapebadger.zillow.models import (
ListingSubType as ZillowListingSubType,
)
from scrapebadger.zillow.models import (
MapBounds as ZillowMapBounds,
)
from scrapebadger.zillow.models import (
MarketInfo as ZillowMarketInfo,
)
from scrapebadger.zillow.models import (
MarketsResponse as ZillowMarketsResponse,
)
from scrapebadger.zillow.models import (
MortgageRate as ZillowMortgageRate,
)
from scrapebadger.zillow.models import (
MortgageRates as ZillowMortgageRates,
)
from scrapebadger.zillow.models import (
NearbyRegion as ZillowNearbyRegion,
)
from scrapebadger.zillow.models import (
OpenHouse as ZillowOpenHouse,
)
from scrapebadger.zillow.models import (
Pagination as ZillowPagination,
)
from scrapebadger.zillow.models import (
PastSale as ZillowPastSale,
)
from scrapebadger.zillow.models import (
Photo as ZillowPhoto,
)
from scrapebadger.zillow.models import (
PriceHistoryEvent as ZillowPriceHistoryEvent,
)
from scrapebadger.zillow.models import (
Property as ZillowProperty,
)
from scrapebadger.zillow.models import (
PropertyResponse as ZillowPropertyResponse,
)
from scrapebadger.zillow.models import (
RegionSelection as ZillowRegionSelection,
)
from scrapebadger.zillow.models import (
School as ZillowSchool,
)
from scrapebadger.zillow.models import (
SearchResponse as ZillowSearchResponse,
)
from scrapebadger.zillow.models import (
TaxHistoryEvent as ZillowTaxHistoryEvent,
)
from scrapebadger.zillow.models import (
ZestimateHistoryPoint as ZillowZestimateHistoryPoint,
)

__version__ = "0.15.6"
__version__ = "0.15.7"

__all__ = [
# TikTok core models
Expand Down Expand Up @@ -814,6 +905,38 @@ async def main():
"YoutubeTrendingItem",
"YoutubeTrendingResponse",
"YoutubeVideo",
# Zillow
"ZillowAddress",
"ZillowAgent",
"ZillowAgentAttribution",
"ZillowAgentLicense",
"ZillowAgentResponse",
"ZillowAgentReview",
"ZillowAutocompleteResponse",
"ZillowAutocompleteResult",
"ZillowClient",
"ZillowHomeFacts",
"ZillowLatLong",
"ZillowListing",
"ZillowListingSubType",
"ZillowMapBounds",
"ZillowMarketInfo",
"ZillowMarketsResponse",
"ZillowMortgageRate",
"ZillowMortgageRates",
"ZillowNearbyRegion",
"ZillowOpenHouse",
"ZillowPagination",
"ZillowPastSale",
"ZillowPhoto",
"ZillowPriceHistoryEvent",
"ZillowProperty",
"ZillowPropertyResponse",
"ZillowRegionSelection",
"ZillowSchool",
"ZillowSearchResponse",
"ZillowTaxHistoryEvent",
"ZillowZestimateHistoryPoint",
# Version
"__version__",
]
24 changes: 24 additions & 0 deletions src/scrapebadger/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from scrapebadger.vinted.client import VintedClient
from scrapebadger.web.client import WebClient
from scrapebadger.youtube.client import YoutubeClient
from scrapebadger.zillow.client import ZillowClient

if TYPE_CHECKING:
from types import TracebackType
Expand Down Expand Up @@ -127,6 +128,7 @@ def __init__(
self._youtube: YoutubeClient | None = None
self._tiktok: TikTokClient | None = None
self._realtor: RealtorClient | None = None
self._zillow: ZillowClient | None = None
self._leboncoin: LeboncoinClient | None = None

@property
Expand Down Expand Up @@ -329,6 +331,28 @@ def realtor(self) -> RealtorClient:
self._realtor = RealtorClient(self._base_client)
return self._realtor

@property
def zillow(self) -> ZillowClient:
"""Access Zillow Scraper API operations.

Returns:
ZillowClient providing access to all 5 Zillow endpoints
(search, property detail, agent profile, autocomplete, markets)
on zillow.com (US + Canadian inventory).

Example:
```python
results = await client.zillow.search.search("Austin, TX")
prop = await client.zillow.properties.get_property("2078133351")
agent = await client.zillow.agents.get_agent(username="jane-doe")
hits = await client.zillow.search.autocomplete("austin")
markets = await client.zillow.reference.list_markets()
```
"""
if self._zillow is None:
self._zillow = ZillowClient(self._base_client)
return self._zillow

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

This module provides a comprehensive async client for scraping real-estate
listings, property detail, and agent profiles from zillow.com through the
ScrapeBadger API. Zillow is a single-domain target (US + Canadian inventory,
USD, en-US). 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.zillow.search.search("Austin, TX")
for listing in results.results:
print(listing.zpid, listing.price)

# Get property detail
prop = await client.zillow.properties.get_property("2078133351")
print(prop.bedrooms, prop.bathrooms, prop.living_area)

# Get an agent profile + their listings
agent = await client.zillow.agents.get_agent(username="jane-doe")
```
"""

from scrapebadger.zillow.client import ZillowClient
from scrapebadger.zillow.models import (
Address,
Agent,
AgentAttribution,
AgentLicense,
AgentResponse,
AgentReview,
AutocompleteResponse,
AutocompleteResult,
HomeFacts,
LatLong,
Listing,
ListingSubType,
MapBounds,
MarketInfo,
MarketsResponse,
MortgageRate,
MortgageRates,
NearbyRegion,
OpenHouse,
Pagination,
PastSale,
Photo,
PriceHistoryEvent,
Property,
PropertyResponse,
RegionSelection,
School,
SearchResponse,
TaxHistoryEvent,
ZestimateHistoryPoint,
)

__all__ = [
"Address",
"Agent",
"AgentAttribution",
"AgentLicense",
"AgentResponse",
"AgentReview",
"AutocompleteResponse",
"AutocompleteResult",
"HomeFacts",
"LatLong",
"Listing",
"ListingSubType",
"MapBounds",
"MarketInfo",
"MarketsResponse",
"MortgageRate",
"MortgageRates",
"NearbyRegion",
"OpenHouse",
"Pagination",
"PastSale",
"Photo",
"PriceHistoryEvent",
"Property",
"PropertyResponse",
"RegionSelection",
"School",
"SearchResponse",
"TaxHistoryEvent",
"ZestimateHistoryPoint",
"ZillowClient",
]
71 changes: 71 additions & 0 deletions src/scrapebadger/zillow/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Zillow Agent API client.

Provides the method for fetching a real-estate professional's profile and
their active listings.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from scrapebadger.zillow.models import Agent, AgentResponse

if TYPE_CHECKING:
from scrapebadger._internal.client import BaseClient


class AgentClient:
"""Client for the Zillow agent-profile endpoint.

Example:
```python
async with ScrapeBadger(api_key="key") as client:
agent = await client.zillow.agents.get_agent(username="jane-doe")
print(agent.name, agent.rating, agent.review_count)
for sale in agent.past_sales:
print(sale.street_address, sale.price)
```
"""

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

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

async def get_agent(
self,
username: str | None = None,
*,
url: str | None = None,
) -> Agent:
"""Get a Zillow professional's profile and their active listings.

Provide either a ``username`` (the profile screen name) or a full
profile ``url``.

Args:
username: Zillow profile username (screen name).
url: Full Zillow /profile/... URL.

Returns:
The agent profile including reviews, past sales, licenses, service
areas, contact info, and their active listings.

Raises:
NotFoundError: If the agent doesn't exist.
AuthenticationError: If the API key is invalid.
ValidationError: If neither ``username`` nor ``url`` is provided.

Example:
```python
agent = await client.zillow.agents.get_agent(username="jane-doe")
for review in agent.reviews:
print(review.rating, review.comment)
```
"""
params: dict[str, Any] = {"username": username, "url": url}
response = await self._client.get("/v1/zillow/agent", params=params)
return AgentResponse.model_validate(response).agent
Loading
Loading