getanyapi 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- getanyapi/__init__.py +76 -0
- getanyapi/_account.py +132 -0
- getanyapi/_async_client.py +215 -0
- getanyapi/_client.py +274 -0
- getanyapi/_errors.py +115 -0
- getanyapi/_pagination.py +295 -0
- getanyapi/_transport.py +239 -0
- getanyapi/platforms/__init__.py +89 -0
- getanyapi/platforms/ahrefs.py +384 -0
- getanyapi/platforms/airbnb.py +120 -0
- getanyapi/platforms/alibaba.py +95 -0
- getanyapi/platforms/amazon.py +442 -0
- getanyapi/platforms/appstore.py +95 -0
- getanyapi/platforms/bluesky.py +215 -0
- getanyapi/platforms/booking.py +128 -0
- getanyapi/platforms/coinmarketcap.py +113 -0
- getanyapi/platforms/congress.py +106 -0
- getanyapi/platforms/dexscreener.py +104 -0
- getanyapi/platforms/ebay.py +215 -0
- getanyapi/platforms/email.py +166 -0
- getanyapi/platforms/facebook.py +2324 -0
- getanyapi/platforms/fiverr.py +122 -0
- getanyapi/platforms/github.py +954 -0
- getanyapi/platforms/glassdoor.py +93 -0
- getanyapi/platforms/google.py +232 -0
- getanyapi/platforms/google_ads.py +380 -0
- getanyapi/platforms/google_finance.py +170 -0
- getanyapi/platforms/google_shopping.py +103 -0
- getanyapi/platforms/hackernews.py +276 -0
- getanyapi/platforms/indeed.py +114 -0
- getanyapi/platforms/instagram.py +1868 -0
- getanyapi/platforms/linkedin.py +1064 -0
- getanyapi/platforms/maps.py +412 -0
- getanyapi/platforms/pandaexpress.py +262 -0
- getanyapi/platforms/person.py +96 -0
- getanyapi/platforms/pinterest.py +96 -0
- getanyapi/platforms/playstore.py +99 -0
- getanyapi/platforms/polymarket.py +109 -0
- getanyapi/platforms/realtor.py +104 -0
- getanyapi/platforms/reddit.py +582 -0
- getanyapi/platforms/redfin.py +95 -0
- getanyapi/platforms/rednote.py +807 -0
- getanyapi/platforms/sec.py +118 -0
- getanyapi/platforms/semrush.py +358 -0
- getanyapi/platforms/snapchat.py +146 -0
- getanyapi/platforms/social.py +105 -0
- getanyapi/platforms/spotify.py +588 -0
- getanyapi/platforms/substack.py +142 -0
- getanyapi/platforms/threads.py +358 -0
- getanyapi/platforms/tiktok.py +1827 -0
- getanyapi/platforms/tiktok_shop.py +536 -0
- getanyapi/platforms/tripadvisor.py +180 -0
- getanyapi/platforms/trustpilot.py +114 -0
- getanyapi/platforms/truthsocial.py +226 -0
- getanyapi/platforms/twitter.py +798 -0
- getanyapi/platforms/upwork.py +119 -0
- getanyapi/platforms/walmart.py +93 -0
- getanyapi/platforms/web.py +264 -0
- getanyapi/platforms/whatsapp.py +91 -0
- getanyapi/platforms/yahoo_finance.py +95 -0
- getanyapi/platforms/yelp.py +141 -0
- getanyapi/platforms/youtube.py +1452 -0
- getanyapi/platforms/zillow.py +218 -0
- getanyapi/py.typed +0 -0
- getanyapi/types.py +170 -0
- getanyapi-0.1.0.dist-info/METADATA +155 -0
- getanyapi-0.1.0.dist-info/RECORD +68 -0
- getanyapi-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Generated - do not edit. Regenerate with: pnpm generate
|
|
2
|
+
"""Generated namespace module for the zillow platform."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from typing import Literal, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
from typing_extensions import NotRequired, Required, TypedDict, Unpack
|
|
10
|
+
|
|
11
|
+
from ..types import RequestOptions, RunResult
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .._async_client import AsyncAnyAPI
|
|
15
|
+
from .._client import AnyAPI
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ZillowPropertyInput(TypedDict, total=False):
|
|
19
|
+
"""Input for Zillow Property."""
|
|
20
|
+
|
|
21
|
+
url: Required[str]
|
|
22
|
+
"""Zillow property details URL (e.g. https://www.zillow.com/homedetails/123-Main-St-Anytown-CA-90210/12345678_zpid/)."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ZillowSearchInput(TypedDict, total=False):
|
|
26
|
+
"""Input for Zillow Search."""
|
|
27
|
+
|
|
28
|
+
limit: NotRequired[int]
|
|
29
|
+
"""Maximum number of results to return (1-25, default 25). You are billed per result returned, so a lower limit costs less. Range: 1 to 25."""
|
|
30
|
+
location: Required[str]
|
|
31
|
+
"""Location to search: city, ZIP code, neighborhood, or address (e.g. 'Austin, TX' or '78701')."""
|
|
32
|
+
operation: NotRequired[Literal["buy", "rent", "sold"]]
|
|
33
|
+
"""Listing type: buy (for sale), rent, or sold. Default: buy."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ZillowPropertyData(BaseModel):
|
|
37
|
+
items: list[ZillowPropertyItem] = Field(
|
|
38
|
+
description="Matching property records: full listing details including price, address, facts and features, photos, and price/tax history."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ZillowPropertyItem(BaseModel):
|
|
43
|
+
model_config = ConfigDict(extra="allow")
|
|
44
|
+
|
|
45
|
+
price: float
|
|
46
|
+
title: str | None = Field(
|
|
47
|
+
default=None, description="Present whenever the upstream returns this record."
|
|
48
|
+
)
|
|
49
|
+
url: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ZillowSearchData(BaseModel):
|
|
53
|
+
items: list[ZillowSearchItem] = Field(
|
|
54
|
+
description="Property listing records matching the search: address, price, beds, baths, living area, property type, status, Zestimate, and coordinates."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ZillowSearchItem(BaseModel):
|
|
59
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
60
|
+
|
|
61
|
+
baths: float | None = Field(default=None, description="Number of bathrooms.")
|
|
62
|
+
beds: float | None = Field(default=None, description="Number of bedrooms.")
|
|
63
|
+
city: str | None = None
|
|
64
|
+
currency: str | None = Field(
|
|
65
|
+
default=None, description="ISO currency code of the price (e.g. usd)."
|
|
66
|
+
)
|
|
67
|
+
days_on_zillow: int | None = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
alias="daysOnZillow",
|
|
70
|
+
description="Days the listing has been on Zillow.",
|
|
71
|
+
)
|
|
72
|
+
image: str | None = Field(
|
|
73
|
+
default=None,
|
|
74
|
+
description="URL of the primary listing photo. Present whenever the upstream returns this record.",
|
|
75
|
+
)
|
|
76
|
+
latitude: float | None = None
|
|
77
|
+
living_area: float | None = Field(
|
|
78
|
+
default=None,
|
|
79
|
+
alias="livingArea",
|
|
80
|
+
description="Interior living area in square feet.",
|
|
81
|
+
)
|
|
82
|
+
longitude: float | None = None
|
|
83
|
+
lot_size: float | None = Field(
|
|
84
|
+
default=None, alias="lotSize", description="Lot size in square feet."
|
|
85
|
+
)
|
|
86
|
+
price: float | None = Field(
|
|
87
|
+
default=None, description="List price in the listing currency."
|
|
88
|
+
)
|
|
89
|
+
property_type: str | None = Field(
|
|
90
|
+
default=None,
|
|
91
|
+
alias="propertyType",
|
|
92
|
+
description="Property type (e.g. singleFamily, condo, townhouse).",
|
|
93
|
+
)
|
|
94
|
+
rent_zestimate: float | None = Field(
|
|
95
|
+
default=None,
|
|
96
|
+
alias="rentZestimate",
|
|
97
|
+
description="Zillow estimated monthly rent.",
|
|
98
|
+
)
|
|
99
|
+
state: str | None = Field(default=None, description="Two-letter state code.")
|
|
100
|
+
status: str | None = Field(
|
|
101
|
+
default=None, description="Listing status (e.g. forSale, forRent, sold)."
|
|
102
|
+
)
|
|
103
|
+
street_address: str | None = Field(
|
|
104
|
+
default=None,
|
|
105
|
+
alias="streetAddress",
|
|
106
|
+
description="Street address of the property. Present whenever the upstream returns this record.",
|
|
107
|
+
)
|
|
108
|
+
url: str = Field(description="Absolute Zillow listing URL.")
|
|
109
|
+
year_built: int | None = Field(default=None, alias="yearBuilt")
|
|
110
|
+
zestimate: float | None = Field(
|
|
111
|
+
default=None, description="Zillow estimated market value."
|
|
112
|
+
)
|
|
113
|
+
zipcode: str | None = None
|
|
114
|
+
zpid: str = Field(description="Zillow property id (zpid).")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ZillowNamespace:
|
|
118
|
+
"""Typed methods for this platform. Attached lazily to the client."""
|
|
119
|
+
|
|
120
|
+
def __init__(self, client: "AnyAPI") -> None:
|
|
121
|
+
self._client = client
|
|
122
|
+
|
|
123
|
+
def property(
|
|
124
|
+
self,
|
|
125
|
+
*,
|
|
126
|
+
options: RequestOptions | None = None,
|
|
127
|
+
**input: Unpack[ZillowPropertyInput],
|
|
128
|
+
) -> RunResult[ZillowPropertyData]:
|
|
129
|
+
"""Zillow Property
|
|
130
|
+
|
|
131
|
+
Fetch full details for a single Zillow property listing by URL - price,
|
|
132
|
+
facts and features, photos, and price/tax history - with transparent
|
|
133
|
+
per-request USD pricing.
|
|
134
|
+
|
|
135
|
+
Price: $0.0024 per result.
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
res = client.zillow.property(url="https://www.zillow.com/homedetails/4510-Secure-Ln-Austin-TX-78725/83126034_zpid/")
|
|
139
|
+
"""
|
|
140
|
+
raw = self._client._run_raw( # pyright: ignore[reportPrivateUsage]
|
|
141
|
+
"zillow.property", dict(input), options
|
|
142
|
+
)
|
|
143
|
+
return RunResult[ZillowPropertyData].model_validate(raw)
|
|
144
|
+
|
|
145
|
+
def search(
|
|
146
|
+
self,
|
|
147
|
+
*,
|
|
148
|
+
options: RequestOptions | None = None,
|
|
149
|
+
**input: Unpack[ZillowSearchInput],
|
|
150
|
+
) -> RunResult[ZillowSearchData]:
|
|
151
|
+
"""Zillow Search
|
|
152
|
+
|
|
153
|
+
Search Zillow for-sale, rental, or sold listings by location (city, ZIP, or
|
|
154
|
+
address) and get matching properties (price, address, beds, baths, living
|
|
155
|
+
area, status, Zestimate) as normalized JSON with per-request USD pricing
|
|
156
|
+
that scales with the number of results.
|
|
157
|
+
|
|
158
|
+
Price: $0.0005 per request plus $0.003 per result.
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
res = client.zillow.search(limit=3, location="Austin, TX", operation="buy")
|
|
162
|
+
"""
|
|
163
|
+
raw = self._client._run_raw( # pyright: ignore[reportPrivateUsage]
|
|
164
|
+
"zillow.search", dict(input), options
|
|
165
|
+
)
|
|
166
|
+
return RunResult[ZillowSearchData].model_validate(raw)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class AsyncZillowNamespace:
|
|
170
|
+
"""Typed methods for this platform. Attached lazily to the client."""
|
|
171
|
+
|
|
172
|
+
def __init__(self, client: "AsyncAnyAPI") -> None:
|
|
173
|
+
self._client = client
|
|
174
|
+
|
|
175
|
+
async def property(
|
|
176
|
+
self,
|
|
177
|
+
*,
|
|
178
|
+
options: RequestOptions | None = None,
|
|
179
|
+
**input: Unpack[ZillowPropertyInput],
|
|
180
|
+
) -> RunResult[ZillowPropertyData]:
|
|
181
|
+
"""Zillow Property
|
|
182
|
+
|
|
183
|
+
Fetch full details for a single Zillow property listing by URL - price,
|
|
184
|
+
facts and features, photos, and price/tax history - with transparent
|
|
185
|
+
per-request USD pricing.
|
|
186
|
+
|
|
187
|
+
Price: $0.0024 per result.
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
res = client.zillow.property(url="https://www.zillow.com/homedetails/4510-Secure-Ln-Austin-TX-78725/83126034_zpid/")
|
|
191
|
+
"""
|
|
192
|
+
raw = await self._client._arun_raw( # pyright: ignore[reportPrivateUsage]
|
|
193
|
+
"zillow.property", dict(input), options
|
|
194
|
+
)
|
|
195
|
+
return RunResult[ZillowPropertyData].model_validate(raw)
|
|
196
|
+
|
|
197
|
+
async def search(
|
|
198
|
+
self,
|
|
199
|
+
*,
|
|
200
|
+
options: RequestOptions | None = None,
|
|
201
|
+
**input: Unpack[ZillowSearchInput],
|
|
202
|
+
) -> RunResult[ZillowSearchData]:
|
|
203
|
+
"""Zillow Search
|
|
204
|
+
|
|
205
|
+
Search Zillow for-sale, rental, or sold listings by location (city, ZIP, or
|
|
206
|
+
address) and get matching properties (price, address, beds, baths, living
|
|
207
|
+
area, status, Zestimate) as normalized JSON with per-request USD pricing
|
|
208
|
+
that scales with the number of results.
|
|
209
|
+
|
|
210
|
+
Price: $0.0005 per request plus $0.003 per result.
|
|
211
|
+
|
|
212
|
+
Example:
|
|
213
|
+
res = client.zillow.search(limit=3, location="Austin, TX", operation="buy")
|
|
214
|
+
"""
|
|
215
|
+
raw = await self._client._arun_raw( # pyright: ignore[reportPrivateUsage]
|
|
216
|
+
"zillow.search", dict(input), options
|
|
217
|
+
)
|
|
218
|
+
return RunResult[ZillowSearchData].model_validate(raw)
|
getanyapi/py.typed
ADDED
|
File without changes
|
getanyapi/types.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Public data models and typed dicts for the getanyapi SDK (SPEC 3.3, 3.7).
|
|
2
|
+
|
|
3
|
+
Output models use pydantic v2. The run envelope is discriminated on ``found``:
|
|
4
|
+
``OutputFound[T]`` carries the data payload, ``OutputNotFound`` carries None.
|
|
5
|
+
Wire keys are camelCase; models use ``populate_by_name`` plus per-field aliases
|
|
6
|
+
so callers read snake_case attributes while the transport round-trips camelCase.
|
|
7
|
+
Data models allow extra keys (``extra="allow"``) so open provider records keep
|
|
8
|
+
unknown fields, exposed via ``.model_extra``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any, Generic, Literal, TypeVar
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
from typing_extensions import TypedDict
|
|
17
|
+
|
|
18
|
+
from ._errors import ResultNotFoundError
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"OutputFound",
|
|
22
|
+
"OutputNotFound",
|
|
23
|
+
"Output",
|
|
24
|
+
"RunResult",
|
|
25
|
+
"BareRunResult",
|
|
26
|
+
"unwrap",
|
|
27
|
+
"Balance",
|
|
28
|
+
"AccountProfile",
|
|
29
|
+
"CatalogEntry",
|
|
30
|
+
"RequestOptions",
|
|
31
|
+
"AgentSignupResult",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
T = TypeVar("T")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class OutputFound(BaseModel, Generic[T]):
|
|
38
|
+
"""The ``found: true`` branch: the upstream returned a matching entity."""
|
|
39
|
+
|
|
40
|
+
found: Literal[True]
|
|
41
|
+
data: T
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class OutputNotFound(BaseModel):
|
|
45
|
+
"""The ``found: false`` branch: no matching entity, ``data`` is None."""
|
|
46
|
+
|
|
47
|
+
found: Literal[False]
|
|
48
|
+
data: None = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Output[T] is the discriminated union on `found`.
|
|
52
|
+
Output = OutputFound[T] | OutputNotFound
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class RunResult(BaseModel, Generic[T]):
|
|
56
|
+
"""The normalized run envelope returned by ``POST /v1/run/{slug}``.
|
|
57
|
+
|
|
58
|
+
Extra top-level keys round-trip via ``.model_extra`` (the envelope root is
|
|
59
|
+
open). ``provider`` is always the literal ``"AnyAPI"``; upstream backends
|
|
60
|
+
are never named.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
64
|
+
|
|
65
|
+
output: OutputFound[T] | OutputNotFound = Field(
|
|
66
|
+
discriminator="found"
|
|
67
|
+
)
|
|
68
|
+
provider: Literal["AnyAPI"]
|
|
69
|
+
cost_usd: float = Field(alias="costUsd")
|
|
70
|
+
items: int | None = None
|
|
71
|
+
hint: str | None = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class BareRunResult(BaseModel, Generic[T]):
|
|
75
|
+
"""The run envelope for a BARE SKU (SPEC 1.2 erratum).
|
|
76
|
+
|
|
77
|
+
A handful of SKUs (e.g. reddit.search) return their data object directly as
|
|
78
|
+
``output`` with no ``{found, data}`` wrapper: ``output`` IS the data payload.
|
|
79
|
+
There is no not-found branch to discriminate, so ``unwrap`` returns
|
|
80
|
+
``output`` directly and never raises.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
84
|
+
|
|
85
|
+
output: T
|
|
86
|
+
provider: Literal["AnyAPI"]
|
|
87
|
+
cost_usd: float = Field(alias="costUsd")
|
|
88
|
+
items: int | None = None
|
|
89
|
+
hint: str | None = None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def unwrap(result: RunResult[T] | BareRunResult[T]) -> T:
|
|
93
|
+
"""Return the data payload when found, else raise :class:`ResultNotFoundError`.
|
|
94
|
+
|
|
95
|
+
For a found-data ``RunResult`` this narrows ``Output[T]`` to ``T`` and raises
|
|
96
|
+
when ``found`` is false. For a ``BareRunResult`` the output IS the data, so it
|
|
97
|
+
is returned directly and this never raises.
|
|
98
|
+
|
|
99
|
+
Catching ``NotFoundError`` catches both an HTTP 404 and an empty found-data
|
|
100
|
+
result; catch ``ResultNotFoundError`` to handle only empty results.
|
|
101
|
+
"""
|
|
102
|
+
if isinstance(result, BareRunResult):
|
|
103
|
+
return result.output
|
|
104
|
+
output = result.output
|
|
105
|
+
if isinstance(output, OutputFound):
|
|
106
|
+
return output.data
|
|
107
|
+
raise ResultNotFoundError("no matching result was found", status=404)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Balance(BaseModel):
|
|
111
|
+
"""Wallet balance in USD (the server returns ``{usd}`` already in USD)."""
|
|
112
|
+
|
|
113
|
+
usd: float
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class AccountProfile(BaseModel):
|
|
117
|
+
"""Account profile from ``GET /v1/me`` (internal fields dropped)."""
|
|
118
|
+
|
|
119
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
120
|
+
|
|
121
|
+
id: str
|
|
122
|
+
email: str | None = None
|
|
123
|
+
status: str
|
|
124
|
+
created_at: str = Field(alias="createdAt")
|
|
125
|
+
onboarding_complete: bool = Field(alias="onboardingComplete")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class CatalogEntry(BaseModel):
|
|
129
|
+
"""One catalog SKU. ``price_usd`` is the cheapest per-request price in USD."""
|
|
130
|
+
|
|
131
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
132
|
+
|
|
133
|
+
slug: str
|
|
134
|
+
platform: str
|
|
135
|
+
action: str
|
|
136
|
+
name: str
|
|
137
|
+
category: str
|
|
138
|
+
description: str
|
|
139
|
+
price_usd: float = Field(alias="priceUsd")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class RequestOptions(TypedDict, total=False):
|
|
143
|
+
"""Per-call response shaping and transport overrides (SPEC 3.7).
|
|
144
|
+
|
|
145
|
+
``fields``, ``max_items``, and ``summary`` shape the response and do NOT
|
|
146
|
+
change cost. ``timeout`` overrides the client per-request timeout (seconds).
|
|
147
|
+
``max_retries`` overrides the client retry cap for this call.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
fields: list[str]
|
|
151
|
+
max_items: int
|
|
152
|
+
summary: bool
|
|
153
|
+
timeout: float
|
|
154
|
+
max_retries: int
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class AgentSignupResult(BaseModel):
|
|
158
|
+
"""Result of :func:`getanyapi.agent_signup` (SPEC 3.7)."""
|
|
159
|
+
|
|
160
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
161
|
+
|
|
162
|
+
secret: str
|
|
163
|
+
cap_usd: float = Field(alias="capUsd")
|
|
164
|
+
claim_token: str = Field(alias="claimToken")
|
|
165
|
+
claim_url: str = Field(alias="claimUrl")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# Convenience aliases used by the transport for untyped generic runs.
|
|
169
|
+
AnyRunResult = RunResult[Any]
|
|
170
|
+
AnyBareRunResult = BareRunResult[Any]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: getanyapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official typed Python SDK for AnyAPI: any API, one wallet, USD, no subscriptions.
|
|
5
|
+
Project-URL: Homepage, https://getanyapi.com
|
|
6
|
+
Project-URL: Documentation, https://getanyapi.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/getanyapi-com/sdks
|
|
8
|
+
Project-URL: Issues, https://github.com/getanyapi-com/sdks/issues
|
|
9
|
+
Author-email: AnyAPI <support@getanyapi.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: anyapi,api,getanyapi,scraping,sdk
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx>=0.27
|
|
20
|
+
Requires-Dist: pydantic>=2.5
|
|
21
|
+
Requires-Dist: typing-extensions>=4.7
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
24
|
+
Requires-Dist: pyright>=1.1.380; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# getanyapi
|
|
31
|
+
|
|
32
|
+
Official typed Python SDK for [AnyAPI](https://getanyapi.com): any API, one wallet, USD, no
|
|
33
|
+
subscriptions. Reach hundreds of scraping and data APIs through one interface and one key; pay
|
|
34
|
+
per request in real US dollars. httpx + pydantic v2, Python 3.10+, sync and async clients.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install getanyapi
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quickstart
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from getanyapi import AnyAPI
|
|
44
|
+
|
|
45
|
+
client = AnyAPI() # reads ANYAPI_API_KEY from the environment
|
|
46
|
+
res = client.reddit.search(query="mechanical keyboard")
|
|
47
|
+
for post in res.output.posts:
|
|
48
|
+
print(post.title, post.score)
|
|
49
|
+
print("charged", res.cost_usd, "USD")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Async:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from getanyapi import AsyncAnyAPI
|
|
56
|
+
|
|
57
|
+
async with AsyncAnyAPI() as client:
|
|
58
|
+
res = await client.google.search(query="best coffee maker")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Inputs vs outputs (naming asymmetry)
|
|
62
|
+
|
|
63
|
+
Input keyword arguments mirror the wire API verbatim (camelCase where the API uses it), because
|
|
64
|
+
they are sent as-is. Output models are Pythonic: attributes are snake_case with a wire alias
|
|
65
|
+
(`item.reviews_count` reads the wire `reviewsCount`), and `model_dump(by_alias=True)` reproduces
|
|
66
|
+
the wire shape. Open provider records round-trip unknown fields via `.model_extra`.
|
|
67
|
+
|
|
68
|
+
## Not found vs error
|
|
69
|
+
|
|
70
|
+
A successful call always returns. For most SKUs the payload is wrapped in a `found` flag:
|
|
71
|
+
`res.output.found` is `False` when the upstream had no matching entity (not an error). Use
|
|
72
|
+
`unwrap` to get the data or raise `ResultNotFoundError` when empty:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from getanyapi import unwrap, ResultNotFoundError
|
|
76
|
+
|
|
77
|
+
res = client.amazon.reviews(product="B07FZ8S74R")
|
|
78
|
+
try:
|
|
79
|
+
data = unwrap(res) # the typed data payload, or raises
|
|
80
|
+
except ResultNotFoundError:
|
|
81
|
+
... # empty result (found: False), not an HTTP failure
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`ResultNotFoundError` subclasses `NotFoundError`, so `except NotFoundError` catches both an
|
|
85
|
+
HTTP 404 and an empty result; catch `ResultNotFoundError` to handle only empty results. A few
|
|
86
|
+
SKUs (e.g. `reddit.search`) return their data object directly as `output` with no `found`
|
|
87
|
+
wrapper; `unwrap` returns it as-is and never raises for those.
|
|
88
|
+
|
|
89
|
+
## Pagination
|
|
90
|
+
|
|
91
|
+
Paginated SKUs expose an `iter_*` method that yields validated item models across pages and
|
|
92
|
+
follows the cursor for you. Call `.pages()` on it to walk whole results (each has its own
|
|
93
|
+
`cost_usd`).
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
for post in client.reddit.iter_search(query="coffee", options={"max_items": 100}):
|
|
97
|
+
print(post.title) # a validated model, not a dict
|
|
98
|
+
|
|
99
|
+
for page in client.reddit.iter_search(query="coffee").pages():
|
|
100
|
+
print(page.cost_usd)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Request options (context-cost savers)
|
|
104
|
+
|
|
105
|
+
Pass `options=` to shape the response. These trim what comes back but do NOT change the price:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
res = client.google.search(
|
|
109
|
+
query="coffee",
|
|
110
|
+
options={"fields": ["title", "link"], "max_items": 5, "summary": True},
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`options` also carries per-call `timeout` and `max_retries` overrides.
|
|
115
|
+
|
|
116
|
+
## Errors and retries
|
|
117
|
+
|
|
118
|
+
| Class | HTTP | Meaning |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `BadRequestError` | 400 | Input failed validation |
|
|
121
|
+
| `AuthenticationError` | 401 | Missing or invalid API key |
|
|
122
|
+
| `InsufficientBalanceError` | 402 | Wallet balance or per-key cap exceeded |
|
|
123
|
+
| `NotFoundError` | 404 | Slug or resource does not exist |
|
|
124
|
+
| `ResultNotFoundError` | - | `unwrap` on an empty found-data result |
|
|
125
|
+
| `RateLimitedError` | 429 | Too many requests (retried automatically) |
|
|
126
|
+
| `UpstreamError` | 502 | An upstream backend failed |
|
|
127
|
+
| `ConnectionError` | 0 | Network or transport failure (retried) |
|
|
128
|
+
| `TimeoutError` | 0 | Request exceeded its timeout (not retried) |
|
|
129
|
+
|
|
130
|
+
All extend `AnyAPIError` (with `.status` and `.request_id`). Retries cover only 429 and network
|
|
131
|
+
failures, with jittered exponential backoff honoring `Retry-After`. Default `max_retries` is 2
|
|
132
|
+
(up to 3 attempts); set it on the client (`AnyAPI(max_retries=...)`) or per request via
|
|
133
|
+
`options`. Timeouts are never retried.
|
|
134
|
+
|
|
135
|
+
## Agent signup
|
|
136
|
+
|
|
137
|
+
Bootstrap a key with no account (for autonomous agents):
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from getanyapi import agent_signup, AnyAPI
|
|
141
|
+
|
|
142
|
+
result = agent_signup(label="my-agent")
|
|
143
|
+
client = AnyAPI(api_key=result.secret)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The key ships with a small starter credit and a per-key spend cap; a human funds it by claiming
|
|
147
|
+
it at `result.claim_url`.
|
|
148
|
+
|
|
149
|
+
## Docs
|
|
150
|
+
|
|
151
|
+
Full API reference and catalog: [getanyapi.com/docs](https://getanyapi.com/docs).
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
getanyapi/__init__.py,sha256=gjAWPRQwwSUPyjyMIGtUkR7eeNugDvgWvxtcpjuVj64,1777
|
|
2
|
+
getanyapi/_account.py,sha256=WAlXPpW2s8W-BJtHbWB_U8AFo8GwtDM5SYpKh0lRPag,3906
|
|
3
|
+
getanyapi/_async_client.py,sha256=lpyfgeMxplimgMOyUbnaEgcOT2apJQ1lHzaMpjnphHA,7137
|
|
4
|
+
getanyapi/_client.py,sha256=_d6qhtuSO12JZcAOVfopuE1S_6e28JoRX8N-ZWAuM1E,9684
|
|
5
|
+
getanyapi/_errors.py,sha256=S3PV9WwxSIiMahXU_-fHPXc1TfZQDvLGu5aH3QFaH2Y,3177
|
|
6
|
+
getanyapi/_pagination.py,sha256=E84LJAeM9TDzVrKk8zCX2AMK1r12yV8xdMiCEIBZMBM,10088
|
|
7
|
+
getanyapi/_transport.py,sha256=vVFmXdP2SdABNjUC2Tc0X5zyq7buy0nWlDJjnKUGH40,7543
|
|
8
|
+
getanyapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
getanyapi/types.py,sha256=TeeNG0zrlgM4tyfc_K950kK_d28m1WHcwh1meRoQWUE,5039
|
|
10
|
+
getanyapi/platforms/__init__.py,sha256=8fKaI-qevcR4BBSsZo6Kjfox3C3Gf2ybDeO2dn_8spA,4729
|
|
11
|
+
getanyapi/platforms/ahrefs.py,sha256=LuF7b8OLzTdryvxyoCK0fvRHt55A0IwE25o3u19M3rs,13755
|
|
12
|
+
getanyapi/platforms/airbnb.py,sha256=EPqY3sNkRT6jPsNl0TUKY5FQl5FUsSOOdBfziEh95os,4368
|
|
13
|
+
getanyapi/platforms/alibaba.py,sha256=Z9_q0Ciz40Qs6BjAvVttL1lMkIANn6Lb3rp4zpQfANA,2987
|
|
14
|
+
getanyapi/platforms/amazon.py,sha256=N2aoRpeaSsn_wP3kRgjpK6UMWcCWNL6s_GboeV8JLms,15211
|
|
15
|
+
getanyapi/platforms/appstore.py,sha256=RiD8D3KXLfnAFkK6XUySVWkDkXG67EvAUftvDWfcIxw,3175
|
|
16
|
+
getanyapi/platforms/bluesky.py,sha256=Y4AdYd-yp0EGhZoNFkrH6pBUzXIWRhZRH5P8Jzq5yLY,6571
|
|
17
|
+
getanyapi/platforms/booking.py,sha256=ipUH1LoBDx-kvnnL72f_WBZJrVLjHD-pk5x-ftfIs4o,4688
|
|
18
|
+
getanyapi/platforms/coinmarketcap.py,sha256=_JAIdTDN4dwYHEmsLp_PHlPpbzwp4Z8nXVXPCL0AFTs,4028
|
|
19
|
+
getanyapi/platforms/congress.py,sha256=Edlp1WvAxdLK-1T6x-m-mApnSFS8BjCKP9-9KmEGFzw,3758
|
|
20
|
+
getanyapi/platforms/dexscreener.py,sha256=Wzs8cpNyTe816H4ZVkWqRngTtiMFLchFAXomyEsg1OU,3660
|
|
21
|
+
getanyapi/platforms/ebay.py,sha256=XuqW7ZsWOUfnaqk5ZRBSVHC8lkpCvg-Utwdu6UPEhWA,7710
|
|
22
|
+
getanyapi/platforms/email.py,sha256=CDXUBEkFhcGX_HEi4knMvCN0_0wYT-NeOvIUjDvZ5ds,5722
|
|
23
|
+
getanyapi/platforms/facebook.py,sha256=7ZyYsWdawg3SW30jcPctiuxq620BJzsn--I9vOkjwyw,80785
|
|
24
|
+
getanyapi/platforms/fiverr.py,sha256=IvkXyxFEGHOkMTyTbouYWDtEgwDkmcrQXkmBHTYo28A,4430
|
|
25
|
+
getanyapi/platforms/github.py,sha256=jX-XRSaXJSm3DUL1UbbjQpxfy7LgDR92oe1xmGZsrqA,31886
|
|
26
|
+
getanyapi/platforms/glassdoor.py,sha256=jgSDQezJmi7TN7ru6Zoo2SL79lxr157CZmsxAqkcfXY,3094
|
|
27
|
+
getanyapi/platforms/google.py,sha256=-Xbt8yYA7lqpId3imOzccSA5UHSjfUrKbWzXc9HwMkw,7549
|
|
28
|
+
getanyapi/platforms/google_ads.py,sha256=gfuQhn4qlnx6kmfV2kXyRIv_QA9sOdVKO9_Ik1_6_3U,13614
|
|
29
|
+
getanyapi/platforms/google_finance.py,sha256=jiG6PFBFQkEpfykGY_-lcHNydRKv_sV7fsuR7HR65-E,6792
|
|
30
|
+
getanyapi/platforms/google_shopping.py,sha256=BxJbLjvu7TrGhbfKQvyFG5svKZQcupLLySuK-2aBXqE,3588
|
|
31
|
+
getanyapi/platforms/hackernews.py,sha256=aeNVz-g431VY32cWewUMX_3ihPcP4WObwfdTmihv53o,8300
|
|
32
|
+
getanyapi/platforms/indeed.py,sha256=AX7J9Fv3WWp2R7kT5HIocthKm0NZR7vvVBHkeyL6xTE,4102
|
|
33
|
+
getanyapi/platforms/instagram.py,sha256=HYiCVyM7iWO5ovVlAwLscB8h9AOmT5TWgfbmKfJiki8,63392
|
|
34
|
+
getanyapi/platforms/linkedin.py,sha256=cTCVnczHXbeAqc5a8BVTIilUp2ZC4EXsu9JQpWNJRY4,37733
|
|
35
|
+
getanyapi/platforms/maps.py,sha256=izaJQYEajGHSGd-wi4YGGsxX-a5xLKUBGynRuzjGs14,15652
|
|
36
|
+
getanyapi/platforms/pandaexpress.py,sha256=aho5rmWoBhuXO_HJ8Zi2LQjtT8aBrMyq_e-4kjC9ils,8849
|
|
37
|
+
getanyapi/platforms/person.py,sha256=lCJzooQBT9obE85kt_EqZwV8Rrms8djdZBU-qjGBi6I,3103
|
|
38
|
+
getanyapi/platforms/pinterest.py,sha256=p06-OtlALRADGIbLPo5Yi7HFPDYd3eLURR9QVcHxmdI,3179
|
|
39
|
+
getanyapi/platforms/playstore.py,sha256=cOZBvydXZZ3VjmdIGFLROxGy0bEc_71XSUFeQbbBMJc,3319
|
|
40
|
+
getanyapi/platforms/polymarket.py,sha256=kQakMp8RPOQik-9t9EkFm8NhZxqKEiKMMOy6XeQlmeo,3688
|
|
41
|
+
getanyapi/platforms/realtor.py,sha256=kzs4GKXCOXJi6xMu31euYd_LeRiE5NnwONCWgcLNK38,3488
|
|
42
|
+
getanyapi/platforms/reddit.py,sha256=XaLnDqxKtOrL4Ga5cakAeKd58ceIbKj7p1aTWAUWS6o,22240
|
|
43
|
+
getanyapi/platforms/redfin.py,sha256=zbNlOLr3ec632NDpvwlqm_-KdprErB0UH61w9gtOvXM,3092
|
|
44
|
+
getanyapi/platforms/rednote.py,sha256=rBbEJpOVjg2vlQxqXzmBfPxbpM2nOvUYbobxQe9UkE4,27399
|
|
45
|
+
getanyapi/platforms/sec.py,sha256=Sk7K2k-t3cu5L-8bI2imPH9sG9aYVnsL0I9BCcaC388,4352
|
|
46
|
+
getanyapi/platforms/semrush.py,sha256=aNf_PlYzQ0m6vD2lOwMkRYoM2yCTK4MCh6K8dTCEbIA,12949
|
|
47
|
+
getanyapi/platforms/snapchat.py,sha256=tKe5SG82v-Q3seNqjoRje3CefkNpHYWkOA19vzaW4cQ,4981
|
|
48
|
+
getanyapi/platforms/social.py,sha256=4Hc7lZSUS19I61jICj1P4QwgF8eU8LokMnijoWU-jz4,3751
|
|
49
|
+
getanyapi/platforms/spotify.py,sha256=_MBAwZyvxVBmL6y7q5NeL1aTK8_PSqn5jD5sp5Msnyw,18262
|
|
50
|
+
getanyapi/platforms/substack.py,sha256=CZaZedMEn8ANBvZdAA0YqKU4lqFbLN_v6dNDSdye6qg,5674
|
|
51
|
+
getanyapi/platforms/threads.py,sha256=kcAbjPU6mAdAs8DIUA_R24aOekD_FLpCMwRkSyChM0Y,11196
|
|
52
|
+
getanyapi/platforms/tiktok.py,sha256=t-Ca9buzdTdUn2ec8IEJpojwT7rmEJBcuyylL2yJIwc,59613
|
|
53
|
+
getanyapi/platforms/tiktok_shop.py,sha256=pS5EdpfKrKaCizxEK4ddwRCGO5spQQ2kR5CgdhcvQI8,19159
|
|
54
|
+
getanyapi/platforms/tripadvisor.py,sha256=ygpZVlKN6rx30KOsAYUGH1vmwHIIhF7Y9mHW847VLK0,6506
|
|
55
|
+
getanyapi/platforms/trustpilot.py,sha256=qWaf9CVNOQLLfZhO68lMsL227TxwM8SmbguzyS4XJ-I,4136
|
|
56
|
+
getanyapi/platforms/truthsocial.py,sha256=HZ-uCZgEw-LDt5KDjPp8UeJsucVxrsvygj0Uwt7Hs3U,7117
|
|
57
|
+
getanyapi/platforms/twitter.py,sha256=1OZEXB7l9MIJHNz8IdJ4Sfdb_1XvnEZ8NVhIIppz87E,28145
|
|
58
|
+
getanyapi/platforms/upwork.py,sha256=huQbW-JETgrvS8UhzPAsJWujOQmu3padvHKgQSCVego,4280
|
|
59
|
+
getanyapi/platforms/walmart.py,sha256=q2IjO9XYOmGgfsqOTdFk59whm75_LG4UYmlm3_bZOXs,2839
|
|
60
|
+
getanyapi/platforms/web.py,sha256=blR1C_SjGv3yj-m3ChtH-_Kx1LmW1BfHOKwsV8ZmqKE,8173
|
|
61
|
+
getanyapi/platforms/whatsapp.py,sha256=XLJef7q8tS5MRsgXB44p6wt2mTakRLsC9sW_mJGwta4,2717
|
|
62
|
+
getanyapi/platforms/yahoo_finance.py,sha256=dWxihVJORkYCN-0agOCVhMYxrkm-nLjfS0AntQj83fo,3003
|
|
63
|
+
getanyapi/platforms/yelp.py,sha256=yDtXy6DtJzTWlJ0vJL4uTr9q_En_De_4Ooosg_-bgoQ,5367
|
|
64
|
+
getanyapi/platforms/youtube.py,sha256=wCe1HGvSnie0GDaX57dklshhuBysb9yuomAnKK7NNiA,48148
|
|
65
|
+
getanyapi/platforms/zillow.py,sha256=k0gcHrjGTjGBlndS1pvdwLDIxarU7u8k9QJUE2h8aco,7931
|
|
66
|
+
getanyapi-0.1.0.dist-info/METADATA,sha256=zOiRh6uimk-8PxFHYbMI9XM3wyv4gFkR4iS0x-0MYE4,5459
|
|
67
|
+
getanyapi-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
68
|
+
getanyapi-0.1.0.dist-info/RECORD,,
|