scrapely-python 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.
- scrapely/__init__.py +246 -0
- scrapely/_browser_locations.py +5470 -0
- scrapely/actor.py +1836 -0
- scrapely/browser_configuration.py +146 -0
- scrapely/charging.py +1143 -0
- scrapely/charging_client.py +107 -0
- scrapely/configuration.py +375 -0
- scrapely/crypto/__init__.py +21 -0
- scrapely/crypto/_secrets.py +210 -0
- scrapely/errors.py +153 -0
- scrapely/events/__init__.py +57 -0
- scrapely/events/_types.py +194 -0
- scrapely/events/event_manager.py +292 -0
- scrapely/log.py +39 -0
- scrapely/patch_browser_pool.py +861 -0
- scrapely/pricing_types.py +172 -0
- scrapely/proxy_configuration.py +741 -0
- scrapely/py.typed +2 -0
- scrapely/request_loaders/__init__.py +5 -0
- scrapely/request_loaders/_scrapely_request_list.py +169 -0
- scrapely/storage/__init__.py +48 -0
- scrapely/storage/_file_system/__init__.py +9 -0
- scrapely/storage/_file_system/_key_value_store_client.py +155 -0
- scrapely/storage/_file_system/_storage_client.py +50 -0
- scrapely/storage/_metadata.py +138 -0
- scrapely/storage/api_client.py +350 -0
- scrapely/storage/client.py +618 -0
- scrapely/storage/patch_storage.py +257 -0
- scrapely/storage/scrapely_dataset_client.py +305 -0
- scrapely/storage/scrapely_kvs_client.py +220 -0
- scrapely/storage/scrapely_rq_client.py +496 -0
- scrapely/storage/scrapely_storage_client.py +192 -0
- scrapely/storage/smart_scrapely_storage_client.py +109 -0
- scrapely/storage/types.py +601 -0
- scrapely/storage/utils.py +38 -0
- scrapely/storage_clients/__init__.py +25 -0
- scrapely/storages/__init__.py +5 -0
- scrapely/types.py +269 -0
- scrapely/webhook.py +82 -0
- scrapely_python-0.1.0.dist-info/METADATA +83 -0
- scrapely_python-0.1.0.dist-info/RECORD +43 -0
- scrapely_python-0.1.0.dist-info/WHEEL +5 -0
- scrapely_python-0.1.0.dist-info/top_level.txt +1 -0
scrapely/types.py
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type definitions for the Scrapely Python SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
# Single source of truth for ChargeResult lives in pricing_types (pydantic model
|
|
11
|
+
# used by ChargingManager); re-exported here for backwards compatibility.
|
|
12
|
+
from .pricing_types import ChargeResult # noqa: F401 (re-export)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ActorPermissionLevel(str, Enum):
|
|
16
|
+
"""Actor permission level - matches Apify's ACTOR_PERMISSION_LEVEL enum."""
|
|
17
|
+
NONE = 'NONE'
|
|
18
|
+
RUN = 'RUN'
|
|
19
|
+
WRITE = 'WRITE'
|
|
20
|
+
ADMIN = 'ADMIN'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ActorInput:
|
|
25
|
+
"""Value types returned by Actor.get_input()."""
|
|
26
|
+
data: Dict[str, Any] = field(default_factory=dict)
|
|
27
|
+
|
|
28
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
29
|
+
return self.data.get(key, default)
|
|
30
|
+
|
|
31
|
+
def __getitem__(self, key: str) -> Any:
|
|
32
|
+
return self.data[key]
|
|
33
|
+
|
|
34
|
+
def __contains__(self, key: str) -> bool:
|
|
35
|
+
return key in self.data
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class ApifyEnv:
|
|
40
|
+
"""Parsed representation of the environment variables.
|
|
41
|
+
|
|
42
|
+
This object is returned by the Actor.get_env() function.
|
|
43
|
+
Fully compatible with Apify's ApifyEnv interface.
|
|
44
|
+
|
|
45
|
+
Supports both attribute access (env.memory_mbytes) and
|
|
46
|
+
dictionary-style subscript access (env['memory_mbytes']).
|
|
47
|
+
"""
|
|
48
|
+
actor_id: Optional[str] = None
|
|
49
|
+
actor_build_id: Optional[str] = None
|
|
50
|
+
actor_build_number: Optional[str] = None
|
|
51
|
+
actor_build_tags: Optional[str] = None
|
|
52
|
+
actor_events_ws_url: Optional[str] = None
|
|
53
|
+
actor_full_name: Optional[str] = None
|
|
54
|
+
actor_max_paid_dataset_items: Optional[int] = None
|
|
55
|
+
actor_permission_level: Optional[ActorPermissionLevel] = None
|
|
56
|
+
actor_pricing_info: Optional[str] = None
|
|
57
|
+
actor_run_id: Optional[str] = None
|
|
58
|
+
actor_storages_json: Optional[str] = None
|
|
59
|
+
actor_task_id: Optional[str] = None
|
|
60
|
+
api_base_url: Optional[str] = None
|
|
61
|
+
api_public_base_url: Optional[str] = None
|
|
62
|
+
charged_event_counts: Optional[str] = None
|
|
63
|
+
chrome_executable_path: Optional[str] = None
|
|
64
|
+
container_port: Optional[int] = None
|
|
65
|
+
container_url: Optional[str] = None
|
|
66
|
+
dedicated_cpus: Optional[str] = None
|
|
67
|
+
default_dataset_id: Optional[str] = None
|
|
68
|
+
default_key_value_store_id: Optional[str] = None
|
|
69
|
+
default_request_queue_id: Optional[str] = None
|
|
70
|
+
disable_outdated_warning: Optional[int] = None
|
|
71
|
+
fact: Optional[str] = None
|
|
72
|
+
headless: Optional[str] = None
|
|
73
|
+
input_key: Optional[str] = None
|
|
74
|
+
input_secrets_private_key_file: Optional[str] = None
|
|
75
|
+
input_secrets_private_key_passphrase: Optional[str] = None
|
|
76
|
+
is_at_home: Optional[str] = None
|
|
77
|
+
local_storage_dir: Optional[str] = None
|
|
78
|
+
log_format: Optional[str] = None
|
|
79
|
+
log_level: Optional[str] = None
|
|
80
|
+
memory_mbytes: Optional[int] = None
|
|
81
|
+
meta_origin: Optional[str] = None
|
|
82
|
+
metamorph_after_sleep_millis: Optional[int] = None
|
|
83
|
+
persist_state_interval_millis: Optional[int] = None
|
|
84
|
+
proxy_hostname: Optional[str] = None
|
|
85
|
+
proxy_password: Optional[str] = None
|
|
86
|
+
proxy_port: Optional[str] = None
|
|
87
|
+
proxy_status_url: Optional[str] = None
|
|
88
|
+
purge_on_start: Optional[str] = None
|
|
89
|
+
sdk_latest_version: Optional[str] = None
|
|
90
|
+
started_at: Optional[datetime] = None
|
|
91
|
+
standby_port: Optional[int] = None
|
|
92
|
+
standby_url: Optional[str] = None
|
|
93
|
+
system_info_interval_millis: Optional[str] = None
|
|
94
|
+
timeout_at: Optional[datetime] = None
|
|
95
|
+
token: Optional[str] = None
|
|
96
|
+
user_id: Optional[str] = None
|
|
97
|
+
user_is_paying: Optional[str] = None
|
|
98
|
+
user_pricing_tier: Optional[str] = None
|
|
99
|
+
workflow_key: Optional[str] = None
|
|
100
|
+
xvfb: Optional[str] = None
|
|
101
|
+
# Scrapely extensions / ACTOR_* extras
|
|
102
|
+
max_total_charge_usd: Optional[float] = None
|
|
103
|
+
user_plan: Optional[str] = None
|
|
104
|
+
restart_on_error: Optional[str] = None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def __getitem__(self, key: str) -> Any:
|
|
108
|
+
"""Enable dictionary-style access: env['memory_mbytes']."""
|
|
109
|
+
return getattr(self, key)
|
|
110
|
+
|
|
111
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
112
|
+
"""Enable dictionary-style assignment: env['memory_mbytes'] = 1024."""
|
|
113
|
+
setattr(self, key, value)
|
|
114
|
+
|
|
115
|
+
def keys(self) -> List[str]:
|
|
116
|
+
"""Return all field names that have values set (non-None)."""
|
|
117
|
+
return [f.name for f in self.__dataclass_fields__.values()
|
|
118
|
+
if getattr(self, f.name) is not None]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class WebhookOptions:
|
|
123
|
+
"""Options for Actor.add_webhook()."""
|
|
124
|
+
event_types: List[str] = field(default_factory=list)
|
|
125
|
+
request_url: str = ''
|
|
126
|
+
payload_template: Optional[str] = None
|
|
127
|
+
idempotency_key: Optional[str] = None
|
|
128
|
+
headers_template: Optional[str] = None
|
|
129
|
+
description: Optional[str] = None
|
|
130
|
+
ignore_ssl_errors: bool = False
|
|
131
|
+
do_not_retry: bool = False
|
|
132
|
+
should_interpolate_strings: bool = False
|
|
133
|
+
is_apify_integration: bool = False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class InitOptions:
|
|
138
|
+
"""Options for Actor.init()."""
|
|
139
|
+
configuration: Optional[Dict[str, Any]] = None
|
|
140
|
+
# ApiStorageConfig dict or a Crawlee StorageClient (tests / custom)
|
|
141
|
+
storage: Optional[Any] = None
|
|
142
|
+
graceful_shutdown: bool = True
|
|
143
|
+
graceful_shutdown_delay_millis: int = 0
|
|
144
|
+
# Set up the default log output (Apify Actor(configure_logging=True) parity)
|
|
145
|
+
configure_logging: bool = True
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@dataclass
|
|
149
|
+
class ExitOptions:
|
|
150
|
+
"""Options for Actor.exit()."""
|
|
151
|
+
status_message: Optional[str] = None
|
|
152
|
+
timeout_secs: int = 30
|
|
153
|
+
exit_code: int = 0
|
|
154
|
+
exit: bool = True
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass
|
|
158
|
+
class RecordOptions:
|
|
159
|
+
"""Options for Actor.set_value() / KeyValueStore.set_value()."""
|
|
160
|
+
content_type: Optional[str] = None
|
|
161
|
+
do_not_retry_timeouts: bool = False
|
|
162
|
+
timeout_secs: Optional[int] = None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class SetStatusMessageOptions:
|
|
167
|
+
"""Options for Actor.set_status_message()."""
|
|
168
|
+
is_status_message_terminal: bool = False
|
|
169
|
+
level: str = 'INFO' # 'DEBUG', 'INFO', 'WARNING', 'ERROR'
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class MetamorphOptions:
|
|
174
|
+
"""Options for Actor.metamorph()."""
|
|
175
|
+
build: Optional[str] = None
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@dataclass
|
|
179
|
+
class RebootOptions:
|
|
180
|
+
"""Options for Actor.reboot()."""
|
|
181
|
+
custom_after_sleep_millis: Optional[int] = None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@dataclass
|
|
185
|
+
class OpenStorageOptions:
|
|
186
|
+
"""Options for Actor.open_dataset(), open_key_value_store(), and open_request_queue()."""
|
|
187
|
+
force_cloud: bool = False
|
|
188
|
+
config: Optional[Any] = None
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass
|
|
192
|
+
class CallOptions:
|
|
193
|
+
"""Options for Actor.call() / Actor.call_task()."""
|
|
194
|
+
token: Optional[str] = None
|
|
195
|
+
build: Optional[str] = None
|
|
196
|
+
max_total_charge_usd: Optional[float] = None
|
|
197
|
+
restart_on_error: Optional[bool] = None
|
|
198
|
+
memory_mbytes: Optional[int] = None
|
|
199
|
+
timeout: Optional[Union[int, str]] = None # number or 'inherit'
|
|
200
|
+
force_permission_level: Optional[ActorPermissionLevel] = None
|
|
201
|
+
webhooks: Optional[List[WebhookOptions]] = None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass
|
|
205
|
+
class StartOptions:
|
|
206
|
+
"""Options for Actor.start()."""
|
|
207
|
+
token: Optional[str] = None
|
|
208
|
+
build: Optional[str] = None
|
|
209
|
+
max_total_charge_usd: Optional[float] = None
|
|
210
|
+
restart_on_error: Optional[bool] = None
|
|
211
|
+
memory_mbytes: Optional[int] = None
|
|
212
|
+
timeout: Optional[Union[int, str]] = None # number or 'inherit'
|
|
213
|
+
force_permission_level: Optional[ActorPermissionLevel] = None
|
|
214
|
+
webhooks: Optional[List[WebhookOptions]] = None
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@dataclass
|
|
218
|
+
class AbortOptions:
|
|
219
|
+
"""Options for Actor.abort()."""
|
|
220
|
+
token: Optional[str] = None
|
|
221
|
+
status_message: Optional[str] = None
|
|
222
|
+
gracefully: Optional[bool] = None
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@dataclass
|
|
226
|
+
class ActorRun:
|
|
227
|
+
"""Information about an Actor run."""
|
|
228
|
+
id: str
|
|
229
|
+
actor_id: str
|
|
230
|
+
status: str
|
|
231
|
+
started_at: Optional[datetime] = None
|
|
232
|
+
finished_at: Optional[datetime] = None
|
|
233
|
+
duration_millis: Optional[int] = None
|
|
234
|
+
build_id: Optional[str] = None
|
|
235
|
+
build_number: Optional[str] = None
|
|
236
|
+
default_dataset_id: Optional[str] = None
|
|
237
|
+
default_key_value_store_id: Optional[str] = None
|
|
238
|
+
default_request_queue_id: Optional[str] = None
|
|
239
|
+
exit_code: Optional[int] = None
|
|
240
|
+
status_message: Optional[str] = None
|
|
241
|
+
input: Optional[Dict[str, Any]] = None
|
|
242
|
+
output: Optional[Dict[str, Any]] = None
|
|
243
|
+
usage_total_usd: Optional[float] = None
|
|
244
|
+
usage: Optional[Dict[str, Any]] = None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@dataclass
|
|
248
|
+
class ProxyInfo:
|
|
249
|
+
"""Information about a proxy configuration.
|
|
250
|
+
|
|
251
|
+
Compatible with crawlee's ProxyInfo to support crawlee's _basic_crawler.py
|
|
252
|
+
which calls proxy_configuration.new_proxy_info(request=..., session=...).
|
|
253
|
+
"""
|
|
254
|
+
url: str
|
|
255
|
+
scheme: str # Required by crawlee
|
|
256
|
+
hostname: str
|
|
257
|
+
port: int
|
|
258
|
+
username: str = ''
|
|
259
|
+
password: str = ''
|
|
260
|
+
session_id: Optional[str] = None # Required by crawlee
|
|
261
|
+
proxy_tier: Optional[int] = None # Required by crawlee
|
|
262
|
+
groups: List[str] = field(default_factory=list)
|
|
263
|
+
country_code: Optional[str] = None
|
|
264
|
+
subdivision_code: Optional[str] = None
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# Type aliases
|
|
268
|
+
Dictionary = Dict[str, Any]
|
|
269
|
+
JsonValue = Union[None, bool, int, float, str, List['JsonValue'], Dict[str, 'JsonValue']]
|
scrapely/webhook.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Webhook types for the Scrapely Python SDK.
|
|
3
|
+
|
|
4
|
+
This module defines the Webhook class and related types for creating
|
|
5
|
+
ad-hoc webhooks on the Scrapely platform.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WebhookEventType(str, Enum):
|
|
16
|
+
"""Event types that can trigger a webhook."""
|
|
17
|
+
ACTOR_RUN_CREATED = 'ACTOR.RUN.CREATED'
|
|
18
|
+
ACTOR_RUN_SUCCEEDED = 'ACTOR.RUN.SUCCEEDED'
|
|
19
|
+
ACTOR_RUN_FAILED = 'ACTOR.RUN.FAILED'
|
|
20
|
+
ACTOR_RUN_ABORTED = 'ACTOR.RUN.ABORTED'
|
|
21
|
+
ACTOR_RUN_TIMED_OUT = 'ACTOR.RUN.TIMED_OUT'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Webhook:
|
|
26
|
+
"""An Apify webhook definition used by the Actor SDK.
|
|
27
|
+
|
|
28
|
+
The same instance can be passed as an ad-hoc webhook to Actor.start() / Actor.call(),
|
|
29
|
+
or to Actor.add_webhook(), which registers it as an ad-hoc webhook for the current run
|
|
30
|
+
(the condition.actor_run_id is set automatically).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
event_types: List[WebhookEventType]
|
|
34
|
+
request_url: str
|
|
35
|
+
payload_template: Optional[str] = None
|
|
36
|
+
headers_template: Optional[str] = None
|
|
37
|
+
idempotency_key: Optional[str] = None
|
|
38
|
+
do_not_retry: Optional[bool] = None
|
|
39
|
+
ignore_ssl_errors: Optional[bool] = None
|
|
40
|
+
# Server-assigned identifier, populated by Actor.add_webhook() / the API.
|
|
41
|
+
id: Optional[str] = None
|
|
42
|
+
|
|
43
|
+
def __post_init__(self) -> None:
|
|
44
|
+
"""Validate the webhook after initialization."""
|
|
45
|
+
if not self.event_types:
|
|
46
|
+
raise ValueError('At least one event type must be specified')
|
|
47
|
+
if not self.request_url:
|
|
48
|
+
raise ValueError('Request URL must be specified')
|
|
49
|
+
|
|
50
|
+
def to_dict(self, actor_run_id: Optional[str] = None) -> Dict[str, Any]:
|
|
51
|
+
"""Convert webhook to dictionary for API calls.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
actor_run_id: Optional run ID to bind the webhook to.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Dictionary representation for the API.
|
|
58
|
+
"""
|
|
59
|
+
result: Dict[str, Any] = {
|
|
60
|
+
'eventTypes': [e.value for e in self.event_types],
|
|
61
|
+
'requestUrl': self.request_url,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if self.payload_template:
|
|
65
|
+
result['payloadTemplate'] = self.payload_template
|
|
66
|
+
if self.headers_template:
|
|
67
|
+
result['headersTemplate'] = self.headers_template
|
|
68
|
+
if self.idempotency_key:
|
|
69
|
+
result['idempotencyKey'] = self.idempotency_key
|
|
70
|
+
if self.do_not_retry is not None:
|
|
71
|
+
result['doNotRetry'] = self.do_not_retry
|
|
72
|
+
if self.ignore_ssl_errors is not None:
|
|
73
|
+
result['ignoreSslErrors'] = self.ignore_ssl_errors
|
|
74
|
+
|
|
75
|
+
# Add condition for the current run
|
|
76
|
+
if actor_run_id:
|
|
77
|
+
result['condition'] = {'actorRunId': actor_run_id}
|
|
78
|
+
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
__all__ = ['Webhook', 'WebhookEventType']
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scrapely-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Scrapely Python SDK - A toolkit for building Actors on the Scrapely platform
|
|
5
|
+
Author-email: Scrapely <support@scrape.ly>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://scrape.ly
|
|
8
|
+
Project-URL: Documentation, https://docs.scrape.ly
|
|
9
|
+
Project-URL: Repository, https://github.com/SandeepDev1/scrapely
|
|
10
|
+
Keywords: scraping,actor,serverless,apify,scrapely
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: crawlee<2.0.0,>=1.8.0
|
|
24
|
+
Requires-Dist: websockets>=12.0
|
|
25
|
+
Requires-Dist: scrapely-client-python<2,>=1.0.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0.0
|
|
27
|
+
Requires-Dist: cryptography>=42.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: playwright>=1.40.0; extra == "dev"
|
|
35
|
+
Requires-Dist: browserforge>=1.2.0; extra == "dev"
|
|
36
|
+
|
|
37
|
+
# Scrapely Python SDK
|
|
38
|
+
|
|
39
|
+
Build Python Actors for the [Scrapely](https://scrape.ly) platform with lifecycle helpers, Crawlee-compatible storage, platform events, remote browser CDP, run control, webhooks, and pay-per-event accounting.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
Scrapely requires Python 3.9 or newer.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python -m pip install scrapely
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Install the appropriate Crawlee/Playwright browser dependencies separately when your Actor uses a browser.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import asyncio
|
|
55
|
+
|
|
56
|
+
from scrapely import Actor
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def main() -> None:
|
|
60
|
+
actor_input = await Actor.get_input_or_throw()
|
|
61
|
+
await Actor.push_data({
|
|
62
|
+
"url": actor_input["url"],
|
|
63
|
+
"status": "processed",
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
asyncio.run(Actor.main(main))
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`Actor.main()` initializes the Actor, awaits your callback, closes events and storage, and exits the process. For embedded applications and tests, use `async with Actor:` instead.
|
|
72
|
+
|
|
73
|
+
## Highlights
|
|
74
|
+
|
|
75
|
+
- Local file-system storage and Scrapely API-backed datasets, key-value stores, and request queues
|
|
76
|
+
- Crawlee request loaders and storage objects
|
|
77
|
+
- Platform event WebSocket integration and state persistence
|
|
78
|
+
- Automatic remote Chromium CDP wiring through `CDP_URL`
|
|
79
|
+
- Actor start, call, abort, reboot, and metamorph operations
|
|
80
|
+
- Ad-hoc webhooks, proxy configuration, and charging/pricing types
|
|
81
|
+
- Apify-compatible environment aliases and asynchronous client access
|
|
82
|
+
|
|
83
|
+
See the [complete Python SDK guide](../docs/sdk-python.md) for lifecycle details, option objects, storage selection, events, CDP behavior, run control, environment variables, errors, and the full public export list.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
scrapely/__init__.py,sha256=EqZTSyL6fkCFXkbp2iej7Umi6y_F19aC7MqxOaUbB68,5745
|
|
2
|
+
scrapely/_browser_locations.py,sha256=8QVVnkms2bDn3_LDYgYDR59MvFx8757l_JYnZ7xb3oI,145269
|
|
3
|
+
scrapely/actor.py,sha256=WzvD7gvCKRMyIN_Ei_I-MfIBL7Darn_B40GQJIgAn04,74960
|
|
4
|
+
scrapely/browser_configuration.py,sha256=jAZapNSHLFW05B96df4wNBtcyiiU9DA3ml0yTL1FwfA,5770
|
|
5
|
+
scrapely/charging.py,sha256=ckqsGbGuzpdw5PgEt6Apx3cwR46sA8V2WwUDSqSSfz8,46887
|
|
6
|
+
scrapely/charging_client.py,sha256=tDtlPwLSVFvoRa2NBgNjyfHkAUM77SSIyYT2ACgpDm8,3710
|
|
7
|
+
scrapely/configuration.py,sha256=YUnbft9JeWlVTgWalr-CgJCiyJ_e_rgoQItVPvjeWRs,15406
|
|
8
|
+
scrapely/errors.py,sha256=DCAlVvE3jToZuPEG2HVDL7i8D8hLboomQ5JpSOcsXoQ,4107
|
|
9
|
+
scrapely/log.py,sha256=iVKoQdMLQXEWz1STzbSXrNUxsS_FNwiIdqoEg7CzeqU,1440
|
|
10
|
+
scrapely/patch_browser_pool.py,sha256=sRAjuzKoOEgn0X8695c_9qioRALzkTWXoDlorVnK9jg,37426
|
|
11
|
+
scrapely/pricing_types.py,sha256=J6wCddZd-U1MYeOtaaEdeHSsp1HBgiQLfvSInBOvhIo,5305
|
|
12
|
+
scrapely/proxy_configuration.py,sha256=lvfOvuR8tOE9uiMOS_nw6TEj11xy7GYGa56iYvPwtmA,34654
|
|
13
|
+
scrapely/py.typed,sha256=XtWlywqUjc6x_M2gAXlDtYXbAsYkCjKZEjFyJvaHvm4,105
|
|
14
|
+
scrapely/types.py,sha256=ceVuHvhYbPai2CL3vFmXLTMoGaMR27IefJFgWhzd7ws,8900
|
|
15
|
+
scrapely/webhook.py,sha256=4WOM42ypOSOs4lKtP5ofxAh6lX-7c8p5U9lOfuFzx-g,2830
|
|
16
|
+
scrapely/crypto/__init__.py,sha256=MbMPs7Eq_fGSVjOZxNts_JckDCUtxCVqdkHU0VCfN4M,481
|
|
17
|
+
scrapely/crypto/_secrets.py,sha256=-ETpq1yCMaW-mheTGedFaQGGhu_pGT9_VMdJ3--V1rk,7614
|
|
18
|
+
scrapely/events/__init__.py,sha256=8vbbxxqkV0DrQicvFkwFwacUzi96XeW-b6KQzpUBuSM,1239
|
|
19
|
+
scrapely/events/_types.py,sha256=UHNP1dVVG0geJqhlhivQHK00nErYJ0gaQ-PxuGBujXo,5754
|
|
20
|
+
scrapely/events/event_manager.py,sha256=CiI-Fiw0vaKx1iGEiXRG9Df08WDgwFDOT-DX3IIHZJg,12521
|
|
21
|
+
scrapely/request_loaders/__init__.py,sha256=aNgr4pRt3MziUbU6UQ_bjTT3moMNvvyUsPeCJyMQcwU,196
|
|
22
|
+
scrapely/request_loaders/_scrapely_request_list.py,sha256=cq7xx7Ai4qOhcqGV2TLqPR3o53FPCPKpVxWEMw5qKaM,7367
|
|
23
|
+
scrapely/storage/__init__.py,sha256=diAhxEvOXjc3YVhZvzkO3MttJUXQWJ5ogxstiApsh7U,1405
|
|
24
|
+
scrapely/storage/_metadata.py,sha256=WWawBnVN0b1iK2K-SlxZXUc6czb5wXWf8iC_0tzkgAQ,4764
|
|
25
|
+
scrapely/storage/api_client.py,sha256=wrRxQ8h4jKdWY50HI0gXS-XHaFpzWPbVyLQ1nOYnsnA,11305
|
|
26
|
+
scrapely/storage/client.py,sha256=M3o_a_9azHNn6eL_UyEeVz-VQJvnT_th1HJPuCA4PkE,21746
|
|
27
|
+
scrapely/storage/patch_storage.py,sha256=o3Fv0BByeZ1T9HhkzhY6bjolOFsIQcnqBoHq1EdG8Fw,8758
|
|
28
|
+
scrapely/storage/scrapely_dataset_client.py,sha256=gRvlCDw9c0yO5GE5LQOa1xAyXc9pnb-E37Eq7fHqHCM,10338
|
|
29
|
+
scrapely/storage/scrapely_kvs_client.py,sha256=ItQhe2rcSl20NkSmegfqHiRyKncH4Qg9BjQVpF6jHfk,7403
|
|
30
|
+
scrapely/storage/scrapely_rq_client.py,sha256=0MoLZSIlzdqaQW_wypraVmHIsQimf_fV4-LCA_lLKJc,18601
|
|
31
|
+
scrapely/storage/scrapely_storage_client.py,sha256=N-p2ISICuKQ8RNzmN-JiXcj_lTttULLOGl9lpLl62qI,6567
|
|
32
|
+
scrapely/storage/smart_scrapely_storage_client.py,sha256=OipItBvlDz83_5ctQirdC8yRSv321d_nrZTqReTwmOU,4245
|
|
33
|
+
scrapely/storage/types.py,sha256=7eC9tL_eiEL2neaK_Ri1VZ0aolrvHlkhwgW9HZ94z64,20844
|
|
34
|
+
scrapely/storage/utils.py,sha256=ngFWCNM48Kx6tdsvR05Pl3iWgiNPwTL3YlEpeRBm57w,1425
|
|
35
|
+
scrapely/storage/_file_system/__init__.py,sha256=dSJ28uDrA--dz6e-vqk7MpE2nYOsXVjkzIlmGvoHTZ8,318
|
|
36
|
+
scrapely/storage/_file_system/_key_value_store_client.py,sha256=4Ipgbh4qEqAkwQJ9fXTujFR0Uu4nsw_7jvX6UkIk-Is,6094
|
|
37
|
+
scrapely/storage/_file_system/_storage_client.py,sha256=aaGJ4P0QAtIgEMl6yHpuobeWFD5M4rMC5HwhOOvuGuo,1794
|
|
38
|
+
scrapely/storage_clients/__init__.py,sha256=cs1YX7JV2_GKBXeiiJgkQFali08b5_y_jH6Yw7iROAA,656
|
|
39
|
+
scrapely/storages/__init__.py,sha256=4PAELhJNZ3exJ7Uouicn-bCQ58NafKjhLBixQ8ATQc4,173
|
|
40
|
+
scrapely_python-0.1.0.dist-info/METADATA,sha256=AbI8nacnK9KwHjwfREv7B3uBfSMnFQuFpyzwaU-33Ag,3137
|
|
41
|
+
scrapely_python-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
42
|
+
scrapely_python-0.1.0.dist-info/top_level.txt,sha256=T4B9UMrs4q99QSAFyD1zdXhl40KnLhBKqrDkPhOTsmY,9
|
|
43
|
+
scrapely_python-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
scrapely
|