scrapely-python 0.1.33__tar.gz → 0.1.34__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.33 → scrapely_python-0.1.34}/CHANGELOG.md +4 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/PKG-INFO +1 -1
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/pyproject.toml +1 -1
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/__init__.py +1 -1
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/actor.py +52 -2
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/PKG-INFO +1 -1
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/LICENSE +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/LICENSE-APACHE +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/MANIFEST.in +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/NOTICE +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/README.md +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/setup.cfg +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/_browser_locations.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/browser_configuration.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/cdp_retry.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/charging.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/charging_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/configuration.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/crypto/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/crypto/_secrets.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/errors.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/events/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/events/_types.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/events/event_manager.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/log.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/patch_browser_pool.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/pricing_types.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/proxy_configuration.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/py.typed +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/request_loaders/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/request_loaders/_scrapely_request_list.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/_actor_runner.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/_async_thread.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/_logging_config.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/_serialization.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/_warnings.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/_graceful_stop.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/_httpcache.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/middlewares/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/middlewares/apify_proxy.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/pipelines/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/pipelines/actor_dataset_push.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/requests.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/scheduler.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/utils.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/solver.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/_file_system/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/_file_system/_key_value_store_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/_file_system/_storage_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/_metadata.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/api_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/patch_storage.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_dataset_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_kvs_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_rq_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/smart_scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/types.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/utils.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage_clients/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storages/__init__.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/types.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/webhook.py +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/SOURCES.txt +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/dependency_links.txt +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/requires.txt +0 -0
- {scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/top_level.txt +0 -0
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.34] - 2026-10-23
|
|
6
|
+
|
|
7
|
+
- Debug captures (`Actor.debug_capture`, `Actor.debug_capture_sync`) store parsed XML/HTML elements as their markup instead of a repr such as `<Element 'change' at 0x...>`: `xml.etree.ElementTree` elements and trees, lxml elements and trees, BeautifulSoup tags, selectolax nodes and parsel / Scrapy selectors, passed alone or inside a dict or list. The text after an element (its tail) is not included. Other objects are still stored as their `str()`. Captures are only active on the platform's own diagnostic runs (`SCRAPELY_DEBUG_CAPTURE=1`).
|
|
8
|
+
|
|
5
9
|
## [0.1.33] - 2026-10-22
|
|
6
10
|
|
|
7
11
|
- Debug captures (`Actor.debug_capture`, `Actor.debug_capture_sync`) keep payloads over 256 KiB whole. They are stored gzip-compressed and base64-encoded as `{key, payload, encoding: 'gzip-base64', length, truncated}` instead of being cut at 262,144 characters; up to 8 Mi characters are kept. A payload that does not compress enough keeps its first 256 KiB, now marked `truncated: True` with its full `length`. Dict and list payloads are dumped as compact JSON, and `bytes` payloads are stored as UTF-8 text (they used to be stored as their `repr`). Captures are only active on the platform's own diagnostic runs (`SCRAPELY_DEBUG_CAPTURE=1`).
|
|
@@ -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.34"
|
|
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"
|
|
@@ -285,6 +285,53 @@ class _ActorMeta(type):
|
|
|
285
285
|
await cls._shutdown()
|
|
286
286
|
|
|
287
287
|
|
|
288
|
+
|
|
289
|
+
def _element_markup(obj: Any) -> Optional[str]:
|
|
290
|
+
"""The markup of a parsed XML/HTML element, or None when ``obj`` is not one.
|
|
291
|
+
|
|
292
|
+
Debug captures store the source an item was read from. Feed and page parsers hand over elements
|
|
293
|
+
(xml.etree / lxml elements and trees, BeautifulSoup tags, selectolax nodes, parsel / Scrapy
|
|
294
|
+
selectors); their ``str()`` is only a repr such as ``<Element 'change' at 0x...>``, which shows
|
|
295
|
+
nothing of the source. Optional parsers are recognised by module, never imported here.
|
|
296
|
+
"""
|
|
297
|
+
import xml.etree.ElementTree as ET
|
|
298
|
+
|
|
299
|
+
if isinstance(obj, ET.ElementTree):
|
|
300
|
+
root = obj.getroot()
|
|
301
|
+
return ET.tostring(root, encoding='unicode') if root is not None else ''
|
|
302
|
+
if isinstance(obj, ET.Element):
|
|
303
|
+
if obj.tail: # the text after the element belongs to its parent, as with lxml's with_tail=False
|
|
304
|
+
import copy
|
|
305
|
+
|
|
306
|
+
obj = copy.copy(obj)
|
|
307
|
+
obj.tail = None
|
|
308
|
+
return ET.tostring(obj, encoding='unicode')
|
|
309
|
+
modules = [getattr(c, '__module__', '') or '' for c in type(obj).__mro__]
|
|
310
|
+
if any(m == 'lxml' or m.startswith('lxml.') for m in modules):
|
|
311
|
+
from lxml import etree # type: ignore[import-not-found]
|
|
312
|
+
|
|
313
|
+
out = etree.tostring(obj, encoding='unicode', with_tail=False)
|
|
314
|
+
return out if isinstance(out, str) else None
|
|
315
|
+
if any(m == 'bs4' or m.startswith('bs4.') for m in modules):
|
|
316
|
+
return str(obj)
|
|
317
|
+
if any(m == 'selectolax' or m.startswith('selectolax.') for m in modules):
|
|
318
|
+
html = getattr(obj, 'html', None)
|
|
319
|
+
return html if isinstance(html, str) else None
|
|
320
|
+
if any(m == 'parsel' or m.startswith('parsel.') for m in modules) and callable(getattr(obj, 'get', None)):
|
|
321
|
+
out = obj.get()
|
|
322
|
+
return out if isinstance(out, str) else None
|
|
323
|
+
return None
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _capture_json_default(obj: Any) -> Any:
|
|
327
|
+
"""json.dumps fallback for debug captures: elements as their markup, anything else as str()."""
|
|
328
|
+
try:
|
|
329
|
+
markup = _element_markup(obj)
|
|
330
|
+
except Exception: # an unusual node type must not lose the rest of the payload
|
|
331
|
+
markup = None
|
|
332
|
+
return markup if markup is not None else str(obj)
|
|
333
|
+
|
|
334
|
+
|
|
288
335
|
class Actor(metaclass=_ActorMeta):
|
|
289
336
|
"""Core class for building Actors on the Scrapely platform."""
|
|
290
337
|
|
|
@@ -974,12 +1021,15 @@ class Actor(metaclass=_ActorMeta):
|
|
|
974
1021
|
if cls._debug_capture_count >= cls._DEBUG_CAPTURE_MAX_RECORDS:
|
|
975
1022
|
return
|
|
976
1023
|
try:
|
|
977
|
-
|
|
1024
|
+
markup = _element_markup(payload)
|
|
1025
|
+
if markup is not None:
|
|
1026
|
+
text = markup
|
|
1027
|
+
elif isinstance(payload, (bytes, bytearray)):
|
|
978
1028
|
text = bytes(payload).decode('utf-8', 'replace')
|
|
979
1029
|
elif isinstance(payload, str):
|
|
980
1030
|
text = payload
|
|
981
1031
|
else:
|
|
982
|
-
text = json.dumps(payload, default=
|
|
1032
|
+
text = json.dumps(payload, default=_capture_json_default, ensure_ascii=False, separators=(',', ':'))
|
|
983
1033
|
record = cls._debug_capture_record(str(key), text)
|
|
984
1034
|
cls._debug_capture_count += 1
|
|
985
1035
|
await cls.set_value(cls.debug_capture_record_key(key), record)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/__init__.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/_graceful_stop.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/extensions/_httpcache.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/middlewares/__init__.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/scrapy/middlewares/apify_proxy.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.33 → scrapely_python-0.1.34}/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.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_dataset_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_kvs_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely/storage/scrapely_rq_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/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
|
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.33 → scrapely_python-0.1.34}/src/scrapely_python.egg-info/top_level.txt
RENAMED
|
File without changes
|