herascrape 0.1.0__tar.gz

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.
@@ -0,0 +1,28 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ venv/
7
+ uv.lock
8
+ build/
9
+ dist/
10
+
11
+ # Tooling caches
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .pyright/
15
+ .coverage
16
+ htmlcov/
17
+
18
+ # Secrets and local environment
19
+ .env
20
+ .env.*
21
+
22
+ # Local tooling
23
+ .superpowers/
24
+ .vscode/
25
+ .DS_Store
26
+
27
+ # Node
28
+ node_modules/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 herascrape
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,209 @@
1
+ Metadata-Version: 2.5
2
+ Name: herascrape
3
+ Version: 0.1.0
4
+ Summary: Official Python client for the herascrape Instagram API.
5
+ Project-URL: Homepage, https://herascrape.com
6
+ Project-URL: Repository, https://github.com/herascrape/herascrape
7
+ Author: herascrape
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: instagram api,instagram private api,instagram scraper
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: httpx>=0.24
21
+ Description-Content-Type: text/markdown
22
+
23
+ # herascrape: Instagram API client for Python
24
+
25
+ `herascrape` is the official Python client for the
26
+ [herascrape](https://herascrape.com) Instagram API. It is an Instagram scraper
27
+ API that reads Instagram's private API for you and hands back Instagram's own
28
+ JSON: profiles, followers, posts, reels, comments, hashtags, locations, audio,
29
+ stories and search. You do not manage Instagram accounts, devices or proxies.
30
+
31
+ ```python
32
+ from herascrape import Client
33
+
34
+ client = Client(api_key="hs_live_xxxxxxxx")
35
+
36
+ user = client.user_by_username(username="instagram")
37
+ print(user["username"], user["follower_count"])
38
+
39
+ for follower in client.iter_user_followers(user["pk"], max_items=100):
40
+ print(follower["username"])
41
+ ```
42
+
43
+ - 37 endpoints, one method each, plus lazy `iter_*` paginators for the lists.
44
+ - Sync (`Client`) and async (`AsyncClient`) with the same surface.
45
+ - Typed exception hierarchy: `NotFoundError`, `PrivateAccountError`,
46
+ `RateLimitError` and the rest.
47
+ - Retries with backoff, `Retry-After` handling and a client-side rate limiter.
48
+ - Typed package (`py.typed`), Python 3.10+, one dependency: `httpx`.
49
+
50
+ Documentation: [herascrape.com/docs](https://herascrape.com/docs).
51
+
52
+ ## Install
53
+
54
+ ```bash
55
+ pip install herascrape
56
+ ```
57
+
58
+ ## Authentication
59
+
60
+ Create a key in the [dashboard](https://herascrape.com/api-keys); the client
61
+ sends it in the `x-api-key` header. Pass it to the constructor:
62
+
63
+ ```python
64
+ from herascrape import Client
65
+
66
+ client = Client(api_key="hs_live_xxxxxxxx")
67
+ ```
68
+
69
+ Or leave it out and the client reads `HERASCRAPE_API_KEY` from the environment.
70
+ With no key in either place, constructing a client raises `AuthenticationError`.
71
+ Keep keys out of source control.
72
+
73
+ Billing is per successful call, and failed calls are not billed. See
74
+ [pricing](https://herascrape.com/docs/getting-started/pricing).
75
+
76
+ ## Usage
77
+
78
+ Every method returns the response `data` as a plain `dict`, exactly as
79
+ Instagram sent it. Check an endpoint's *What comes back* section in the
80
+ [docs](https://herascrape.com/docs) before mapping fields.
81
+
82
+ ```python
83
+ from herascrape import Client
84
+
85
+ client = Client()
86
+
87
+ # Profiles: look a username up once, then use the numeric pk.
88
+ user = client.user_by_username(username="instagram")
89
+ page = client.user_followers(user["pk"])
90
+ print(len(page["items"]), page["has_more"], page["next_cursor"])
91
+
92
+ # Pagination: iter_* walks the pages lazily.
93
+ for reel in client.iter_user_reels(user["pk"], max_items=50):
94
+ print(reel["code"])
95
+
96
+ # Search: session UUIDs are generated for you.
97
+ for hit in client.search_users(query="nike")["items"]:
98
+ print(hit["pk"], hit["username"])
99
+
100
+ # Posts take a pk or a shortcode.
101
+ post = client.post("B4XpqViUFUI")
102
+ print(post["like_count"], post["comment_count"])
103
+
104
+ # Convert between a media pk and its shortcode.
105
+ print(client.resolve_media(code="B4XpqViUFUI"))
106
+ ```
107
+
108
+ List responses carry `items`, `next_cursor` and `has_more`. `post_comments`
109
+ and `user_posts` keep Instagram's own paging shape, so page those by hand; see
110
+ the [docs](https://herascrape.com/docs/getting-started/pagination).
111
+
112
+ ### Async
113
+
114
+ ```python
115
+ import asyncio
116
+
117
+ from herascrape import AsyncClient
118
+
119
+
120
+ async def main() -> None:
121
+ async with AsyncClient() as client:
122
+ user = await client.user_by_username(username="instagram")
123
+ async for follower in client.iter_user_followers(
124
+ user["pk"], max_items=100
125
+ ):
126
+ print(follower["username"])
127
+
128
+
129
+ asyncio.run(main())
130
+ ```
131
+
132
+ ## Errors
133
+
134
+ Every exception inherits from `HerascrapeError`. API errors are
135
+ `HerascrapeAPIError` subclasses carrying `status_code`, `error_code`, `detail`
136
+ and `request_id`.
137
+
138
+ ```python
139
+ from herascrape import Client, PrivateAccountError, ProfileNotFoundError
140
+
141
+ client = Client()
142
+
143
+ try:
144
+ followers = client.user_followers("25025320")
145
+ except PrivateAccountError:
146
+ print("private account")
147
+ except ProfileNotFoundError:
148
+ print("no such profile")
149
+ ```
150
+
151
+ | Exception | When |
152
+ | --- | --- |
153
+ | `BadRequestError` | 400. `InvalidCursorError` and `InvalidParameterError` are subclasses. |
154
+ | `AuthenticationError` | 401. Missing or invalid key. |
155
+ | `ForbiddenError` | 403. `PrivateAccountError` is the private-profile case. |
156
+ | `NotFoundError` | 404. `ProfileNotFoundError` is the unknown-profile case. |
157
+ | `ValidationError` | 422. Per-field messages in `field_errors`. |
158
+ | `RateLimitError` | 429. Seconds to wait in `retry_after`, when sent. |
159
+ | `ServerError` | 5xx. `InternalError`, `UpstreamError` and `ServiceUnavailableError` are subclasses. |
160
+ | `HerascrapeTransportError` | No response: connection failure or timeout. |
161
+
162
+ ## Retries and rate limiting
163
+
164
+ The client retries connection errors and timeouts, 429, 502, 503 and
165
+ `invalid_cursor` up to `max_retries` times (default 3), backing off from 0.5 s
166
+ to 8 s with jitter. A 429 with a `Retry-After` header waits that long, capped
167
+ at 300 s. It also throttles requests on the client with a token bucket that
168
+ defaults to 50 requests per second. Match it to your key's limit:
169
+
170
+ ```python
171
+ from herascrape import Client, RateLimit
172
+
173
+ client = Client(rate_limit=RateLimit(rate=10, period="s"))
174
+ client = Client(rate_limit=None) # no client-side limit
175
+ ```
176
+
177
+ Other constructor options: `timeout` (seconds, default 10), `max_retries`, and
178
+ `base_url` (default `https://api.herascrape.com`).
179
+
180
+ ## Endpoints
181
+
182
+ All 37 endpoints are `GET`s. The full table with paths is in the
183
+ [repository README](https://github.com/herascrape/herascrape#endpoints).
184
+
185
+ | Group | Methods |
186
+ | --- | --- |
187
+ | Users | `user_by_username`, `user`, `user_followers`, `user_following`, `user_posts`, `user_reels`, `user_tagged`, `user_stories`, `user_highlights`, `user_reposts`, `user_about` |
188
+ | Posts and comments | `post`, `post_comments`, `post_likers`, `comment_replies`, `comment_likers` |
189
+ | Search | `search_users`, `search_hashtags`, `search_audio`, `search_top`, `search_places` |
190
+ | Hashtags | `hashtag`, `hashtag_top`, `hashtag_recent`, `hashtag_reels` |
191
+ | Locations | `location`, `location_top`, `location_recent` |
192
+ | Audio | `audio_trending`, `audio`, `audio_medias` |
193
+ | Stories and highlights | `highlight`, `story` |
194
+ | Utility | `resolve_media`, `oembed`, `balance`, `health` |
195
+
196
+ Coming from HikerAPI? The
197
+ [migration guide](https://herascrape.com/docs/guides/hikerapi-migration) maps
198
+ each path to its herascrape equivalent.
199
+
200
+ ## Disclaimer
201
+
202
+ herascrape is not affiliated with, authorized, maintained, or endorsed by
203
+ Instagram or Meta. Instagram is a trademark of Meta Platforms, Inc. You are
204
+ responsible for using the data in line with applicable law and Instagram's
205
+ terms.
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,187 @@
1
+ # herascrape: Instagram API client for Python
2
+
3
+ `herascrape` is the official Python client for the
4
+ [herascrape](https://herascrape.com) Instagram API. It is an Instagram scraper
5
+ API that reads Instagram's private API for you and hands back Instagram's own
6
+ JSON: profiles, followers, posts, reels, comments, hashtags, locations, audio,
7
+ stories and search. You do not manage Instagram accounts, devices or proxies.
8
+
9
+ ```python
10
+ from herascrape import Client
11
+
12
+ client = Client(api_key="hs_live_xxxxxxxx")
13
+
14
+ user = client.user_by_username(username="instagram")
15
+ print(user["username"], user["follower_count"])
16
+
17
+ for follower in client.iter_user_followers(user["pk"], max_items=100):
18
+ print(follower["username"])
19
+ ```
20
+
21
+ - 37 endpoints, one method each, plus lazy `iter_*` paginators for the lists.
22
+ - Sync (`Client`) and async (`AsyncClient`) with the same surface.
23
+ - Typed exception hierarchy: `NotFoundError`, `PrivateAccountError`,
24
+ `RateLimitError` and the rest.
25
+ - Retries with backoff, `Retry-After` handling and a client-side rate limiter.
26
+ - Typed package (`py.typed`), Python 3.10+, one dependency: `httpx`.
27
+
28
+ Documentation: [herascrape.com/docs](https://herascrape.com/docs).
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install herascrape
34
+ ```
35
+
36
+ ## Authentication
37
+
38
+ Create a key in the [dashboard](https://herascrape.com/api-keys); the client
39
+ sends it in the `x-api-key` header. Pass it to the constructor:
40
+
41
+ ```python
42
+ from herascrape import Client
43
+
44
+ client = Client(api_key="hs_live_xxxxxxxx")
45
+ ```
46
+
47
+ Or leave it out and the client reads `HERASCRAPE_API_KEY` from the environment.
48
+ With no key in either place, constructing a client raises `AuthenticationError`.
49
+ Keep keys out of source control.
50
+
51
+ Billing is per successful call, and failed calls are not billed. See
52
+ [pricing](https://herascrape.com/docs/getting-started/pricing).
53
+
54
+ ## Usage
55
+
56
+ Every method returns the response `data` as a plain `dict`, exactly as
57
+ Instagram sent it. Check an endpoint's *What comes back* section in the
58
+ [docs](https://herascrape.com/docs) before mapping fields.
59
+
60
+ ```python
61
+ from herascrape import Client
62
+
63
+ client = Client()
64
+
65
+ # Profiles: look a username up once, then use the numeric pk.
66
+ user = client.user_by_username(username="instagram")
67
+ page = client.user_followers(user["pk"])
68
+ print(len(page["items"]), page["has_more"], page["next_cursor"])
69
+
70
+ # Pagination: iter_* walks the pages lazily.
71
+ for reel in client.iter_user_reels(user["pk"], max_items=50):
72
+ print(reel["code"])
73
+
74
+ # Search: session UUIDs are generated for you.
75
+ for hit in client.search_users(query="nike")["items"]:
76
+ print(hit["pk"], hit["username"])
77
+
78
+ # Posts take a pk or a shortcode.
79
+ post = client.post("B4XpqViUFUI")
80
+ print(post["like_count"], post["comment_count"])
81
+
82
+ # Convert between a media pk and its shortcode.
83
+ print(client.resolve_media(code="B4XpqViUFUI"))
84
+ ```
85
+
86
+ List responses carry `items`, `next_cursor` and `has_more`. `post_comments`
87
+ and `user_posts` keep Instagram's own paging shape, so page those by hand; see
88
+ the [docs](https://herascrape.com/docs/getting-started/pagination).
89
+
90
+ ### Async
91
+
92
+ ```python
93
+ import asyncio
94
+
95
+ from herascrape import AsyncClient
96
+
97
+
98
+ async def main() -> None:
99
+ async with AsyncClient() as client:
100
+ user = await client.user_by_username(username="instagram")
101
+ async for follower in client.iter_user_followers(
102
+ user["pk"], max_items=100
103
+ ):
104
+ print(follower["username"])
105
+
106
+
107
+ asyncio.run(main())
108
+ ```
109
+
110
+ ## Errors
111
+
112
+ Every exception inherits from `HerascrapeError`. API errors are
113
+ `HerascrapeAPIError` subclasses carrying `status_code`, `error_code`, `detail`
114
+ and `request_id`.
115
+
116
+ ```python
117
+ from herascrape import Client, PrivateAccountError, ProfileNotFoundError
118
+
119
+ client = Client()
120
+
121
+ try:
122
+ followers = client.user_followers("25025320")
123
+ except PrivateAccountError:
124
+ print("private account")
125
+ except ProfileNotFoundError:
126
+ print("no such profile")
127
+ ```
128
+
129
+ | Exception | When |
130
+ | --- | --- |
131
+ | `BadRequestError` | 400. `InvalidCursorError` and `InvalidParameterError` are subclasses. |
132
+ | `AuthenticationError` | 401. Missing or invalid key. |
133
+ | `ForbiddenError` | 403. `PrivateAccountError` is the private-profile case. |
134
+ | `NotFoundError` | 404. `ProfileNotFoundError` is the unknown-profile case. |
135
+ | `ValidationError` | 422. Per-field messages in `field_errors`. |
136
+ | `RateLimitError` | 429. Seconds to wait in `retry_after`, when sent. |
137
+ | `ServerError` | 5xx. `InternalError`, `UpstreamError` and `ServiceUnavailableError` are subclasses. |
138
+ | `HerascrapeTransportError` | No response: connection failure or timeout. |
139
+
140
+ ## Retries and rate limiting
141
+
142
+ The client retries connection errors and timeouts, 429, 502, 503 and
143
+ `invalid_cursor` up to `max_retries` times (default 3), backing off from 0.5 s
144
+ to 8 s with jitter. A 429 with a `Retry-After` header waits that long, capped
145
+ at 300 s. It also throttles requests on the client with a token bucket that
146
+ defaults to 50 requests per second. Match it to your key's limit:
147
+
148
+ ```python
149
+ from herascrape import Client, RateLimit
150
+
151
+ client = Client(rate_limit=RateLimit(rate=10, period="s"))
152
+ client = Client(rate_limit=None) # no client-side limit
153
+ ```
154
+
155
+ Other constructor options: `timeout` (seconds, default 10), `max_retries`, and
156
+ `base_url` (default `https://api.herascrape.com`).
157
+
158
+ ## Endpoints
159
+
160
+ All 37 endpoints are `GET`s. The full table with paths is in the
161
+ [repository README](https://github.com/herascrape/herascrape#endpoints).
162
+
163
+ | Group | Methods |
164
+ | --- | --- |
165
+ | Users | `user_by_username`, `user`, `user_followers`, `user_following`, `user_posts`, `user_reels`, `user_tagged`, `user_stories`, `user_highlights`, `user_reposts`, `user_about` |
166
+ | Posts and comments | `post`, `post_comments`, `post_likers`, `comment_replies`, `comment_likers` |
167
+ | Search | `search_users`, `search_hashtags`, `search_audio`, `search_top`, `search_places` |
168
+ | Hashtags | `hashtag`, `hashtag_top`, `hashtag_recent`, `hashtag_reels` |
169
+ | Locations | `location`, `location_top`, `location_recent` |
170
+ | Audio | `audio_trending`, `audio`, `audio_medias` |
171
+ | Stories and highlights | `highlight`, `story` |
172
+ | Utility | `resolve_media`, `oembed`, `balance`, `health` |
173
+
174
+ Coming from HikerAPI? The
175
+ [migration guide](https://herascrape.com/docs/guides/hikerapi-migration) maps
176
+ each path to its herascrape equivalent.
177
+
178
+ ## Disclaimer
179
+
180
+ herascrape is not affiliated with, authorized, maintained, or endorsed by
181
+ Instagram or Meta. Instagram is a trademark of Meta Platforms, Inc. You are
182
+ responsible for using the data in line with applicable law and Instagram's
183
+ terms.
184
+
185
+ ## License
186
+
187
+ MIT
@@ -0,0 +1,52 @@
1
+ from ._errors import (
2
+ AuthenticationError,
3
+ BadRequestError,
4
+ ForbiddenError,
5
+ HerascrapeAPIError,
6
+ HerascrapeError,
7
+ HerascrapeTransportError,
8
+ InternalError,
9
+ InvalidCursorError,
10
+ InvalidParameterError,
11
+ NotFoundError,
12
+ PrivateAccountError,
13
+ ProfileNotFoundError,
14
+ RateLimitError,
15
+ ServerError,
16
+ ServiceUnavailableError,
17
+ UpstreamError,
18
+ ValidationError,
19
+ )
20
+ from .async_client import AsyncClient
21
+ from .client import Client
22
+ from .ratelimit import RateLimit
23
+ from .types import BalanceResponse, MediaIdResolution, Page
24
+
25
+ __version__ = "0.1.0"
26
+
27
+ __all__ = [
28
+ "AsyncClient",
29
+ "AuthenticationError",
30
+ "BadRequestError",
31
+ "BalanceResponse",
32
+ "Client",
33
+ "ForbiddenError",
34
+ "HerascrapeAPIError",
35
+ "HerascrapeError",
36
+ "HerascrapeTransportError",
37
+ "InternalError",
38
+ "InvalidCursorError",
39
+ "InvalidParameterError",
40
+ "MediaIdResolution",
41
+ "NotFoundError",
42
+ "Page",
43
+ "PrivateAccountError",
44
+ "ProfileNotFoundError",
45
+ "RateLimit",
46
+ "RateLimitError",
47
+ "ServerError",
48
+ "ServiceUnavailableError",
49
+ "UpstreamError",
50
+ "ValidationError",
51
+ "__version__",
52
+ ]