Commit Graph

1442 Commits

Author SHA1 Message Date
Karim shoair 5ec929435b style: Fix all mypy errors and add type hints to untyped function bodies
**Resolved all 65 mypy errors across 14 files and added type annotations to all previously untyped function bodies. Final result: 0 errors with --check-untyped-defs enabled, all 454 tests pass.**

`scrapling/core/_types.py`

  - Removed broken Self = object fallback — now requires typing_extensions for Python < 3.11

`scrapling/core/storage.py`

  - Fixed str/bytes mismatch in _get_hash() — used separate _identifier_bytes variable instead of reassigning from str to bytes

`scrapling/core/custom_types.py`

  - split() return type: Union[List, "TextHandlers"] → list[Any] (avoids LSP violation with parent list[str])
  - format() kwargs: **kwargs: str → **kwargs: object (matches parent str.format signature)
  - AttributesHandler.__init__: Added mapping: Any = None, **kwargs: Any and -> None
  - json_string property: Added -> bytes return type

`scrapling/core/mixins.py`

  - Changed self: "Selector" to self: Any on all mixin methods (mypy can't handle forward-reference self types on non-subclass mixins)
  - Added Dict[str, int] annotation for counter variable
  - Removed unused TYPE_CHECKING / Selector imports

`scrapling/parser.py (~30 errors)`

  - Added body: str | bytes pre-annotation for dual-type if/elif assignment
  - Used Dict[str, Any] kwargs dict for HTMLParser(...) to bypass incomplete lxml stubs missing default_doctype
  - Changed base_url=url or None → base_url=url or "" (avoids str | None vs str | bytes)
  - bool(adaptive) to guarantee bool type for __adaptive_enabled
  - Declared __text: Optional[TextHandler], __tag: Optional[str], __attributes: Optional[AttributesHandler] at top of __init__
  - cast(List, ...) for all XPath() call results (_find_all_elements, _find_all_elements_with_spaces)
  - Added Dict[float, List[Any]] for score_table, Dict[str, Any] for attributes
  - Changed score, checks = 0, 0 → score: float = 0; checks: int = 0 (two locations)
  - Renamed target → target_element in save() to avoid variable redefinition with different types
  - Wrapped node_text.clean() / .lower() in TextHandler(...) to preserve type

`scrapling/engines/_browsers/_page.py`

  - Added PageInfo[SyncPage] | PageInfo[AsyncPage] union type annotation to page_info variable

`scrapling/engines/_browsers/_validators.py`

  - Convert method_kwargs (TypedDict) to plain Dict[str, Any] before dynamic key access

`scrapling/engines/_browsers/_base.py`

  - Added _config declaration to BaseSessionMixin
  - Used cast(StealthConfig, self._config) in __generate_stealth_options to access stealth-only attributes
  - Added Tuple[str, ...] annotation for flags
  - Removed redundant narrower StealthConfig type annotation on self._config in StealthySessionMixin.__validate__
  - Widened SyncSession and AsyncSession fields (playwright, context, browser) to Any to support both playwright and patchright types
  - Added -> None to both start() methods

`scrapling/engines/_browsers/_stealth.py`

  - Added Optional, ProxyType imports
  - Annotated proxy: Optional[ProxyType] in both sync/async fetch loops
  - Annotated outer_box: Any at first declaration, removed duplicate type annotations in subsequent branches
  - Added -> None to sync and async start()
  - Added config: Any parameter type to _initialize_context
  - Removed redundant self.context: AsyncBrowserContext re-annotations in conditional branches

`scrapling/engines/_browsers/_controllers.py`

  - Added Optional, ProxyType imports
  - Annotated proxy: Optional[ProxyType] in both sync/async fetch loops
  - Added -> None to async start()
  - Removed redundant self.context: AsyncBrowserContext re-annotations

`scrapling/spiders/request.py`

  - Added Optional import, typed _fp: Optional[bytes] = None
  - Removed redundant body: bytes re-annotation

`scrapling/spiders/session.py`

  - Used separate client variable instead of reassigning session = session._client (avoids type incompatibility and fixes a bug where session._make_request was called instead of client._make_request)
  - Added -> None to SessionManager.__init__

`scrapling/engines/toolbelt/convertor.py`

  - Added list[Response] annotation for history in both sync/async methods

`scrapling/engines/static.py`

  - FetcherClient.__init__ and AsyncFetcherClient.__init__: Added **kwargs: Any and -> None

`scrapling/core/shell.py`

  - Wrapped re_sub(...) result in TextHandler(...) to maintain correct type
  - Added -> None to CurlParser.__init__
  - Added full type signature to create_wrapper, replaced wrapper.__signature__ = ... with setattr(wrapper, "__signature__", ...) to satisfy mypy
  - Added Callable to imports
2026-02-07 16:30:00 +02:00
Karim shoair 5f557a7f9f test: add tests for the new feature 2026-02-07 01:28:58 +02:00
Karim shoair 66476d42be feat(browsers): Add option to block requests to specific domains 2026-02-07 01:26:21 +02:00
Karim shoair d00c34ee7f style(parser): Improve the type hint for find_by_text and find_by_regex 2026-02-06 03:19:00 +02:00
Karim shoair 05f62fba81 fix(response): Force the body of the response to always be bytes 2026-02-06 03:14:23 +02:00
Karim shoair 9acc8194c5 test: update the tests accordingly 2026-02-06 02:45:13 +02:00
Karim shoair aa7a95fb70 feat(parser)!: Make all selection return selector objects by default
- The strings/Texthandlers are only returned by `get`/`getall`/`extract`/`extract_first`. This makes the type checking/autocompletion experience consistent.
- Removed `css_first` and `xpath_first` since it doesn't make sense to leave them now.
- Made the type hints more accurate in multiple places.
2026-02-06 02:43:51 +02:00
Karim shoair d8fe909c8b docs: make translation urls absolute
For PyPI, Docker, and other external websites featuring this
2026-02-05 02:44:12 +02:00
Karim shoair 151e4e7a7c docs: adding new sponsor 2026-02-05 02:39:51 +02:00
Karim shoair f88502718f feat(proxy control): Force a proxy at request level at any given point
And merge request's meta with response's meta
2026-02-02 14:26:52 +02:00
Karim shoair 6e0277f23b test: add new tests for the proxy rotation logic 2026-02-02 00:16:40 +02:00
Karim shoair ef8c5bc7d6 feat(spiders/fetchers): Adding proxy rotation logic and change retry logic
- User passes a single proxy to the browser session, and it will keep using the same context. Pass a proxy manager that automatically refreshes the IP with each proxy, and you get speed but sacrifice some stealth.

- User imports the proxy rotator class and passes proxies to it and a rotation strategy (Round robin by default). Then pass the instance to the session class, which will create a context and a tab for each proxy returned by the rotator. This way, you sacrifice speed a bit, but you get maximum stealth since each context is created with the proxy that will be used.

- Normal requests use what you pass without issues, of course.

- All errors are retried now, and proxies are rotated on retries automatically.
2026-02-02 00:16:22 +02:00
Karim shoair 65f1a23358 fix(browsers): Improve stealth and speed by adjusting flags 2026-01-29 00:58:04 +02:00
Karim shoair 0c3d359b46 fix(browsers): disable autoplay for all browsers 2026-01-29 00:57:30 +02:00
Karim shoair 90c52c45c7 feat(parser): replacing tldextract with tld library
This might break the adaptive data users have for websites BUT:
1. tld uses ~3.7x less memory during extraction operations (1.5 MB vs 5.7 MB).
2. tld uses ~56% less memory on import (5.2 MB vs 11.9 MB).
3. Zero dependencies (vs 3 for tldextract).

In return, it's 30ms slower for extracting 5000 URLs, which is negligible. Also, the type hints aren't always accurate, but it's fine; I corrected them.
2026-01-23 00:00:48 +02:00
Karim shoair 5dbbd84b3d fix(requests): return the cached fingerprint on second call 2026-01-20 20:28:13 +02:00
Karim shoair d90189e675 test: update tests accordingly 2026-01-20 20:22:47 +02:00
Karim shoair 122923c80e feat(spiders/requests): Use a reliable method for fingerprint generation 2026-01-20 20:21:42 +02:00
Karim shoair 5aa178a76e style: update post requests type hints to be more accurate 2026-01-20 18:27:52 +02:00
Karim shoair d0f52c3855 test: remove the tests for the removed html_utils module 2026-01-20 16:37:17 +02:00
Karim shoair 95955af3be build: Add w3lib to deps 2026-01-20 16:36:34 +02:00
Karim shoair 0ec78e2335 test: update tests accordingly 2026-01-19 16:40:18 +02:00
Karim shoair 6947066761 feat(spiders): Make graceful shutdown always enabled 2026-01-19 16:40:02 +02:00
Karim shoair 94bc759c6a test: updates tests to include new logic 2026-01-19 16:13:29 +02:00
Karim shoair 25850db92c fix(spiders): handle errors with manual pause during stream mode 2026-01-19 16:13:03 +02:00
Karim shoair fbc8be5bcc fix(spiders): fix a bug with session stats counter 2026-01-19 16:00:06 +02:00
Karim shoair 4ecf8a64d3 fix(spiders): Fix for when the pausing system has large queue 2026-01-19 15:04:40 +02:00
Karim shoair cf0de7ea6d Merge branch 'main' into v4 2026-01-19 14:47:59 +02:00
Karim shoair 9229cef895 docs: adding new sponsor 2026-01-19 14:12:32 +02:00
Karim shoair d247b5b691 test: add tests for the spiders system
It's generated by Opus on Claude Code. It's very good as per my review and instructions, but I will have another look later.
2026-01-19 03:46:00 +02:00
Karim shoair 0d003f62e3 ops: update bandit checklist 2026-01-19 03:45:39 +02:00
Karim shoair 1f0f86e3a2 feat(spiders): Add pause/resume system for crawls 2026-01-19 03:43:10 +02:00
Karim shoair acdb39988c ops: update bandit checklist 2026-01-19 03:40:57 +02:00
Karim shoair bf5aa021d4 fix(browsers): solving an issues with leaving playwright loop open when cdp connection fails
This has been causing issues with tests for a long time, and now finally found the reason.
2026-01-18 16:46:48 +02:00
Karim shoair 02c9dffc77 style(spiders): make parse function abstract 2026-01-18 00:01:04 +02:00
Karim shoair afe6b2e97b feat(spiders): Change items hook to make it for processing items + add a stat for this 2026-01-17 20:52:49 +02:00
Karim shoair 41c7a7e793 fix(spiders engine): Improve logging 2026-01-17 19:57:04 +02:00
Karim shoair dac854a129 fix(parser): handle responses with empty body
It makes root's value None
2026-01-13 02:35:26 +02:00
Karim shoair 35d570120a feat(spiders): Add option to logging format and date format 2026-01-12 17:11:52 +02:00
Karim shoair 3466bcab2c feat: add hook to run after collecting an item 2026-01-12 15:58:33 +02:00
Karim shoair e0f94cf7d0 feat(spiders): Add a stream mode to collect items in realtime 2026-01-12 15:53:29 +02:00
Karim shoair 927cfd85ff feat(spiders): The option to start sessions lazily 2026-01-12 02:09:50 +02:00
Karim shoair f2c6216968 style: remove unwanted import from spiders main init file 2026-01-12 01:21:26 +02:00
Karim shoair 72c3c2792a feat(spiders): add simple export system for the results 2026-01-12 01:21:05 +02:00
Karim shoair a17bb1d976 feat(browsers): Add option to retry tabs that gives errors 2026-01-11 23:40:26 +02:00
Karim shoair 5a11c2466b fix: make retry_blocked_request take the response as well 2026-01-11 22:54:17 +02:00
Karim shoair 736873a7c6 feat(spiders): Add logic to detect blocked requests and retry them 2026-01-11 21:56:57 +02:00
Karim shoair 774364b6d3 style(spiders): make the usage of uvloop optional 2026-01-11 19:57:03 +02:00
Karim shoair 0bfdab7158 feat: spiders use uvloop/winloop when available 2026-01-11 18:39:42 +02:00
Karim shoair d5b9ed11b2 fix(browsers): Close pages that give error
This was causing the browser and the whole code to stand still.
2026-01-11 18:34:13 +02:00