scrapely-python 0.1.23__tar.gz → 0.1.24__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.
- {scrapely_python-0.1.23/src/scrapely_python.egg-info → scrapely_python-0.1.24}/PKG-INFO +1 -1
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/pyproject.toml +1 -1
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/__init__.py +1 -1
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/actor.py +30 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/proxy_configuration.py +2 -2
- {scrapely_python-0.1.23 → scrapely_python-0.1.24/src/scrapely_python.egg-info}/PKG-INFO +1 -1
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/SOURCES.txt +1 -0
- scrapely_python-0.1.24/tests/test_debug_capture.py +31 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/LICENSE +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/LICENSE-APACHE +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/NOTICE +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/README.md +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/setup.cfg +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/_browser_locations.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/browser_configuration.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/cdp_retry.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/charging.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/charging_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/configuration.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/crypto/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/crypto/_secrets.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/errors.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/events/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/events/_types.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/events/event_manager.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/log.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/patch_browser_pool.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/pricing_types.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/py.typed +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/request_loaders/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/request_loaders/_scrapely_request_list.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/solver.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/_file_system/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/_file_system/_key_value_store_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/_file_system/_storage_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/_metadata.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/api_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/patch_storage.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_dataset_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_kvs_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_rq_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/smart_scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/types.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/utils.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage_clients/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storages/__init__.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/types.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/webhook.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/dependency_links.txt +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/requires.txt +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/top_level.txt +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_api_client_retries.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_apify_parity.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_browser_configuration.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_cdp_retry.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_charge_limit_guard.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_charge_retries.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_charging_parity.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_charging_pending.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_input_proxy_aliases.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_lazy_crawlee.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_parity.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_patch_browser_pool.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_proxy_configuration.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_push_idempotency.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_run_control.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_secrets.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_solver.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_storage.py +0 -0
- {scrapely_python-0.1.23 → scrapely_python-0.1.24}/tests/test_terminal_status_message.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scrapely-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.24"
|
|
8
8
|
description = "Scrapely Python SDK - A toolkit for building Actors on the Scrapely platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT AND Apache-2.0"
|
|
@@ -922,6 +922,36 @@ class Actor(metaclass=_ActorMeta):
|
|
|
922
922
|
cls._default_kvs = await cls.open_key_value_store()
|
|
923
923
|
await cls._default_kvs.set_value(key, value, content_type=content_type)
|
|
924
924
|
|
|
925
|
+
# Debug capture: raw source payloads for platform diagnostics. Only active when the platform
|
|
926
|
+
# sets SCRAPELY_DEBUG_CAPTURE=1 on its own diagnostic runs; a no-op in every other run.
|
|
927
|
+
_DEBUG_CAPTURE_MAX_BYTES = 256 * 1024
|
|
928
|
+
_DEBUG_CAPTURE_MAX_RECORDS = 500
|
|
929
|
+
_debug_capture_count = 0
|
|
930
|
+
|
|
931
|
+
@staticmethod
|
|
932
|
+
def debug_capture_record_key(key: str) -> str:
|
|
933
|
+
"""The key-value store record name for a capture key (item URL or id)."""
|
|
934
|
+
import hashlib
|
|
935
|
+
return 'DEBUG_CAPTURE_' + hashlib.sha1(str(key).strip().encode('utf-8')).hexdigest()[:24]
|
|
936
|
+
|
|
937
|
+
@classmethod
|
|
938
|
+
async def debug_capture(cls, key: str, payload: Any) -> None:
|
|
939
|
+
"""Save the raw source payload (API JSON or HTML) an item was extracted from, keyed by
|
|
940
|
+
the item's URL or id. Does nothing unless the platform enabled capture for this run."""
|
|
941
|
+
if os.environ.get('SCRAPELY_DEBUG_CAPTURE') != '1' or not key:
|
|
942
|
+
return
|
|
943
|
+
if cls._debug_capture_count >= cls._DEBUG_CAPTURE_MAX_RECORDS:
|
|
944
|
+
return
|
|
945
|
+
try:
|
|
946
|
+
text = payload if isinstance(payload, str) else json.dumps(payload, default=str, ensure_ascii=False)
|
|
947
|
+
if isinstance(text, bytes):
|
|
948
|
+
text = text.decode('utf-8', 'replace')
|
|
949
|
+
text = text[: cls._DEBUG_CAPTURE_MAX_BYTES]
|
|
950
|
+
cls._debug_capture_count += 1
|
|
951
|
+
await cls.set_value(cls.debug_capture_record_key(key), {'key': str(key), 'payload': text})
|
|
952
|
+
except Exception as err: # never break the run
|
|
953
|
+
logging.getLogger('scrapely').debug('debug_capture failed: %s', err)
|
|
954
|
+
|
|
925
955
|
@classmethod
|
|
926
956
|
def _resolve_open_args(
|
|
927
957
|
cls,
|
|
@@ -203,7 +203,7 @@ def _platform_missing_error() -> str:
|
|
|
203
203
|
'proxy credentials (SCRAPELY_PROXY_*/APIFY_PROXY_*) were injected into this '
|
|
204
204
|
'environment. Run the actor on Scrapely with proxy access enabled, or remove the '
|
|
205
205
|
'platform proxy entries. To use the platform proxy locally or from outside '
|
|
206
|
-
'Scrapely, copy your proxy credentials from the Scrapely
|
|
206
|
+
'Scrapely, copy your proxy credentials from the Scrapely dashboard (Proxy page) '
|
|
207
207
|
'into the SCRAPELY_PROXY_HOSTNAME, SCRAPELY_PROXY_PORT, SCRAPELY_PROXY_USERNAME '
|
|
208
208
|
'and SCRAPELY_PROXY_PASSWORD environment variables (or pass password=... '
|
|
209
209
|
'explicitly). External platform proxy access requires an active plan or a '
|
|
@@ -431,7 +431,7 @@ class ProxyConfiguration:
|
|
|
431
431
|
logger.warning(
|
|
432
432
|
'The Scrapely platform proxy is only available in on-platform runs when your '
|
|
433
433
|
'account has proxy access. Locally, either add proxy_urls to your actor input, '
|
|
434
|
-
'or copy your proxy credentials from the Scrapely
|
|
434
|
+
'or copy your proxy credentials from the Scrapely dashboard (Proxy page) into the '
|
|
435
435
|
'SCRAPELY_PROXY_HOSTNAME, SCRAPELY_PROXY_PORT, SCRAPELY_PROXY_USERNAME and '
|
|
436
436
|
'SCRAPELY_PROXY_PASSWORD environment variables. Using the platform proxy from '
|
|
437
437
|
'outside Scrapely requires an active plan or a prepaid (PAYG) balance of at '
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from scrapely.actor import Actor
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_debug_capture_noop_without_flag(monkeypatch):
|
|
7
|
+
monkeypatch.delenv('SCRAPELY_DEBUG_CAPTURE', raising=False)
|
|
8
|
+
calls = []
|
|
9
|
+
|
|
10
|
+
async def fake_set_value(key, value, content_type=None):
|
|
11
|
+
calls.append(key)
|
|
12
|
+
|
|
13
|
+
monkeypatch.setattr(Actor, 'set_value', fake_set_value)
|
|
14
|
+
asyncio.run(Actor.debug_capture('https://x/item/1', {'a': 1}))
|
|
15
|
+
assert calls == []
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_debug_capture_writes_keyed_capped_record(monkeypatch):
|
|
19
|
+
monkeypatch.setenv('SCRAPELY_DEBUG_CAPTURE', '1')
|
|
20
|
+
saved = {}
|
|
21
|
+
|
|
22
|
+
async def fake_set_value(key, value, content_type=None):
|
|
23
|
+
saved[key] = value
|
|
24
|
+
|
|
25
|
+
monkeypatch.setattr(Actor, 'set_value', fake_set_value)
|
|
26
|
+
monkeypatch.setattr(Actor, '_debug_capture_count', 0)
|
|
27
|
+
asyncio.run(Actor.debug_capture('https://x/item/1', 'x' * (Actor._DEBUG_CAPTURE_MAX_BYTES + 10)))
|
|
28
|
+
key = Actor.debug_capture_record_key('https://x/item/1')
|
|
29
|
+
assert key.startswith('DEBUG_CAPTURE_') and len(key) == len('DEBUG_CAPTURE_') + 24
|
|
30
|
+
assert saved[key]['key'] == 'https://x/item/1'
|
|
31
|
+
assert len(saved[key]['payload']) == Actor._DEBUG_CAPTURE_MAX_BYTES
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/_file_system/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_dataset_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_kvs_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_rq_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely/storage/scrapely_storage_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.23 → scrapely_python-0.1.24}/src/scrapely_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|