refactor(api)!: Unifying log under 1 logger and removing debug parameter

So now you control the logging and the debugging from the shell through the logger with the name 'scrapling'
This commit is contained in:
Karim shoair
2024-12-11 21:41:37 +02:00
parent f30eb6ab6c
commit 193827e27b
16 changed files with 81 additions and 92 deletions
+2 -3
View File
@@ -1,10 +1,9 @@
import logging
from camoufox import DefaultAddons
from camoufox.sync_api import Camoufox
from scrapling.core._types import (Callable, Dict, List, Literal, Optional,
Union)
from scrapling.core.utils import log
from scrapling.engines.toolbelt import (Response, StatusText,
check_type_validity,
construct_proxy_dict, do_nothing,
@@ -63,7 +62,7 @@ class CamoufoxEngine:
self.page_action = page_action
else:
self.page_action = do_nothing
logging.error('[Ignored] Argument "page_action" must be callable')
log.error('[Ignored] Argument "page_action" must be callable')
self.wait_selector = wait_selector
self.wait_selector_state = wait_selector_state
+2 -2
View File
@@ -1,7 +1,7 @@
import json
import logging
from scrapling.core._types import Callable, Dict, List, Optional, Union
from scrapling.core.utils import log
from scrapling.engines.constants import (DEFAULT_STEALTH_FLAGS,
NSTBROWSER_DEFAULT_QUERY)
from scrapling.engines.toolbelt import (Response, StatusText,
@@ -78,7 +78,7 @@ class PlaywrightEngine:
self.page_action = page_action
else:
self.page_action = do_nothing
logging.error('[Ignored] Argument "page_action" must be callable')
log.error('[Ignored] Argument "page_action" must be callable')
self.wait_selector = wait_selector
self.wait_selector_state = wait_selector_state
-3
View File
@@ -1,5 +1,3 @@
import logging
import httpx
from httpx._models import Response as httpxResponse
@@ -36,7 +34,6 @@ class StaticEngine:
# Validate headers
if not headers.get('user-agent') and not headers.get('User-Agent'):
headers['User-Agent'] = generate_headers(browser_mode=False).get('User-Agent')
logging.info(f"Can't find useragent in headers so '{headers['User-Agent']}' was used.")
if stealth:
extra_headers = generate_headers(browser_mode=False)
+10 -15
View File
@@ -2,13 +2,12 @@
Functions related to custom types or type checking
"""
import inspect
import logging
from email.message import Message
from scrapling.core._types import (Any, Callable, Dict, List, Optional, Tuple,
Type, Union)
from scrapling.core.custom_types import MappingProxyType
from scrapling.core.utils import cache, setup_basic_logging
from scrapling.core.utils import log, lru_cache
from scrapling.parser import Adaptor, SQLiteStorageSystem
@@ -17,7 +16,7 @@ class ResponseEncoding:
__ISO_8859_1_CONTENT_TYPES = {"text/plain", "text/html", "text/css", "text/javascript"}
@classmethod
@cache(maxsize=None)
@lru_cache(maxsize=None)
def __parse_content_type(cls, header_value: str) -> Tuple[str, Dict[str, str]]:
"""Parse content type and parameters from a content-type header value.
@@ -39,7 +38,7 @@ class ResponseEncoding:
return content_type, params
@classmethod
@cache(maxsize=None)
@lru_cache(maxsize=None)
def get_value(cls, content_type: Optional[str], text: Optional[str] = 'test') -> str:
"""Determine the appropriate character encoding from a content-type header.
@@ -98,7 +97,7 @@ class Response(Adaptor):
# For back-ward compatibility
self.adaptor = self
# For easier debugging while working from a Python shell
logging.info(f'Fetched ({status}) <{method} {url}> (referer: {request_headers.get("referer")})')
log.info(f'Fetched ({status}) <{method} {url}> (referer: {request_headers.get("referer")})')
# def __repr__(self):
# return f'<{self.__class__.__name__} [{self.status} {self.reason}]>'
@@ -107,7 +106,7 @@ class Response(Adaptor):
class BaseFetcher:
def __init__(
self, huge_tree: bool = True, keep_comments: Optional[bool] = False, auto_match: Optional[bool] = True,
storage: Any = SQLiteStorageSystem, storage_args: Optional[Dict] = None, debug: Optional[bool] = False,
storage: Any = SQLiteStorageSystem, storage_args: Optional[Dict] = None,
automatch_domain: Optional[str] = None, keep_cdata: Optional[bool] = False,
):
"""Arguments below are the same from the Adaptor class so you can pass them directly, the rest of Adaptor's arguments
@@ -124,7 +123,6 @@ class BaseFetcher:
If empty, default values will be used.
:param automatch_domain: For cases where you want to automatch selectors across different websites as if they were on the same website, use this argument to unify them.
Otherwise, the domain of the request is used by default.
:param debug: Enable debug mode
"""
# Adaptor class parameters
# I won't validate Adaptor's class parameters here again, I will leave it to be validated later
@@ -134,14 +132,11 @@ class BaseFetcher:
keep_cdata=keep_cdata,
auto_match=auto_match,
storage=storage,
storage_args=storage_args,
debug=debug,
storage_args=storage_args
)
# If the user used fetchers first, then configure the logger from here instead of the `Adaptor` class
setup_basic_logging(level='debug' if debug else 'info')
if automatch_domain:
if type(automatch_domain) is not str:
logging.warning('[Ignored] The argument "automatch_domain" must be of string type')
log.warning('[Ignored] The argument "automatch_domain" must be of string type')
else:
self.adaptor_arguments.update({'automatch_domain': automatch_domain})
@@ -217,7 +212,7 @@ class StatusText:
})
@classmethod
@cache(maxsize=128)
@lru_cache(maxsize=128)
def get(cls, status_code: int) -> str:
"""Get the phrase for a given HTTP status code."""
return cls._phrases.get(status_code, "Unknown Status Code")
@@ -284,7 +279,7 @@ def check_type_validity(variable: Any, valid_types: Union[List[Type], None], def
error_msg = f'Argument "{var_name}" cannot be None'
if critical:
raise TypeError(error_msg)
logging.error(f'[Ignored] {error_msg}')
log.error(f'[Ignored] {error_msg}')
return default_value
# If no valid_types specified and variable has a value, return it
@@ -297,7 +292,7 @@ def check_type_validity(variable: Any, valid_types: Union[List[Type], None], def
error_msg = f'Argument "{var_name}" must be of type {" or ".join(type_names)}'
if critical:
raise TypeError(error_msg)
logging.error(f'[Ignored] {error_msg}')
log.error(f'[Ignored] {error_msg}')
return default_value
return variable
+3 -3
View File
@@ -9,10 +9,10 @@ from browserforge.headers import Browser, HeaderGenerator
from tldextract import extract
from scrapling.core._types import Dict, Union
from scrapling.core.utils import cache
from scrapling.core.utils import lru_cache
@cache(None, typed=True)
@lru_cache(None, typed=True)
def generate_convincing_referer(url: str) -> str:
"""Takes the domain from the URL without the subdomain/suffix and make it look like you were searching google for this website
@@ -26,7 +26,7 @@ def generate_convincing_referer(url: str) -> str:
return f'https://www.google.com/search?q={website_name}'
@cache(None, typed=True)
@lru_cache(None, typed=True)
def get_os_name() -> Union[str, None]:
"""Get the current OS name in the same format needed for browserforge
+3 -5
View File
@@ -1,15 +1,13 @@
"""
Functions related to files and URLs
"""
import logging
import os
from urllib.parse import urlencode, urlparse
from playwright.sync_api import Route
from scrapling.core._types import Dict, Optional, Union
from scrapling.core.utils import cache
from scrapling.core.utils import log, lru_cache
from scrapling.engines.constants import DEFAULT_DISABLED_RESOURCES
@@ -20,7 +18,7 @@ def intercept_route(route: Route) -> Union[Route, None]:
:return: PlayWright `Route` object
"""
if route.request.resource_type in DEFAULT_DISABLED_RESOURCES:
logging.debug(f'Blocking background resource "{route.request.url}" of type "{route.request.resource_type}"')
log.debug(f'Blocking background resource "{route.request.url}" of type "{route.request.resource_type}"')
return route.abort()
return route.continue_()
@@ -97,7 +95,7 @@ def construct_cdp_url(cdp_url: str, query_params: Optional[Dict] = None) -> str:
raise ValueError(f"Invalid CDP URL: {str(e)}")
@cache(None, typed=True)
@lru_cache(None, typed=True)
def js_bypass_path(filename: str) -> str:
"""Takes the base filename of JS file inside the `bypasses` folder then return the full path of it