D4Vinci/Scrapling · error · TypeError

Input must be of type `Selector`

Error message

Input must be of type `Selector`

What it means

Convertor._extract_content is the extraction pipeline for markdown/html/text output. Its first guard requires the page argument to be a truthy Selector instance; anything else (str, bytes, Response, None) raises TypeError immediately. Note the falsy check: an empty/None page also fails even before the isinstance check matters.

Source

Thrown at scrapling/core/shell.py:626

            element.drop_tree()
        for element in clean_root.iter():
            if element.text:
                element.text = _CONTROL_CHARS_PATTERN.sub("", _ZWC_PATTERN.sub("", element.text))
            if element.tail:
                element.tail = _CONTROL_CHARS_PATTERN.sub("", _ZWC_PATTERN.sub("", element.tail))
        return Selector(root=clean_root, url=page.url, keep_comments=False)

    @classmethod
    def _extract_content(
        cls,
        page: Selector,
        extraction_type: extraction_types = "markdown",
        css_selector: Optional[str] = None,
        main_content_only: bool = False,
    ) -> Generator[str, None, None]:
        """Extract the content of a Selector"""
        if not page or not isinstance(page, Selector):  # pragma: no cover
            raise TypeError("Input must be of type `Selector`")
        elif not extraction_type or extraction_type not in cls._extension_map.values():
            raise ValueError(f"Unknown extraction type: {extraction_type}")
        else:
            if main_content_only:
                page = cast(Selector, page.css("body").first) or page
                page = cls._strip_noise_tags(page)
                page = cls._sanitize_for_ai(page)

            pages = [page] if not css_selector else cast(Selectors, page.css(css_selector))
            for page in pages:
                match extraction_type:
                    case "markdown":
                        yield cls._convert_to_markdown(page.html_content)
                    case "html":
                        yield page.html_content
                    case "text":
                        txt_content = page.get_all_text(
                            strip=True, ignore_tags=("script", "style", "noscript", "svg", "iframe")

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Fetch first so you hold a Selector: `page = Fetcher.get(url)` then pass `page` (Selector), not `page.content`
  2. If you have raw HTML, wrap it: `Selector(content=html_string)` before extraction
  3. Use public APIs (fetch/shell commands or write_content_to_file) instead of _extract_content

Example fix

# before
content = Convertor._extract_content(response, 'markdown')

# after
content = Convertor._extract_content(response.selector, 'markdown')
Defensive patterns

Strategy: type-guard

Validate before calling

from scrapling.parser import Selector

assert isinstance(page, Selector) and bool(page), 'pass a non-empty Selector, not raw content or a Response'

Type guard

from scrapling.parser import Selector
from typing import Any

def is_selector(value: Any) -> bool:
    return isinstance(value, Selector) and bool(value)

Prevention

When it happens

Trigger: Calling Convertor methods with a Response object instead of its .selector, passing page.html_content (a string), or calling the private _extract_content directly on raw content. Marked pragma: no cover because public entry points normally always pass a Selector.

Common situations: Users reaching into the private API, or older snippets where a function took html text and now expects a Selector after a version refactor.

Related errors


AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14). Data as JSON: /api/errors/af71d182836512a4. Report an issue: GitHub.