mrscraper-sdk 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.
- mrscraper_sdk-0.1.0/.gitignore +64 -0
- mrscraper_sdk-0.1.0/LICENSE +21 -0
- mrscraper_sdk-0.1.0/PKG-INFO +274 -0
- mrscraper_sdk-0.1.0/README.md +240 -0
- mrscraper_sdk-0.1.0/pyproject.toml +79 -0
- mrscraper_sdk-0.1.0/src/mrscraper/__init__.py +31 -0
- mrscraper_sdk-0.1.0/src/mrscraper/exceptions.py +23 -0
- mrscraper_sdk-0.1.0/src/mrscraper/mrscraper.py +549 -0
- mrscraper_sdk-0.1.0/tests/__init__.py +0 -0
- mrscraper_sdk-0.1.0/tests/test_client_integration.py +177 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
eggs/
|
|
12
|
+
parts/
|
|
13
|
+
var/
|
|
14
|
+
sdist/
|
|
15
|
+
wheels/
|
|
16
|
+
pip-wheel-metadata/
|
|
17
|
+
share/python-wheels/
|
|
18
|
+
*.manifest
|
|
19
|
+
*.spec
|
|
20
|
+
debug_dir/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
env/
|
|
27
|
+
ENV/
|
|
28
|
+
|
|
29
|
+
# Distribution / packaging
|
|
30
|
+
.eggs/
|
|
31
|
+
*.tar.gz
|
|
32
|
+
|
|
33
|
+
# Unit test / coverage
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
htmlcov/
|
|
37
|
+
.cache
|
|
38
|
+
.pytest_cache/
|
|
39
|
+
nosetests.xml
|
|
40
|
+
coverage.xml
|
|
41
|
+
*.cover
|
|
42
|
+
.hypothesis/
|
|
43
|
+
|
|
44
|
+
# Type checking
|
|
45
|
+
.mypy_cache/
|
|
46
|
+
.dmypy.json
|
|
47
|
+
dmypy.json
|
|
48
|
+
.pytype/
|
|
49
|
+
.pyre/
|
|
50
|
+
|
|
51
|
+
# IDEs
|
|
52
|
+
.idea/
|
|
53
|
+
.vscode/
|
|
54
|
+
*.swp
|
|
55
|
+
*.swo
|
|
56
|
+
*~
|
|
57
|
+
|
|
58
|
+
# macOS
|
|
59
|
+
.DS_Store
|
|
60
|
+
|
|
61
|
+
# Environment files
|
|
62
|
+
.env
|
|
63
|
+
.env.*
|
|
64
|
+
!.env.example
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MrScraper
|
|
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,274 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mrscraper-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the MrScraper web-scraping API
|
|
5
|
+
Project-URL: Homepage, https://mrscraper.com
|
|
6
|
+
Project-URL: Documentation, https://docs.mrscraper.com
|
|
7
|
+
Project-URL: Repository, https://github.com/mrscraper/mrscraper-python
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/mrscraper/mrscraper-python/issues
|
|
9
|
+
Author: MrScraper
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api,mrscraper,scraping,sdk,web scraping
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Requires-Dist: httpx>=0.27
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
31
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# MrScraper Python SDK
|
|
36
|
+
|
|
37
|
+
A clean, typed Python client for the [MrScraper](https://mrscraper.com) web-scraping API.
|
|
38
|
+
Supports **async/await** usage.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install mrscraper-sdk
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Requires Python 3.9+.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Authentication
|
|
53
|
+
|
|
54
|
+
Every client is initialised with your MrScraper API token.
|
|
55
|
+
Get yours at <https://app.mrscraper.com>.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from mrscraper import MrScraper
|
|
59
|
+
|
|
60
|
+
client = MrScraper(token="atk_your_token_here")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
### Fetch raw HTML (stealth browser)
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import asyncio
|
|
71
|
+
from mrscraper import MrScraper
|
|
72
|
+
|
|
73
|
+
async def main():
|
|
74
|
+
client = MrScraper(token="atk_your_token_here")
|
|
75
|
+
|
|
76
|
+
result = await client.fetch_html(
|
|
77
|
+
"https://stockx.com/air-jordan-1-retro-low-og-chicago-2025",
|
|
78
|
+
geo_code="US",
|
|
79
|
+
timeout=120,
|
|
80
|
+
block_resources=False,
|
|
81
|
+
)
|
|
82
|
+
print(result["data"]) # raw HTML string
|
|
83
|
+
|
|
84
|
+
asyncio.run(main())
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Create an AI scraper
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
result = await client.create_scraper(
|
|
91
|
+
url="https://example.com/products",
|
|
92
|
+
message="Extract all product names, prices, and ratings",
|
|
93
|
+
agent="listing", # "general" | "listing" | "map"
|
|
94
|
+
proxy_country="US",
|
|
95
|
+
)
|
|
96
|
+
scraper_id = result["data"]["data"]["id"]
|
|
97
|
+
print("Scraper ID:", scraper_id)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Rerun a scraper on a new URL
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
result = await client.rerun_scraper(
|
|
104
|
+
scraper_id=scraper_id,
|
|
105
|
+
url="https://example.com/products?page=2",
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Bulk rerun on multiple URLs (AI scraper)
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
result = await client.bulk_rerun_scraper(
|
|
113
|
+
scraper_id=scraper_id,
|
|
114
|
+
urls=[
|
|
115
|
+
"https://example.com/products/item1",
|
|
116
|
+
"https://example.com/products/item2",
|
|
117
|
+
"https://example.com/products/item3",
|
|
118
|
+
],
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Rerun a manually configured scraper
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
result = await client.rerun_manual_scraper(
|
|
126
|
+
scraper_id="manual_scraper_67890",
|
|
127
|
+
url="https://example.com/products/new-item",
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Bulk rerun manual scraper on multiple URLs
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
result = await client.bulk_rerun_manual_scraper(
|
|
135
|
+
scraper_id="scraper_12345",
|
|
136
|
+
urls=[
|
|
137
|
+
"https://www.example.com/products/item1",
|
|
138
|
+
"https://www.example.com/products/item2",
|
|
139
|
+
"https://www.example.com/products/item3",
|
|
140
|
+
],
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Retrieve results
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# All results (paginated)
|
|
148
|
+
page = await client.get_all_results(
|
|
149
|
+
sort_field="updatedAt",
|
|
150
|
+
sort_order="DESC",
|
|
151
|
+
page_size=20,
|
|
152
|
+
page=1,
|
|
153
|
+
search="product",
|
|
154
|
+
date_range_column="updatedAt",
|
|
155
|
+
start_at="2024-01-01",
|
|
156
|
+
end_at="2024-01-31",
|
|
157
|
+
)
|
|
158
|
+
print(page["data"])
|
|
159
|
+
|
|
160
|
+
# A specific result by ID
|
|
161
|
+
result = await client.get_result_by_id("result_12345")
|
|
162
|
+
print(result["data"])
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## API Reference
|
|
168
|
+
|
|
169
|
+
### `MrScraper`
|
|
170
|
+
|
|
171
|
+
All methods are coroutines and must be awaited.
|
|
172
|
+
|
|
173
|
+
| Method | Description |
|
|
174
|
+
|--------|-------------|
|
|
175
|
+
| `fetch_html(url, *, timeout, geo_code, block_resources)` | Fetch rendered HTML via the MrScraper stealth browser |
|
|
176
|
+
| `create_scraper(url, message, *, agent, proxy_country, ...)` | Create & run an AI-powered scraper |
|
|
177
|
+
| `rerun_scraper(scraper_id, url, *, max_depth, max_pages, limit, ...)` | Rerun an AI scraper on a new URL |
|
|
178
|
+
| `bulk_rerun_scraper(scraper_id, urls)` | Rerun an AI scraper on multiple URLs in one batch |
|
|
179
|
+
| `rerun_manual_scraper(scraper_id, url)` | Rerun a manually configured scraper on a single URL |
|
|
180
|
+
| `bulk_rerun_manual_scraper(scraper_id, urls)` | Rerun a manual scraper on multiple URLs in one batch |
|
|
181
|
+
| `get_all_results(*, sort_field, sort_order, page_size, page, search, ...)` | List all results with filtering & pagination |
|
|
182
|
+
| `get_result_by_id(result_id)` | Fetch a single result by its ID |
|
|
183
|
+
|
|
184
|
+
All methods return a `dict` with the following keys:
|
|
185
|
+
|
|
186
|
+
| Key | Type | Description |
|
|
187
|
+
|-----|------|-------------|
|
|
188
|
+
| `status_code` | `int` | HTTP status code |
|
|
189
|
+
| `data` | `Any` | Parsed JSON body or raw text |
|
|
190
|
+
| `headers` | `dict` | Response headers |
|
|
191
|
+
|
|
192
|
+
### `bulk_rerun_manual_scraper`
|
|
193
|
+
|
|
194
|
+
Reruns a manually configured scraper on multiple URLs simultaneously in a single batch operation. This is more efficient than calling `rerun_manual_scraper` multiple times, as it processes all URLs in parallel and returns consolidated results. Ideal for scraping multiple pages, products, or articles with the same extraction logic.
|
|
195
|
+
|
|
196
|
+
| Argument | Description |
|
|
197
|
+
|----------|-------------|
|
|
198
|
+
| `scraper_id` | The ID of the manual scraper to rerun (obtained from the MrScraper dashboard). Must be a scraper created manually through the web interface, not an AI scraper. Find it at https://app.mrscraper.com |
|
|
199
|
+
| `urls` | A list of target URLs to scrape (required, must contain at least one URL). Each URL will be processed independently using the scraper's extraction logic. Example: `["https://example.com/page1", "https://example.com/page2"]` |
|
|
200
|
+
|
|
201
|
+
**Returns:** A dict with `status_code`, `data` (bulk job info including job ID, status, metadata; use `get_all_results` or `get_result_by_id` to fetch per-URL results), and `headers`.
|
|
202
|
+
|
|
203
|
+
**Example:**
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
result = await client.bulk_rerun_manual_scraper(
|
|
207
|
+
scraper_id="scraper_12345",
|
|
208
|
+
urls=[
|
|
209
|
+
"https://www.example.com/products/item1",
|
|
210
|
+
"https://www.example.com/products/item2",
|
|
211
|
+
"https://www.example.com/products/item3",
|
|
212
|
+
],
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `create_scraper` — agent types
|
|
217
|
+
|
|
218
|
+
| Agent | Best used for |
|
|
219
|
+
|-------|---------------|
|
|
220
|
+
| `"general"` | Default; handles almost any page |
|
|
221
|
+
| `"listing"` | Product listings, job boards, search results |
|
|
222
|
+
| `"map"` | Crawling all sub-pages / sitemaps of a site |
|
|
223
|
+
|
|
224
|
+
The `max_depth`, `max_pages`, `limit`, `include_patterns`, and `exclude_patterns`
|
|
225
|
+
parameters are only meaningful when `agent="map"`.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Exceptions
|
|
230
|
+
|
|
231
|
+
| Exception | Raised when |
|
|
232
|
+
|-----------|-------------|
|
|
233
|
+
| `MrScraperError` | Base class for all SDK errors |
|
|
234
|
+
| `AuthenticationError` | API token is invalid or missing (HTTP 401) |
|
|
235
|
+
| `APIError` | API returned a non-2xx error; has `.status_code` attribute |
|
|
236
|
+
| `NetworkError` | Connection timeout or network-level failure |
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from mrscraper.exceptions import AuthenticationError, APIError, NetworkError
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
result = await client.fetch_html("https://example.com")
|
|
243
|
+
except AuthenticationError:
|
|
244
|
+
print("Check your API token at https://app.mrscraper.com")
|
|
245
|
+
except APIError as e:
|
|
246
|
+
print(f"API error {e.status_code}: {e}")
|
|
247
|
+
except NetworkError as e:
|
|
248
|
+
print(f"Network problem: {e}")
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Development
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Install with dev dependencies
|
|
257
|
+
pip install -e ".[dev]"
|
|
258
|
+
|
|
259
|
+
# Run tests
|
|
260
|
+
pytest
|
|
261
|
+
|
|
262
|
+
# Lint & format
|
|
263
|
+
ruff check .
|
|
264
|
+
ruff format .
|
|
265
|
+
|
|
266
|
+
# Type check
|
|
267
|
+
mypy src/mrscraper
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
MIT © MrScraper
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# MrScraper Python SDK
|
|
2
|
+
|
|
3
|
+
A clean, typed Python client for the [MrScraper](https://mrscraper.com) web-scraping API.
|
|
4
|
+
Supports **async/await** usage.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install mrscraper-sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Requires Python 3.9+.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Authentication
|
|
19
|
+
|
|
20
|
+
Every client is initialised with your MrScraper API token.
|
|
21
|
+
Get yours at <https://app.mrscraper.com>.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from mrscraper import MrScraper
|
|
25
|
+
|
|
26
|
+
client = MrScraper(token="atk_your_token_here")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### Fetch raw HTML (stealth browser)
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import asyncio
|
|
37
|
+
from mrscraper import MrScraper
|
|
38
|
+
|
|
39
|
+
async def main():
|
|
40
|
+
client = MrScraper(token="atk_your_token_here")
|
|
41
|
+
|
|
42
|
+
result = await client.fetch_html(
|
|
43
|
+
"https://stockx.com/air-jordan-1-retro-low-og-chicago-2025",
|
|
44
|
+
geo_code="US",
|
|
45
|
+
timeout=120,
|
|
46
|
+
block_resources=False,
|
|
47
|
+
)
|
|
48
|
+
print(result["data"]) # raw HTML string
|
|
49
|
+
|
|
50
|
+
asyncio.run(main())
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Create an AI scraper
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
result = await client.create_scraper(
|
|
57
|
+
url="https://example.com/products",
|
|
58
|
+
message="Extract all product names, prices, and ratings",
|
|
59
|
+
agent="listing", # "general" | "listing" | "map"
|
|
60
|
+
proxy_country="US",
|
|
61
|
+
)
|
|
62
|
+
scraper_id = result["data"]["data"]["id"]
|
|
63
|
+
print("Scraper ID:", scraper_id)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Rerun a scraper on a new URL
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
result = await client.rerun_scraper(
|
|
70
|
+
scraper_id=scraper_id,
|
|
71
|
+
url="https://example.com/products?page=2",
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Bulk rerun on multiple URLs (AI scraper)
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
result = await client.bulk_rerun_scraper(
|
|
79
|
+
scraper_id=scraper_id,
|
|
80
|
+
urls=[
|
|
81
|
+
"https://example.com/products/item1",
|
|
82
|
+
"https://example.com/products/item2",
|
|
83
|
+
"https://example.com/products/item3",
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Rerun a manually configured scraper
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
result = await client.rerun_manual_scraper(
|
|
92
|
+
scraper_id="manual_scraper_67890",
|
|
93
|
+
url="https://example.com/products/new-item",
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Bulk rerun manual scraper on multiple URLs
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
result = await client.bulk_rerun_manual_scraper(
|
|
101
|
+
scraper_id="scraper_12345",
|
|
102
|
+
urls=[
|
|
103
|
+
"https://www.example.com/products/item1",
|
|
104
|
+
"https://www.example.com/products/item2",
|
|
105
|
+
"https://www.example.com/products/item3",
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Retrieve results
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# All results (paginated)
|
|
114
|
+
page = await client.get_all_results(
|
|
115
|
+
sort_field="updatedAt",
|
|
116
|
+
sort_order="DESC",
|
|
117
|
+
page_size=20,
|
|
118
|
+
page=1,
|
|
119
|
+
search="product",
|
|
120
|
+
date_range_column="updatedAt",
|
|
121
|
+
start_at="2024-01-01",
|
|
122
|
+
end_at="2024-01-31",
|
|
123
|
+
)
|
|
124
|
+
print(page["data"])
|
|
125
|
+
|
|
126
|
+
# A specific result by ID
|
|
127
|
+
result = await client.get_result_by_id("result_12345")
|
|
128
|
+
print(result["data"])
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## API Reference
|
|
134
|
+
|
|
135
|
+
### `MrScraper`
|
|
136
|
+
|
|
137
|
+
All methods are coroutines and must be awaited.
|
|
138
|
+
|
|
139
|
+
| Method | Description |
|
|
140
|
+
|--------|-------------|
|
|
141
|
+
| `fetch_html(url, *, timeout, geo_code, block_resources)` | Fetch rendered HTML via the MrScraper stealth browser |
|
|
142
|
+
| `create_scraper(url, message, *, agent, proxy_country, ...)` | Create & run an AI-powered scraper |
|
|
143
|
+
| `rerun_scraper(scraper_id, url, *, max_depth, max_pages, limit, ...)` | Rerun an AI scraper on a new URL |
|
|
144
|
+
| `bulk_rerun_scraper(scraper_id, urls)` | Rerun an AI scraper on multiple URLs in one batch |
|
|
145
|
+
| `rerun_manual_scraper(scraper_id, url)` | Rerun a manually configured scraper on a single URL |
|
|
146
|
+
| `bulk_rerun_manual_scraper(scraper_id, urls)` | Rerun a manual scraper on multiple URLs in one batch |
|
|
147
|
+
| `get_all_results(*, sort_field, sort_order, page_size, page, search, ...)` | List all results with filtering & pagination |
|
|
148
|
+
| `get_result_by_id(result_id)` | Fetch a single result by its ID |
|
|
149
|
+
|
|
150
|
+
All methods return a `dict` with the following keys:
|
|
151
|
+
|
|
152
|
+
| Key | Type | Description |
|
|
153
|
+
|-----|------|-------------|
|
|
154
|
+
| `status_code` | `int` | HTTP status code |
|
|
155
|
+
| `data` | `Any` | Parsed JSON body or raw text |
|
|
156
|
+
| `headers` | `dict` | Response headers |
|
|
157
|
+
|
|
158
|
+
### `bulk_rerun_manual_scraper`
|
|
159
|
+
|
|
160
|
+
Reruns a manually configured scraper on multiple URLs simultaneously in a single batch operation. This is more efficient than calling `rerun_manual_scraper` multiple times, as it processes all URLs in parallel and returns consolidated results. Ideal for scraping multiple pages, products, or articles with the same extraction logic.
|
|
161
|
+
|
|
162
|
+
| Argument | Description |
|
|
163
|
+
|----------|-------------|
|
|
164
|
+
| `scraper_id` | The ID of the manual scraper to rerun (obtained from the MrScraper dashboard). Must be a scraper created manually through the web interface, not an AI scraper. Find it at https://app.mrscraper.com |
|
|
165
|
+
| `urls` | A list of target URLs to scrape (required, must contain at least one URL). Each URL will be processed independently using the scraper's extraction logic. Example: `["https://example.com/page1", "https://example.com/page2"]` |
|
|
166
|
+
|
|
167
|
+
**Returns:** A dict with `status_code`, `data` (bulk job info including job ID, status, metadata; use `get_all_results` or `get_result_by_id` to fetch per-URL results), and `headers`.
|
|
168
|
+
|
|
169
|
+
**Example:**
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
result = await client.bulk_rerun_manual_scraper(
|
|
173
|
+
scraper_id="scraper_12345",
|
|
174
|
+
urls=[
|
|
175
|
+
"https://www.example.com/products/item1",
|
|
176
|
+
"https://www.example.com/products/item2",
|
|
177
|
+
"https://www.example.com/products/item3",
|
|
178
|
+
],
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### `create_scraper` — agent types
|
|
183
|
+
|
|
184
|
+
| Agent | Best used for |
|
|
185
|
+
|-------|---------------|
|
|
186
|
+
| `"general"` | Default; handles almost any page |
|
|
187
|
+
| `"listing"` | Product listings, job boards, search results |
|
|
188
|
+
| `"map"` | Crawling all sub-pages / sitemaps of a site |
|
|
189
|
+
|
|
190
|
+
The `max_depth`, `max_pages`, `limit`, `include_patterns`, and `exclude_patterns`
|
|
191
|
+
parameters are only meaningful when `agent="map"`.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Exceptions
|
|
196
|
+
|
|
197
|
+
| Exception | Raised when |
|
|
198
|
+
|-----------|-------------|
|
|
199
|
+
| `MrScraperError` | Base class for all SDK errors |
|
|
200
|
+
| `AuthenticationError` | API token is invalid or missing (HTTP 401) |
|
|
201
|
+
| `APIError` | API returned a non-2xx error; has `.status_code` attribute |
|
|
202
|
+
| `NetworkError` | Connection timeout or network-level failure |
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from mrscraper.exceptions import AuthenticationError, APIError, NetworkError
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
result = await client.fetch_html("https://example.com")
|
|
209
|
+
except AuthenticationError:
|
|
210
|
+
print("Check your API token at https://app.mrscraper.com")
|
|
211
|
+
except APIError as e:
|
|
212
|
+
print(f"API error {e.status_code}: {e}")
|
|
213
|
+
except NetworkError as e:
|
|
214
|
+
print(f"Network problem: {e}")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Development
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Install with dev dependencies
|
|
223
|
+
pip install -e ".[dev]"
|
|
224
|
+
|
|
225
|
+
# Run tests
|
|
226
|
+
pytest
|
|
227
|
+
|
|
228
|
+
# Lint & format
|
|
229
|
+
ruff check .
|
|
230
|
+
ruff format .
|
|
231
|
+
|
|
232
|
+
# Type check
|
|
233
|
+
mypy src/mrscraper
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT © MrScraper
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mrscraper-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python SDK for the MrScraper web-scraping API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "MrScraper", url = "https://mrscraper.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["scraping", "web scraping", "mrscraper", "api", "sdk"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"httpx>=0.27",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://mrscraper.com"
|
|
36
|
+
Documentation = "https://docs.mrscraper.com"
|
|
37
|
+
Repository = "https://github.com/mrscraper/mrscraper-python"
|
|
38
|
+
"Bug Tracker" = "https://github.com/mrscraper/mrscraper-python/issues"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/mrscraper"]
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
include = [
|
|
45
|
+
"src/",
|
|
46
|
+
"tests/",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE",
|
|
49
|
+
"pyproject.toml",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[project.optional-dependencies]
|
|
53
|
+
dev = [
|
|
54
|
+
"pytest>=8",
|
|
55
|
+
"pytest-asyncio>=0.24",
|
|
56
|
+
"respx>=0.21",
|
|
57
|
+
"ruff>=0.4",
|
|
58
|
+
"mypy>=1.10",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 100
|
|
63
|
+
target-version = "py39"
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
67
|
+
ignore = ["E501"]
|
|
68
|
+
|
|
69
|
+
[tool.mypy]
|
|
70
|
+
python_version = "3.9"
|
|
71
|
+
strict = true
|
|
72
|
+
files = ["src/mrscraper"]
|
|
73
|
+
|
|
74
|
+
[tool.pytest.ini_options]
|
|
75
|
+
asyncio_mode = "auto"
|
|
76
|
+
testpaths = ["tests"]
|
|
77
|
+
markers = [
|
|
78
|
+
"integration: marks tests as integration tests (hit real API)",
|
|
79
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MrScraper Python SDK
|
|
3
|
+
|
|
4
|
+
A clean Python client for the `MrScraper <https://mrscraper.com>`_ API.
|
|
5
|
+
Supports async/await usage.
|
|
6
|
+
|
|
7
|
+
Quickstart::
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
from mrscraper import MrScraper
|
|
11
|
+
|
|
12
|
+
async def main():
|
|
13
|
+
client = MrScraper(token="atk_your_token_here")
|
|
14
|
+
result = await client.fetch_html("https://example.com")
|
|
15
|
+
print(result["data"])
|
|
16
|
+
|
|
17
|
+
asyncio.run(main())
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .mrscraper import MrScraper
|
|
21
|
+
from .exceptions import APIError, AuthenticationError, MrScraperError, NetworkError
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"MrScraper",
|
|
25
|
+
"MrScraperError",
|
|
26
|
+
"AuthenticationError",
|
|
27
|
+
"APIError",
|
|
28
|
+
"NetworkError",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
__version__ = "0.1.0"
|