Erste Schritte¶
Einführung¶
Voraussetzungen
- Sie haben die Seite Fetcher-Grundlagen gelesen und wissen, welche Fetcher es gibt und wann Sie diese verwenden.
- Sie haben die Seite Hauptklassen gelesen und kennen die Klassen Selector und Response.
- Sie haben die Seite Architektur gelesen und wissen im Überblick, wie das Spider-System arbeitet.
Mit dem Spider-System erstellen Sie in wenigen Codezeilen Crawler, die mehrere Seiten parallel abrufen. Wenn Sie Scrapy kennen, werden Ihnen die Abläufe vertraut sein. Falls nicht, erklärt diese Anleitung alles, was Sie für den Einstieg brauchen.
Ihr erster Spider¶
Ein Spider ist eine Klasse, die festlegt, wie Websites durchsucht und Daten daraus extrahiert werden. Hier ist ein möglichst einfacher Spider:
from scrapling.spiders import Spider, Response
class QuotesSpider(Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com"]
async def parse(self, response: Response):
for quote in response.css("div.quote"):
yield {
"text": quote.css("span.text::text").get(""),
"author": quote.css("small.author::text").get(""),
}
Jeder Spider braucht drei Dinge:
name- Eine eindeutige Kennung für den Spider.start_urls- Eine Liste der URLs, bei denen der Crawl beginnt.parse()- Eine asynchrone Generatormethode, die jede Antwort verarbeitet und Ergebnisse liefert.
In der Methode parse() findet die Verarbeitung statt. Sie verwenden dieselben Auswahlmethoden wie bei Scraplings Selector/Response und geben die extrahierten Datensätze mit yield als Dictionaries aus.
Den Spider starten¶
Erstellen Sie eine Instanz und rufen Sie start() auf, um Ihren Spider zu starten:
Die Methode start() übernimmt die asynchrone Ausführung intern. Sie müssen sich also nicht um Event-Loops kümmern. Während der Spider läuft, werden alle Vorgänge im Terminal protokolliert. Am Ende des Crawls erhalten Sie ausführliche Statistiken.
Diese Statistiken stehen im zurückgegebenen Objekt CrawlResult, das alle nötigen Ergebnisse enthält:
result = QuotesSpider().start()
# Access scraped items
for item in result.items:
print(item["text"], "-", item["author"])
# Check statistics
print(f"Scraped {result.stats.items_scraped} items")
print(f"Made {result.stats.requests_count} requests")
print(f"Took {result.stats.elapsed_seconds:.1f} seconds")
# Did the crawl finish or was it paused?
print(f"Completed: {result.completed}")
Links folgen¶
Die meisten Crawls folgen Links über mehrere Seiten. Erstellen Sie mit response.follow() die Folgeanfragen:
from scrapling.spiders import Spider, Response
class QuotesSpider(Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com"]
async def parse(self, response: Response):
# Extract items from the current page
for quote in response.css("div.quote"):
yield {
"text": quote.css("span.text::text").get(""),
"author": quote.css("small.author::text").get(""),
}
# Follow the "next page" link
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse)
response.follow() verarbeitet relative URLs automatisch und verbindet sie mit der URL der aktuellen Seite. Standardmäßig setzt es diese Seite auch als Wert des Headers Referer.
Für verschiedene Seitentypen können Sie Folgeanfragen an unterschiedliche Callback-Methoden senden:
async def parse(self, response: Response):
for link in response.css("a.product-link::attr(href)").getall():
yield response.follow(link, callback=self.parse_product)
async def parse_product(self, response: Response):
yield {
"name": response.css("h1::text").get(""),
"price": response.css(".price::text").get(""),
}
Note
Alle Callback-Methoden müssen asynchrone Generatoren sein und async def sowie yield verwenden.
Daten exportieren¶
Die in result.items zurückgegebene ItemList hat eingebaute Exportmethoden:
result = QuotesSpider().start()
# Export as JSON
result.items.to_json("quotes.json")
# Export as JSON with pretty-printing
result.items.to_json("quotes.json", indent=True)
# Export as JSON Lines (one JSON object per line)
result.items.to_jsonl("quotes.jsonl")
# Export as CSV or XML
result.items.to_csv("quotes.csv")
result.items.to_xml("quotes.xml")
Alle Methoden erstellen fehlende übergeordnete Verzeichnisse automatisch.
to_csv() schreibt eine Spalte für jeden Schlüssel, der in Ihren Datensätzen vorkommt. Datensätze dürfen also unterschiedliche Schlüssel haben; fehlende Zellen bleiben leer. Mit fields=[...] wählen Sie die Spalten und ihre Reihenfolge selbst, mit delimiter="\t" erstellen Sie eine TSV-Datei. to_xml() umschließt jeden Datensatz mit einem <item>-Element innerhalb des Wurzelelements <items>. Beide Namen können Sie mit root_tag und item_tag ändern.
In beiden Formaten werden Werte, die keine einfachen Skalare sind, etwa verschachtelte Dictionaries oder Listen, als JSON gespeichert. So gehen keine Daten unbemerkt verloren.
Domains filtern¶
Mit allowed_domains begrenzen Sie den Spider auf bestimmte Domains. So folgt er nicht versehentlich Links zu externen Websites:
class MySpider(Spider):
name = "my_spider"
start_urls = ["https://example.com"]
allowed_domains = {"example.com"}
async def parse(self, response: Response):
for link in response.css("a::attr(href)").getall():
# Links to other domains are silently dropped
yield response.follow(link, callback=self.parse)
Subdomains sind automatisch eingeschlossen. Mit allowed_domains = {"example.com"} erlauben Sie also auch sub.example.com, blog.example.com usw.
Ausgefilterte Anfragen werden in stats.offsite_requests_count gezählt. So sehen Sie, wie viele verworfen wurden.
robots.txt beachten¶
Setzen Sie robots_txt_obey = True, damit der Spider vor dem Abruf einer Domain deren robots.txt-Regeln beachtet:
class PoliteSpider(Spider):
name = "polite"
start_urls = ["https://example.com"]
robots_txt_obey = True
async def parse(self, response: Response):
for link in response.css("a::attr(href)").getall():
yield response.follow(link, callback=self.parse)
Wenn diese Option aktiv ist, führt der Spider folgende Schritte aus:
- robots.txt vorab abrufen: Vor dem Crawl lädt er die Dateien für alle Domains in
start_urlsparallel. - Jede Anfrage prüfen: Er prüft sie anhand der
Disallow-Regeln in der robots.txt der Domain. Nicht erlaubte Anfragen werden ohne Meldung verworfen und instats.robots_disallowed_countgezählt. - Die Vorgaben
Crawl-delayundRequest-ratebeachten: Er verwendet den höheren Wert aus der Vorgabe und Ihrem eingestelltendownload_delay. robots.txt kann Ihre Wartezeit somit nur erhöhen, niemals verkürzen. Wenn AutoThrottle aktiv ist, begrenzt dessen maximale Wartezeit auch diesen Wert. Setzen Sieautothrottle_max_delayhoch genug, um die geforderte Wartezeit einzuhalten.
robots.txt-Dateien werden über die Standardsitzung des Spiders abgerufen und für den gesamten Crawl pro Domain zwischengespeichert. Für Domains, die erst während des Crawls gefunden werden und nicht in start_urls stehen, wird die Datei bei der ersten Anfrage an diese Domain abgerufen.
Hinweis: robots_txt_obey ist standardmäßig ausgeschaltet, um unerwartetes Verhalten zu vermeiden. Wenn Sie es einschalten, bleiben Ihre Einstellungen für parallele Anfragen (concurrent_requests, concurrent_requests_per_domain) gleich. Nur die Wartezeit zwischen Anfragen wird angepasst.
Wenn Sie download_delay nicht selbst wählen möchten, setzen Sie autothrottle_enabled = True. Der Spider passt dann die Wartezeit je Domain an deren Antwortgeschwindigkeit an und wartet bei Sperren länger. Siehe AutoThrottle.
Nächste Schritte¶
Nachdem Sie die Grundlagen kennen, können Sie diese Themen ansehen:
- Anfragen und Antworten - Prioritäten, Vermeidung doppelter Anfragen, Metadaten und mehr.
- Sitzungen - Verschiedene Fetcher-Typen (HTTP, Browser, Stealth) in einem Spider verwenden.
- Proxys und Sperren - Proxys zwischen Anfragen wechseln und Sperren behandeln.
- Erweiterte Funktionen - Parallele Anfragen, AutoThrottle, Pausieren und Fortsetzen, Streaming, Lebenszyklus-Hooks und Protokollierung.