D4Vinci/Scrapling · error · ExpressionError
The functional pseudo-element ::{pseudo_element.name}() is u
Error message
The functional pseudo-element ::{pseudo_element.name}() is unknown What it means
Raised by `xpath_pseudo_element` in Scrapling's translator (scrapling/core/translator.py:99). When translating a CSS selector, each pseudo-element is dispatched to a handler method named `xpath_<name>_functional_pseudo_element`. Scrapling implements `::attr()`; any other functional pseudo-element (one written with parentheses, e.g. `::nth-child(2)` misused as pseudo-element, `::lang(en)`, `::dir(rtl)`) has no handler, so an `ExpressionError` (cssselect's exception, exported for compatibility) is raised.
Source
Thrown at scrapling/core/translator.py:99
"""This mixin adds support to CSS pseudo elements via dynamic dispatch.
Currently supported pseudo-elements are ``::text`` and ``::attr(ATTR_NAME)``.
"""
def xpath_element(self: TranslatorProtocol, selector: Element) -> XPathExpr:
# https://github.com/python/mypy/issues/14757
xpath = super().xpath_element(selector) # type: ignore[safe-super]
return XPathExpr.from_xpath(xpath)
def xpath_pseudo_element(self, xpath: OriginalXPathExpr, pseudo_element: PseudoElement) -> OriginalXPathExpr:
"""
Dispatch method that transforms XPath to support the pseudo-element.
"""
if isinstance(pseudo_element, FunctionalPseudoElement):
method_name = f"xpath_{pseudo_element.name.replace('-', '_')}_functional_pseudo_element"
method = getattr(self, method_name, None)
if not method: # pragma: no cover
raise ExpressionError(f"The functional pseudo-element ::{pseudo_element.name}() is unknown")
xpath = method(xpath, pseudo_element)
else:
method_name = f"xpath_{pseudo_element.replace('-', '_')}_simple_pseudo_element"
method = getattr(self, method_name, None)
if not method: # pragma: no cover
raise ExpressionError(f"The pseudo-element ::{pseudo_element} is unknown")
xpath = method(xpath)
return xpath
@staticmethod
def xpath_attr_functional_pseudo_element(xpath: OriginalXPathExpr, function: FunctionalPseudoElement) -> XPathExpr:
"""Support selecting attribute values using ::attr() pseudo-element"""
if function.argument_types() not in (["STRING"], ["IDENT"]): # pragma: no cover
raise ExpressionError(f"Expected a single string or ident for ::attr(), got {function.arguments!r}")
return XPathExpr.from_xpath(xpath, attribute=function.arguments[0].value)
@staticmethod
def xpath_text_simple_pseudo_element(xpath: OriginalXPathExpr) -> XPathExpr:View on GitHub (pinned to 5d213a2d47)
Solutions
- Restrict pseudo-elements in Scrapling selectors to the supported set: `::text`, `::attr(name)` (and standard structural pseudo-classes like `:nth-child()` written with one colon, which cssselect handles natively).
- Replace unsupported functional pseudo-elements with equivalent XPath: `p::lang(en)` -> select then filter by `element.lang` attribute in Python.
- If you need browser-grade CSS, evaluate the selector in the browser engine via the fetcher's `page_action`/JS instead of the translator.
- Check the exact selector string for typos before assuming a missing feature.
Example fix
# before
links = page.css('a::attr(href)')
lang_paras = page.css('p::lang(en)') # ExpressionError
# after
links = page.css('a::attr(href)')
lang_paras = [p for p in page.css('p') if p.attrib.get('lang', '').startswith('en')] Defensive patterns
Strategy: validation
Validate before calling
import re
SUPPORTED_FUNCTIONAL = {'attr'}
def selector_uses_supported_pseudo_elements(css: str) -> bool:
found = re.findall(r'::([a-zA-Z-]+)\(', css)
return all(name in SUPPORTED_FUNCTIONAL for name in found) Try / catch
from cssselect.parser import ExpressionError # same class scrapling re-raises
try:
vals = page.css('p::lang(en)')
except Exception as e:
if 'pseudo-element' in str(e):
vals = [p for p in page.css('p') if p.attrib.get('lang', '').startswith('en')]
else:
raise Prevention
- Restrict Scrapling pseudo-elements to ::text and ::attr(name).
- Use structural pseudo-classes (:nth-child) with one colon, not pseudo-elements.
- Keep a whitelist check on dynamically assembled selector strings.
When it happens
Trigger: Calling `selector.css('p::lang(en)')`, `selector.css('div::dir(rtl)')`, or any `::<name>(...)` pseudo-element other than `::attr()` in Scrapling. Anything with parentheses that isn't `::attr(...)` hits this branch.
Common situations: Copy-pasting selectors written for Scrapy (which supports a similar set) or from browser DevTools; assuming all CSS pseudo-elements work because `::text` and `::attr()` do; typos like `::atrr(href)`.
Related errors
- The pseudo-element ::{pseudo_element} is unknown
- Expressions of type {__name__}.XPathExpr can ony join expres
- Expected a single string or ident for ::attr(), got {functio
- Storage system must implement `save` method
- Storage system must implement `retrieve` method
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/07097aef898e8717.
Report an issue: GitHub.