refactor: replace's Selector inpt (text/body) with 1 argument called content

This commit is contained in:
Karim shoair
2025-07-29 06:08:15 +03:00
parent 9e9ba9ab10
commit b9c7a5af2e
5 changed files with 30 additions and 42 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ def test_scrapling():
@benchmark
def test_parsel():
return Selector(text=large_html).css(".item::text").extract()
return Selector(content=large_html).css(".item::text").extract()
@benchmark
+5 -10
View File
@@ -34,8 +34,7 @@ class ResponseFactory:
Response(
url=current_request.url,
# using current_response.text() will trigger "Error: Response.text: Response body is unavailable for redirect responses"
text="",
body=b"",
content="",
status=current_response.status if current_response else 301,
reason=(
current_response.status_text
@@ -112,8 +111,7 @@ class ResponseFactory:
return Response(
url=page.url,
text=page_content,
body=page_content.encode("utf-8"),
content=page_content,
status=final_response.status,
reason=status_text,
encoding=encoding,
@@ -141,8 +139,7 @@ class ResponseFactory:
Response(
url=current_request.url,
# using current_response.text() will trigger "Error: Response.text: Response body is unavailable for redirect responses"
text="",
body=b"",
content="",
status=current_response.status if current_response else 301,
reason=(
current_response.status_text
@@ -221,8 +218,7 @@ class ResponseFactory:
return Response(
url=page.url,
text=page_content,
body=page_content.encode("utf-8"),
content=page_content,
status=final_response.status,
reason=status_text,
encoding=encoding,
@@ -243,8 +239,7 @@ class ResponseFactory:
"""
return Response(
url=response.url,
text=response.text,
body=response.content
content=response.content
if type(response.content) is bytes
else response.content.encode(),
status=response.status_code,
+5 -5
View File
@@ -103,8 +103,7 @@ class Response(Selector):
def __init__(
self,
url: str,
text: str,
body: bytes,
content: str | bytes,
status: int,
reason: str,
cookies: Union[Tuple[Dict[str, str], ...], Dict[str, str]],
@@ -122,10 +121,11 @@ class Response(Selector):
self.headers = headers
self.request_headers = request_headers
self.history = history or []
encoding = ResponseEncoding.get_value(encoding, text)
encoding = ResponseEncoding.get_value(
encoding, content.decode("utf-8") if isinstance(content, bytes) else content
)
super().__init__(
text=text,
body=body,
content=content,
url=adaptive_domain or url,
encoding=encoding,
**selector_config,
+18 -22
View File
@@ -50,9 +50,8 @@ class Selector(SelectorsGeneration):
def __init__(
self,
text: Optional[str] = None,
content: Optional[Union[str, bytes]] = None,
url: Optional[str] = None,
body: bytes = b"",
encoding: str = "utf8",
huge_tree: bool = True,
root: Optional[html.HtmlElement] = None,
@@ -72,9 +71,8 @@ class Selector(SelectorsGeneration):
not possible. You can test it here and see code explodes with `AssertionError: invalid Element proxy at...`.
It's an old issue with lxml, see `this entry <https://bugs.launchpad.net/lxml/+bug/736708>`
:param text: HTML body passed as text.
:param content: HTML content as either string or bytes.
:param url: It allows storing a URL with the HTML data for retrieving later.
:param body: HTML body as an ``bytes`` object. It can be used instead of the ``text`` argument.
:param encoding: The encoding type that will be used in HTML parsing, default is `UTF-8`
:param huge_tree: Enabled by default, should always be enabled when parsing large HTML documents. This controls
the libxml2 feature that forbids parsing certain large documents to protect from possible memory exhaustion.
@@ -88,27 +86,23 @@ class Selector(SelectorsGeneration):
:param storage_args: A dictionary of ``argument->value`` pairs to be passed for the storage class.
If empty, default values will be used.
"""
if root is None and not body and text is None:
if root is None and content is None:
raise ValueError(
"Selector class needs text, body, or root arguments to work"
"Selector class needs HTML content, or root arguments to work"
)
self.__text = ""
if root is None:
if text is None:
if not body or not isinstance(body, bytes):
raise TypeError(
f"body argument must be valid and of type bytes, got {body.__class__}"
)
body = body.replace(b"\x00", b"").strip()
if isinstance(content, bytes):
body = content.replace(b"\x00", b"").strip()
elif isinstance(content, str):
body = (
content.strip().replace("\x00", "").encode(encoding) or b"<html/>"
)
else:
if not isinstance(text, str):
raise TypeError(
f"text argument must be of type str, got {text.__class__}"
)
body = text.strip().replace("\x00", "").encode(encoding) or b"<html/>"
raise TypeError(
f"content argument must be str or bytes, got {type(content)}"
)
# https://lxml.de/api/lxml.etree.HTMLParser-class.html
parser = html.HTMLParser(
@@ -122,8 +116,10 @@ class Selector(SelectorsGeneration):
strip_cdata=(not keep_cdata),
)
self._root = etree.fromstring(body, parser=parser, base_url=url)
if is_jsonable(text or body.decode()):
self.__text = TextHandler(text or body.decode())
jsonable_text = content if isinstance(content, str) else body.decode()
if is_jsonable(jsonable_text):
self.__text = TextHandler(jsonable_text)
else:
# All HTML types inherit from HtmlMixin so this to check for all at once
@@ -930,7 +926,7 @@ class Selector(SelectorsGeneration):
) -> None:
"""Saves the element's unique properties to the storage for retrieval and relocation later
:param element: The element itself that we want to save to storage, it can be an ` Selector ` or pure ` HtmlElement `
:param element: The element itself that we want to save to storage, it can be a ` Selector ` or pure ` HtmlElement `
:param identifier: This is the identifier that will be used to retrieve the element later from the storage. See
the docs for more info.
"""
+1 -4
View File
@@ -173,10 +173,7 @@ class TestErrorHandling:
_ = Selector(root="ayo", adaptive=False)
with pytest.raises(TypeError):
_ = Selector(text=1, adaptive=False)
with pytest.raises(TypeError):
_ = Selector(body=1, adaptive=False)
_ = Selector(content=1, adaptive=False)
def test_invalid_storage(self, page, html_content):
"""Test invalid storage parameter"""