Zum Inhalt

Spider-Klassen

Hier finden Sie die Parameter, Attribute und Methoden der Klassen im Spider-Framework.

Sie können sie direkt importieren:

from scrapling.spiders import Spider, Request, CrawlResult, SessionManager, Response

scrapling.spiders.Spider

Spider(crawldir=None, interval=300.0)

Basisklassen: ABC


              flowchart TD
              scrapling.spiders.Spider[Spider]

              

              click scrapling.spiders.Spider href "" "scrapling.spiders.Spider"
            

Eine abstrakte Basisklasse zum Erstellen von Web-Spidern.

Weitere Informationen finden Sie auf der Dokumentationswebsite.

Initialisiert den Spider.

PARAMETER BESCHREIBUNG
crawldir

Ordner für Checkpoint-Dateien. Wenn angegeben, sind Pause und Fortsetzung möglich.

TYP: Optional[Union[str, Path, Path]] STANDARDWERT: None

interval

Sekunden zwischen regelmäßigen Checkpoint-Speicherungen. Standard: 5 Minuten.

TYP: float STANDARDWERT: 300.0

Quellcode in scrapling/spiders/spider.py
def __init__(self, crawldir: Optional[Union[str, Path, AsyncPath]] = None, interval: float = 300.0):
    """Initialize the spider.

    :param crawldir: Directory for checkpoint files. If provided, enables pause/resume.
    :param interval: Seconds between periodic checkpoint saves (default 5 minutes).
    """
    if self.name is None:
        raise ValueError(f"{self.__class__.__name__} must have a name.")

    self.logger = logging.getLogger(f"scrapling.spiders.{self.name}")
    self.logger.setLevel(self.logging_level)
    self.logger.handlers.clear()
    self.logger.propagate = False  # Don't propagate to parent 'scrapling' logger

    formatter = logging.Formatter(
        fmt=self.logging_format.format(spider_name=self.name), datefmt=self.logging_date_format
    )

    # Add a log counter handler to track log counts by level
    self._log_counter = LogCounterHandler()
    self.logger.addHandler(self._log_counter)

    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    self.logger.addHandler(console_handler)

    if self.log_file:
        Path(self.log_file).parent.mkdir(parents=True, exist_ok=True)
        file_handler = logging.FileHandler(self.log_file, encoding=self.log_file_encoding)
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)

    self.crawldir: Optional[Path] = Path(crawldir) if crawldir else None
    self._interval = interval
    self._engine: Optional[CrawlerEngine] = None
    self._original_sigint_handler: Any = None

    self._session_manager = SessionManager()

    try:
        self.configure_sessions(self._session_manager)
    except Exception as e:
        raise SessionConfigurationError(f"Error in {self.__class__.__name__}.configure_sessions(): {e}") from e

    if len(self._session_manager) == 0:
        raise SessionConfigurationError(f"{self.__class__.__name__}.configure_sessions() did not add any sessions")

    self.logger.info("Spider initialized")

name class-attribute instance-attribute

name = None

start_urls class-attribute instance-attribute

start_urls = []

allowed_domains class-attribute instance-attribute

allowed_domains = set()

robots_txt_obey class-attribute instance-attribute

robots_txt_obey = False

development_mode class-attribute instance-attribute

development_mode = False

development_cache_dir class-attribute instance-attribute

development_cache_dir = None

concurrent_requests class-attribute instance-attribute

concurrent_requests = 4

concurrent_requests_per_domain class-attribute instance-attribute

concurrent_requests_per_domain = 0

download_delay class-attribute instance-attribute

download_delay = 0.0

max_blocked_retries class-attribute instance-attribute

max_blocked_retries = 3

autothrottle_enabled class-attribute instance-attribute

autothrottle_enabled = False

autothrottle_start_delay class-attribute instance-attribute

autothrottle_start_delay = 5.0

autothrottle_max_delay class-attribute instance-attribute

autothrottle_max_delay = 60.0

autothrottle_target_concurrency class-attribute instance-attribute

autothrottle_target_concurrency = None

autothrottle_block_backoff class-attribute instance-attribute

autothrottle_block_backoff = True

fp_include_kwargs class-attribute instance-attribute

fp_include_kwargs = False

fp_keep_fragments class-attribute instance-attribute

fp_keep_fragments = False

fp_include_headers class-attribute instance-attribute

fp_include_headers = False

logging_level class-attribute instance-attribute

logging_level = logging.DEBUG

logging_format class-attribute instance-attribute

logging_format = "[%(asctime)s]:({spider_name}) %(levelname)s: %(message)s"

logging_date_format class-attribute instance-attribute

logging_date_format = '%Y-%m-%d %H:%M:%S'

log_file class-attribute instance-attribute

log_file = None

log_file_encoding class-attribute instance-attribute

log_file_encoding = None

logger instance-attribute

logger = logging.getLogger(f"scrapling.spiders.{self.name}")

crawldir instance-attribute

crawldir = Path(crawldir) if crawldir else None

stats property

stats

Greift auf die aktuellen Crawl-Statistiken zu. Funktioniert auch beim Streaming.

start_requests async

start_requests()

Erzeugt die ersten Anfragen für den Crawl.

Erzeugt standardmäßig Request-Objekte für jede URL in start_urls. Nutzt die Standardsitzung des Sitzungsmanagers und parse() als Callback.

Überschreiben Sie diese Methode, um die ersten Anfragen genauer zu steuern, etwa mit eigenen Headern oder anderen Callbacks.

Quellcode in scrapling/spiders/spider.py
async def start_requests(self) -> AsyncGenerator[Request, None]:
    """Generate initial requests to start the crawl.

    By default, this generates Request objects for each URL in `start_urls`
    using the session manager's default session and `parse()` as callback.

    Override this method for more control over initial requests
    (e.g., to add custom headers, use different callbacks, etc.)
    """
    if not self.start_urls:
        raise RuntimeError(
            "Spider has no starting point, either set `start_urls` or override `start_requests` function."
        )

    for url in self.start_urls:
        yield Request(url, sid=self._session_manager.default_session_id)

parse abstractmethod async

parse(response)

Standard-Callback zum Verarbeiten von Antworten.

Quellcode in scrapling/spiders/spider.py
@abstractmethod
async def parse(self, response: "Response") -> AsyncGenerator[Dict[str, Any] | Request | None, None]:
    """Default callback for processing responses"""
    raise NotImplementedError(f"{self.__class__.__name__} must implement parse() method")
    yield  # Make this a generator for type checkers

on_start async

on_start(resuming=False)

Wird vor dem Start des Crawls aufgerufen. Überschreiben Sie die Methode für eigene Vorbereitungsschritte.

PARAMETER BESCHREIBUNG
resuming

Aktiviert, wenn der Spider von einem Checkpoint fortgesetzt wird. Sie können diesen Wert in Ihrem Code verwenden.

TYP: bool STANDARDWERT: False

Quellcode in scrapling/spiders/spider.py
async def on_start(self, resuming: bool = False) -> None:
    """Called before crawling starts. Override for setup logic.

    :param resuming: It's enabled if the spider is resuming from a checkpoint, left for the user to use.
    """
    if resuming:
        self.logger.debug("Resuming spider from checkpoint")
    else:
        self.logger.debug("Starting spider")

on_close async

on_close()

Wird nach dem Ende des Crawls aufgerufen. Überschreiben Sie die Methode, um Ressourcen freizugeben.

Quellcode in scrapling/spiders/spider.py
async def on_close(self) -> None:
    """Called after crawling finishes. Override for cleanup logic."""
    self.logger.debug("Spider closed")

on_error async

on_error(request, error)

Behandelt Anfragefehler für alle Anfragen des Spiders.

Überschreiben Sie die Methode für eine eigene Fehlerbehandlung.

Quellcode in scrapling/spiders/spider.py
async def on_error(self, request: Request, error: Exception) -> None:
    """
    Handle request errors for all spider requests.

    Override for custom error handling.
    """
    pass

on_scraped_item async

on_scraped_item(item)

Ein Hook, den Sie überschreiben können, um extrahierte Datensätze zu verarbeiten. Geben Sie None zurück, um den Datensatz ohne Meldung zu verwerfen.

Quellcode in scrapling/spiders/spider.py
async def on_scraped_item(self, item: Dict[str, Any]) -> Dict[str, Any] | None:
    """A hook to be overridden by users to do some processing on scraped items, return `None` to drop the item silently."""
    return item

is_blocked async

is_blocked(response)

Prüft, ob die Antwort blockiert ist. Überschreiben Sie die Methode für eine eigene Erkennung.

Quellcode in scrapling/spiders/spider.py
async def is_blocked(self, response: "Response") -> bool:
    """Check if the response is blocked. Users should override this for custom detection logic."""
    if response.status in BLOCKED_CODES:
        return True
    return False

retry_blocked_request async

retry_blocked_request(request, response)

Überschreiben Sie die Methode bei Bedarf, um eine blockierte Anfrage vor dem nächsten Versuch anzupassen.

Quellcode in scrapling/spiders/spider.py
async def retry_blocked_request(self, request: Request, response: "Response") -> Request:
    """Users should override this to prepare the blocked request before retrying, if needed."""
    return request

__repr__

__repr__()

Darstellung des Spiders als Zeichenfolge.

Quellcode in scrapling/spiders/spider.py
def __repr__(self) -> str:
    """String representation of the spider."""
    return f"<{self.__class__.__name__} '{self.name}'>"

configure_sessions

configure_sessions(manager)

Konfiguriert die Sitzungen dieses Spiders.

Überschreiben Sie diese Methode, um eigene Sitzungen hinzuzufügen. Die Standardimplementierung erstellt eine FetcherSession-Sitzung.

Die zuerst hinzugefügte Sitzung wird zur Standardsitzung für start_requests(), wenn nichts anderes angegeben ist.

PARAMETER BESCHREIBUNG
manager

Der zu konfigurierende SessionManager.

TYP: SessionManager

Quellcode in scrapling/spiders/spider.py
def configure_sessions(self, manager: SessionManager) -> None:
    """Configure sessions for this spider.

    Override this method to add custom sessions.
    The default implementation creates a FetcherSession session.

    The first session added becomes the default for `start_requests()` unless specified otherwise.

    :param manager: SessionManager to configure
    """
    from scrapling.fetchers import FetcherSession

    manager.add("default", FetcherSession())

pause

pause()

Fordert einen geordneten Stopp des Crawls an.

Quellcode in scrapling/spiders/spider.py
def pause(self):
    """Request graceful shutdown of the crawling process."""
    if self._engine:
        self._engine.request_pause()
    else:
        raise RuntimeError("No active crawl to stop")

start

start(use_uvloop=False, **backend_options)

Führt den Spider aus und gibt die Ergebnisse zurück.

Der Haupteinstiegspunkt zum Ausführen eines Spiders. Verwaltet die asynchrone Ausführung intern mit anyio.

Ctrl+C leitet einen geordneten Stopp ein und wartet auf aktive Aufgaben. Ein zweites Ctrl+C erzwingt den sofortigen Stopp.

Wenn crawldir gesetzt ist, wird beim geordneten Stopp auch ein Checkpoint gespeichert. Beim nächsten Start des Spiders können Sie den Crawl damit fortsetzen.

PARAMETER BESCHREIBUNG
use_uvloop

Gibt an, ob die schnellere Ereignisschleife von uvloop/winloop verwendet werden soll, falls verfügbar.

TYP: bool STANDARDWERT: False

backend_options

Optionen des Asyncio-Backends für anyio.run.

TYP: Any STANDARDWERT: {}

Quellcode in scrapling/spiders/spider.py
def start(self, use_uvloop: bool = False, **backend_options: Any) -> CrawlResult:
    """Run the spider and return results.

    This is the main entry point for running a spider.
    Handles async execution internally via anyio.

    Pressing Ctrl+C will initiate graceful shutdown (waits for active tasks to complete).
    Pressing Ctrl+C a second time will force immediate stop.

    If crawldir is set, a checkpoint will also be saved on graceful shutdown,
    allowing you to resume the crawl later by running the spider again.

    :param use_uvloop: Whether to use the faster uvloop/winloop event loop implementation, if available.
    :param backend_options: Asyncio backend options to be used with `anyio.run`
    """
    backend_options = backend_options or {}
    if use_uvloop:
        backend_options.update({"use_uvloop": True})

    # Set up SIGINT handler for graceful shutdown
    self._setup_signal_handler()
    try:
        return anyio.run(self.__run, backend="asyncio", backend_options=backend_options)
    finally:
        self._restore_signal_handler()

stream async

stream()

Gibt Datensätze direkt beim Extrahieren als Stream aus. Geeignet für lange Crawls oder Anwendungen, die auf Spidern aufbauen.

Muss aus einem asynchronen Kontext aufgerufen werden. Gibt Datensätze einzeln direkt nach dem Extrahieren aus. Greifen Sie während der Iteration auf spider.stats zu, um aktuelle Statistiken zu erhalten.

Hinweis: Die Behandlung von SIGINT für Pause und Fortsetzung ist im Streaming-Modus nicht verfügbar.

Quellcode in scrapling/spiders/spider.py
async def stream(self) -> AsyncGenerator[Dict[str, Any], None]:
    """Stream items as they're scraped. Ideal for long-running spiders or building applications on top of the spiders.

    Must be called from an async context. Yields items one by one as they are scraped.
    Access `spider.stats` during iteration for real-time statistics.

    Note: SIGINT handling for pause/resume is not available in stream mode.
    """
    token = set_logger(self.logger)
    try:
        self._engine = CrawlerEngine(self, self._session_manager, self.crawldir, self._interval)
        async for item in self._engine:
            yield item
    finally:
        self._engine = None
        reset_logger(token)
        if self.log_file:
            for handler in self.logger.handlers:
                if isinstance(handler, logging.FileHandler):
                    handler.close()

scrapling.spiders.Request

Request(
    url,
    sid="",
    callback=None,
    priority=0,
    dont_filter=False,
    meta=None,
    _retry_count=0,
    **kwargs
)
Quellcode in scrapling/spiders/request.py
def __init__(
    self,
    url: str,
    sid: str = "",
    callback: Callable[[Response], AsyncGenerator[Union[Dict[str, Any], "Request", None], None]] | None = None,
    priority: int = 0,
    dont_filter: bool = False,
    meta: dict[str, Any] | None = None,
    _retry_count: int = 0,
    **kwargs: Any,
) -> None:
    self.url: str = url
    self.sid: str = sid
    self.callback = callback
    self.priority: int = priority
    self.dont_filter: bool = dont_filter
    self.meta: dict[str, Any] = meta if meta else {}
    self._retry_count: int = _retry_count
    self._session_kwargs = kwargs if kwargs else {}
    self._fp: Optional[bytes] = None

url instance-attribute

url = url

sid instance-attribute

sid = sid

callback instance-attribute

callback = callback

priority instance-attribute

priority = priority

dont_filter instance-attribute

dont_filter = dont_filter

meta instance-attribute

meta = meta if meta else {}

domain cached property

domain

copy

copy()

Erstellt eine Kopie dieser Anfrage.

Quellcode in scrapling/spiders/request.py
def copy(self) -> "Request":
    """Create a copy of this request."""
    return Request(
        url=self.url,
        sid=self.sid,
        callback=self.callback,
        priority=self.priority,
        dont_filter=self.dont_filter,
        meta=self.meta.copy(),
        _retry_count=self._retry_count,
        **self._session_kwargs,
    )

update_fingerprint

update_fingerprint(
    include_kwargs=False,
    include_headers=False,
    keep_fragments=False,
)

Erzeugt einen eindeutigen Fingerprint zum Erkennen von Duplikaten.

Speichert das Ergebnis nach der ersten Berechnung in self._fp zwischen.

Quellcode in scrapling/spiders/request.py
def update_fingerprint(
    self,
    include_kwargs: bool = False,
    include_headers: bool = False,
    keep_fragments: bool = False,
) -> bytes:
    """Generate a unique fingerprint for deduplication.

    Caches the result in self._fp after first computation.
    """
    if self._fp is not None:
        return self._fp

    post_data = self._session_kwargs.get("data", {})
    body = b""
    if post_data:
        if isinstance(post_data, dict | list | tuple):
            body = urlencode(post_data).encode()
        elif isinstance(post_data, str):
            body = post_data.encode()
        elif isinstance(post_data, BytesIO):
            body = post_data.getvalue()
        elif isinstance(post_data, bytes):
            body = post_data
    else:
        post_data = self._session_kwargs.get("json")
        body = orjson.dumps(post_data) if post_data is not None else b""

    params = self._session_kwargs.get("params")
    url = update_url_params(self.url, params) if params else self.url

    data: Dict[str, str | Tuple] = {
        "sid": self.sid,
        "body": body.hex(),
        "method": self._session_kwargs.get("method", "GET"),
        "url": canonicalize_url(url, keep_fragments=keep_fragments),
    }

    if include_kwargs:
        filtered_kwargs = {
            key.lower(): _stable_value_repr(value)
            for key, value in self._session_kwargs.items()
            if key.lower() not in ("data", "json")
        }
        data["kwargs"] = tuple(sorted(filtered_kwargs.items()))

    if include_headers:
        headers = self._session_kwargs.get("headers") or self._session_kwargs.get("extra_headers") or {}
        processed_headers = {}
        # Some header normalization
        for key, value in headers.items():
            processed_headers[_convert_to_bytes(key.lower()).hex()] = _convert_to_bytes(value).hex()
        data["headers"] = tuple(sorted(processed_headers.items()))

    fp = hashlib.sha1(orjson.dumps(data, option=orjson.OPT_SORT_KEYS), usedforsecurity=False).digest()
    self._fp = fp
    return fp

__repr__

__repr__()
Quellcode in scrapling/spiders/request.py
def __repr__(self) -> str:
    callback_name = getattr(self.callback, "__name__", None) or "None"
    return f"<Request({self.url}) priority={self.priority} callback={callback_name}>"

__str__

__str__()
Quellcode in scrapling/spiders/request.py
def __str__(self) -> str:
    return self.url

__lt__

__lt__(other)

Vergleicht Anfragen nach ihrer Priorität.

Quellcode in scrapling/spiders/request.py
def __lt__(self, other: object) -> bool:
    """Compare requests by priority"""
    if not isinstance(other, Request):
        return NotImplemented
    return self.priority < other.priority

__gt__

__gt__(other)

Vergleicht Anfragen nach ihrer Priorität.

Quellcode in scrapling/spiders/request.py
def __gt__(self, other: object) -> bool:
    """Compare requests by priority"""
    if not isinstance(other, Request):
        return NotImplemented
    return self.priority > other.priority

__eq__

__eq__(other)

Anfragen sind gleich, wenn sie denselben Fingerprint haben.

Quellcode in scrapling/spiders/request.py
def __eq__(self, other: object) -> bool:
    """Requests are equal if they have the same fingerprint."""
    if not isinstance(other, Request):
        return NotImplemented
    if self._fp is None or other._fp is None:
        raise RuntimeError("Cannot compare requests before generating their fingerprints!")
    return self._fp == other._fp

__getstate__

__getstate__()

Bereitet den Zustand für pickle vor. Speichert den Namen des Callbacks als String, damit er mit pickle kompatibel ist.

Quellcode in scrapling/spiders/request.py
def __getstate__(self) -> dict[str, Any]:
    """Prepare state for pickling - store callback as name string for pickle compatibility."""
    state = self.__dict__.copy()
    state["_callback_name"] = getattr(self.callback, "__name__", None) if self.callback is not None else None
    state["callback"] = None  # Don't pickle the actual callable
    return state

__setstate__

__setstate__(state)

Stellt den Zustand aus pickle wieder her. Der Callback wird später mit _restore_callback() wiederhergestellt.

Quellcode in scrapling/spiders/request.py
def __setstate__(self, state: dict[str, Any]) -> None:
    """Restore state from pickle - callback restored later via _restore_callback()."""
    self._callback_name: str | None = state.pop("_callback_name", None)
    self.__dict__.update(state)

Ergebnisklassen

scrapling.spiders.result.CrawlResult dataclass

CrawlResult(stats, items, paused=False)

Das vollständige Ergebnis eines Spider-Durchlaufs.

stats instance-attribute

stats

items instance-attribute

items

paused class-attribute instance-attribute

paused = False

completed property

completed

True, wenn der Crawl normal abgeschlossen wurde und nicht pausiert ist.

__len__

__len__()
Quellcode in scrapling/spiders/result.py
def __len__(self) -> int:
    return len(self.items)

__iter__

__iter__()
Quellcode in scrapling/spiders/result.py
def __iter__(self) -> Iterator[dict[str, Any]]:
    return iter(self.items)

scrapling.spiders.result.CrawlStats dataclass

CrawlStats(
    requests_count=0,
    concurrent_requests=0,
    concurrent_requests_per_domain=0,
    failed_requests_count=0,
    offsite_requests_count=0,
    robots_disallowed_count=0,
    cache_hits=0,
    cache_misses=0,
    response_bytes=0,
    items_scraped=0,
    items_dropped=0,
    start_time=0.0,
    end_time=0.0,
    download_delay=0.0,
    autothrottle_enabled=False,
    blocked_requests_count=0,
    autothrottle_delays=dict(),
    custom_stats=dict(),
    response_status_count=dict(),
    domains_response_bytes=dict(),
    sessions_requests_count=dict(),
    proxies=list(),
    log_levels_counter=dict(),
)

Statistiken eines Crawl-Durchlaufs.

requests_count class-attribute instance-attribute

requests_count = 0

concurrent_requests class-attribute instance-attribute

concurrent_requests = 0

concurrent_requests_per_domain class-attribute instance-attribute

concurrent_requests_per_domain = 0

failed_requests_count class-attribute instance-attribute

failed_requests_count = 0

offsite_requests_count class-attribute instance-attribute

offsite_requests_count = 0

robots_disallowed_count class-attribute instance-attribute

robots_disallowed_count = 0

cache_hits class-attribute instance-attribute

cache_hits = 0

cache_misses class-attribute instance-attribute

cache_misses = 0

response_bytes class-attribute instance-attribute

response_bytes = 0

items_scraped class-attribute instance-attribute

items_scraped = 0

items_dropped class-attribute instance-attribute

items_dropped = 0

start_time class-attribute instance-attribute

start_time = 0.0

end_time class-attribute instance-attribute

end_time = 0.0

download_delay class-attribute instance-attribute

download_delay = 0.0

autothrottle_enabled class-attribute instance-attribute

autothrottle_enabled = False

blocked_requests_count class-attribute instance-attribute

blocked_requests_count = 0

autothrottle_delays class-attribute instance-attribute

autothrottle_delays = field(default_factory=dict)

custom_stats class-attribute instance-attribute

custom_stats = field(default_factory=dict)

response_status_count class-attribute instance-attribute

response_status_count = field(default_factory=dict)

domains_response_bytes class-attribute instance-attribute

domains_response_bytes = field(default_factory=dict)

sessions_requests_count class-attribute instance-attribute

sessions_requests_count = field(default_factory=dict)

proxies class-attribute instance-attribute

proxies = field(default_factory=list)

log_levels_counter class-attribute instance-attribute

log_levels_counter = field(default_factory=dict)

elapsed_seconds property

elapsed_seconds

requests_per_second property

requests_per_second

increment_status

increment_status(status)
Quellcode in scrapling/spiders/result.py
def increment_status(self, status: int) -> None:
    self.response_status_count[f"status_{status}"] = self.response_status_count.get(f"status_{status}", 0) + 1

increment_response_bytes

increment_response_bytes(domain, count)
Quellcode in scrapling/spiders/result.py
def increment_response_bytes(self, domain: str, count: int) -> None:
    self.response_bytes += count
    self.domains_response_bytes[domain] = self.domains_response_bytes.get(domain, 0) + count

increment_requests_count

increment_requests_count(sid)
Quellcode in scrapling/spiders/result.py
def increment_requests_count(self, sid: str) -> None:
    self.requests_count += 1
    self.sessions_requests_count[sid] = self.sessions_requests_count.get(sid, 0) + 1

to_dict

to_dict()
Quellcode in scrapling/spiders/result.py
def to_dict(self) -> dict[str, Any]:
    return {
        "items_scraped": self.items_scraped,
        "items_dropped": self.items_dropped,
        "elapsed_seconds": round(self.elapsed_seconds, 2),
        "download_delay": round(self.download_delay, 2),
        "autothrottle_enabled": self.autothrottle_enabled,
        "autothrottle_delays": {domain: round(delay, 2) for domain, delay in self.autothrottle_delays.items()},
        "concurrent_requests": self.concurrent_requests,
        "concurrent_requests_per_domain": self.concurrent_requests_per_domain,
        "requests_count": self.requests_count,
        "requests_per_second": round(self.requests_per_second, 2),
        "sessions_requests_count": self.sessions_requests_count,
        "failed_requests_count": self.failed_requests_count,
        "offsite_requests_count": self.offsite_requests_count,
        "robots_disallowed_count": self.robots_disallowed_count,
        "cache_hits": self.cache_hits,
        "cache_misses": self.cache_misses,
        "blocked_requests_count": self.blocked_requests_count,
        "response_status_count": self.response_status_count,
        "response_bytes": self.response_bytes,
        "domains_response_bytes": self.domains_response_bytes,
        "proxies": self.proxies,
        "custom_stats": self.custom_stats,
        "log_count": self.log_levels_counter,
    }

scrapling.spiders.result.ItemList

Basisklassen: list


              flowchart TD
              scrapling.spiders.result.ItemList[ItemList]

              

              click scrapling.spiders.result.ItemList href "" "scrapling.spiders.result.ItemList"
            

Eine Liste extrahierter Datensätze mit Exportfunktionen.

to_json

to_json(path, *, indent=False)

Exportiert Datensätze in eine JSON-Datei.

PARAMETER BESCHREIBUNG
path

Pfad zur Ausgabedatei.

TYP: Union[str, Path]

indent

Formatiert die Ausgabe mit 2 Leerzeichen Einrückung. Etwas langsamer.

TYP: bool STANDARDWERT: False

Quellcode in scrapling/spiders/result.py
def to_json(self, path: Union[str, Path], *, indent: bool = False):
    """Export items to a JSON file.

    :param path: Path to the output file
    :param indent: Pretty-print with 2-space indentation (slightly slower)
    """
    options = orjson.OPT_SERIALIZE_NUMPY
    if indent:
        options |= orjson.OPT_INDENT_2

    file = Path(path)
    file.parent.mkdir(parents=True, exist_ok=True)
    file.write_bytes(orjson.dumps(list(self), option=options))
    log.info("Saved %d items to %s", len(self), path)

to_jsonl

to_jsonl(path)

Exportiert Datensätze als JSON Lines, mit einem JSON-Objekt pro Zeile.

PARAMETER BESCHREIBUNG
path

Pfad zur Ausgabedatei.

TYP: Union[str, Path]

Quellcode in scrapling/spiders/result.py
def to_jsonl(self, path: Union[str, Path]):
    """Export items as JSON Lines (one JSON object per line).

    :param path: Path to the output file
    """
    Path(path).parent.mkdir(parents=True, exist_ok=True)
    with open(path, "wb") as f:
        for item in self:
            f.write(orjson.dumps(item, option=orjson.OPT_SERIALIZE_NUMPY))
            f.write(b"\n")
    log.info("Saved %d items to %s", len(self), path)

to_csv

to_csv(path, *, fields=None, delimiter=',')

Exportiert Datensätze in eine CSV-Datei.

Auch Datensätze mit unterschiedlichen Schlüsseln werden geschrieben. Fehlende Zellen bleiben leer. Nicht skalare Werte, etwa verschachtelte Wörterbücher oder Listen, werden als JSON geschrieben.

PARAMETER BESCHREIBUNG
path

Pfad zur Ausgabedatei.

TYP: Union[str, Path]

fields

Die zu schreibenden Spalten. Standardmäßig alle Schlüssel der Datensätze in der Reihenfolge ihres ersten Auftretens.

TYP: Optional[Iterable[str]] STANDARDWERT: None

delimiter

Das Zeichen zwischen den Spalten.

TYP: str STANDARDWERT: ','

Quellcode in scrapling/spiders/result.py
def to_csv(self, path: Union[str, Path], *, fields: Optional[Iterable[str]] = None, delimiter: str = ","):
    """Export items to a CSV file.

    Items that don't share the same keys are still written, with the missing cells left empty, and any value
    that isn't a scalar (a nested dictionary or a list) is written as JSON.

    :param path: Path to the output file
    :param fields: The columns to write, defaulting to every key found in the items, in the order they appeared
    :param delimiter: The character separating the columns
    """
    columns = list(fields) if fields is not None else list({key: None for item in self for key in item})

    file = Path(path)
    file.parent.mkdir(parents=True, exist_ok=True)
    with open(file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=columns, delimiter=delimiter, extrasaction="ignore")
        writer.writeheader()
        for item in self:
            writer.writerow({column: _stringify(item.get(column)) for column in columns})

    log.info("Saved %d items to %s", len(self), path)

to_xml

to_xml(
    path, *, root_tag="items", item_tag="item", indent=True
)

Exportiert Datensätze in eine XML-Datei.

Jeder Datensatz wird zu einem Element, dessen Kinder nach seinen Schlüsseln benannt sind. Schlüssel, die keine gültigen XML-Namen sind, werden umgeschrieben. Das Original bleibt in einem name-Attribut erhalten. Nicht skalare Werte, etwa verschachtelte Wörterbücher oder Listen, werden als JSON geschrieben.

PARAMETER BESCHREIBUNG
path

Pfad zur Ausgabedatei.

TYP: Union[str, Path]

root_tag

Name des Elements, das alle Datensätze umschließt.

TYP: str STANDARDWERT: 'items'

item_tag

Name des Elements, das jeden einzelnen Datensatz umschließt.

TYP: str STANDARDWERT: 'item'

indent

Formatiert die Datei lesbar, statt alles in eine Zeile zu schreiben.

TYP: bool STANDARDWERT: True

Quellcode in scrapling/spiders/result.py
def to_xml(self, path: Union[str, Path], *, root_tag: str = "items", item_tag: str = "item", indent: bool = True):
    """Export items to an XML file.

    Each item becomes an element whose children are named after the item's keys. Keys that aren't valid XML
    names are rewritten and keep the original in a `name` attribute, and any value that isn't a scalar
    (a nested dictionary or a list) is written as JSON.

    :param path: Path to the output file
    :param root_tag: The name of the element wrapping all the items
    :param item_tag: The name of the element wrapping every item
    :param indent: Pretty-print the file instead of writing it on a single line
    """
    root = Element(root_tag)
    for item in self:
        element = SubElement(root, item_tag)
        for key, value in item.items():
            tag = _xml_tag(key)
            child = SubElement(element, tag)
            if tag != str(key):
                child.set("name", _XML_FORBIDDEN_CHARS.sub("", str(key)))
            child.text = _XML_FORBIDDEN_CHARS.sub("", _stringify(value))

    tree = ElementTree(root)
    if indent:
        indent_tree(tree, space="  ")

    file = Path(path)
    file.parent.mkdir(parents=True, exist_ok=True)
    tree.write(file, encoding="utf-8", xml_declaration=True)
    log.info("Saved %d items to %s", len(self), path)

Sitzungen verwalten

scrapling.spiders.session.SessionManager

SessionManager()

Verwaltet vorkonfigurierte Sitzungsinstanzen.

Quellcode in scrapling/spiders/session.py
def __init__(self) -> None:
    self._sessions: dict[str, Session] = {}
    self._default_session_id: str | None = None
    self._started: bool = False
    self._lazy_sessions: Set[str] = set()
    self._lazy_lock = Lock()

default_session_id property

default_session_id

session_ids property

session_ids

add

add(session_id, session, *, default=False, lazy=False)

Registriert eine Sitzungsinstanz.

PARAMETER BESCHREIBUNG
session_id

Name, mit dem diese Sitzung in Anfragen ausgewählt wird.

TYP: str

session

Ihre vorkonfigurierte Sitzungsinstanz.

TYP: Session

default

Bei True wird dies die Standardsitzung.

TYP: bool STANDARDWERT: False

lazy

Bei True startet die Sitzung erst, wenn eine Anfrage ihre ID verwendet.

TYP: bool STANDARDWERT: False

Quellcode in scrapling/spiders/session.py
def add(self, session_id: str, session: Session, *, default: bool = False, lazy: bool = False) -> "SessionManager":
    """Register a session instance.

    :param session_id: Name to reference this session in requests
    :param session: Your pre-configured session instance
    :param default: If True, this becomes the default session
    :param lazy: If True, the session will be started only when a request uses its ID.
    """
    if session_id in self._sessions:
        raise ValueError(f"Session '{session_id}' already registered")

    self._sessions[session_id] = session

    if default or self._default_session_id is None:
        self._default_session_id = session_id

    if lazy:
        self._lazy_sessions.add(session_id)

    return self

remove

remove(session_id)

Entfernt eine Sitzung.

PARAMETER BESCHREIBUNG
session_id

ID der zu entfernenden Sitzung.

TYP: str

Quellcode in scrapling/spiders/session.py
def remove(self, session_id: str) -> None:
    """Removes a session.

    :param session_id: ID of session to remove
    """
    _ = self.pop(session_id)

pop

pop(session_id)

Entfernt eine Sitzung und gibt sie zurück.

PARAMETER BESCHREIBUNG
session_id

ID der zu entfernenden Sitzung.

TYP: str

Quellcode in scrapling/spiders/session.py
def pop(self, session_id: str) -> Session:
    """Remove and returns a session.

    :param session_id: ID of session to remove
    """
    if session_id not in self._sessions:
        raise KeyError(f"Session '{session_id}' not found")

    session = self._sessions.pop(session_id)
    if session_id in self._lazy_sessions:
        self._lazy_sessions.remove(session_id)

    if session and self._default_session_id == session_id:
        self._default_session_id = next(iter(self._sessions), None)

    return session

get

get(session_id)
Quellcode in scrapling/spiders/session.py
def get(self, session_id: str) -> Session:
    if session_id not in self._sessions:
        available = ", ".join(self._sessions.keys())
        raise KeyError(f"Session '{session_id}' not found. Available: {available}")
    return self._sessions[session_id]

start async

start()

Startet alle Sitzungen, die noch nicht aktiv sind.

Quellcode in scrapling/spiders/session.py
async def start(self) -> None:
    """Start all sessions that aren't already alive."""
    if self._started:
        return

    for sid, session in self._sessions.items():
        if sid not in self._lazy_sessions and not session._is_alive:
            await session.__aenter__()

    self._started = True

close async

close()

Schließt alle registrierten Sitzungen.

Quellcode in scrapling/spiders/session.py
async def close(self) -> None:
    """Close all registered sessions."""
    for sid, session in self._sessions.items():
        if sid in self._lazy_sessions and not session._is_alive:
            continue
        _ = await session.__aexit__(None, None, None)

    self._started = False

fetch async

fetch(request)
Quellcode in scrapling/spiders/session.py
async def fetch(self, request: Request) -> Response:
    sid = request.sid if request.sid else self.default_session_id
    session = self.get(sid)

    if session:
        if sid in self._lazy_sessions and not session._is_alive:
            async with self._lazy_lock:
                if not session._is_alive:
                    await session.__aenter__()

        if isinstance(session, FetcherSession):
            client = session._client

            if isinstance(client, _ASyncSessionLogic):
                kwargs = request._session_kwargs.copy()
                method = cast(SUPPORTED_HTTP_METHODS, kwargs.pop("method", "GET"))
                if "stealthy_headers" in kwargs:
                    # Same mapping as the public session methods (`get`, `post`, ...), so it doesn't reach curl_cffi
                    kwargs["stealth"] = kwargs.pop("stealthy_headers")
                response = await client._make_request(
                    method=method,
                    url=request.url,
                    **kwargs,
                )
            else:
                # Sync session or other types - shouldn't happen in async context
                raise TypeError(f"Session type {type(client)} not supported for async fetch")
        else:
            response = await session.fetch(url=request.url, **request._session_kwargs)

        response.request = request
        # Merge request meta into response meta (response meta takes priority)
        response.meta = {**request.meta, **response.meta}
        return response
    raise RuntimeError("No session found with the request session id")

__aenter__ async

__aenter__()
Quellcode in scrapling/spiders/session.py
async def __aenter__(self) -> "SessionManager":
    await self.start()
    return self

__aexit__ async

__aexit__(*exc)
Quellcode in scrapling/spiders/session.py
async def __aexit__(self, *exc) -> None:
    await self.close()

__contains__

__contains__(session_id)

Prüft, ob eine Sitzungs-ID registriert ist.

Quellcode in scrapling/spiders/session.py
def __contains__(self, session_id: str) -> bool:
    """Check if a session ID is registered."""
    return session_id in self._sessions

__len__

__len__()

Anzahl der registrierten Sitzungen.

Quellcode in scrapling/spiders/session.py
def __len__(self) -> int:
    """Number of registered sessions."""
    return len(self._sessions)