Der ultimative Leitfaden zum Erstellen skalierbarer Web Scraper mit Scrapy

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Scrapy ist ein beliebtes Open-Source-Python-Framework zum Schreiben skalierbarer Web Scraper. In diesem Tutorial führen wir Sie Schritt für Schritt durch die Verwendung von Scrapy, um eine Liste von Oscar-prämierten Filmen aus Wikipedia zu erstellen.

Web Scraping ist eine Möglichkeit, Daten von Websites abzurufen, ohne Zugriff auf APIs oder die Datenbank der Website zu benötigen. Sie benötigen nur Zugriff auf die Daten der Website – solange Ihr Browser auf die Daten zugreifen kann, können Sie sie auslesen.

Realistischerweise könnten Sie die meiste Zeit einfach manuell durch eine Website gehen und die Daten per Kopieren und Einfügen „von Hand“ abrufen, aber in vielen Fällen würde Sie das viele Stunden manueller Arbeit kosten, die Sie am Ende kosten könnte viel mehr, als die Daten wert sind, besonders wenn Sie jemanden eingestellt haben, der die Aufgabe für Sie erledigt. Warum jemanden einstellen, der 1–2 Minuten pro Abfrage arbeitet, wenn Sie ein Programm bekommen können, das alle paar Sekunden automatisch eine Abfrage durchführt?

Angenommen, Sie möchten eine Liste der Oscar-Preisträger für den besten Film zusammen mit ihrem Regisseur, den Hauptdarstellern, dem Veröffentlichungsdatum und der Laufzeit zusammenstellen. Wenn Sie Google verwenden, können Sie sehen, dass es mehrere Websites gibt, die diese Filme nach Namen und möglicherweise einigen zusätzlichen Informationen auflisten, aber im Allgemeinen müssen Sie Links folgen, um alle gewünschten Informationen zu erfassen.

Offensichtlich wäre es unpraktisch und zeitaufwändig, jeden Link von 1927 bis heute durchzugehen und manuell zu versuchen, die Informationen auf jeder Seite zu finden. Beim Web Scraping müssen wir nur eine Website mit Seiten finden, die all diese Informationen enthalten, und dann unser Programm mit den richtigen Anweisungen in die richtige Richtung lenken.

In diesem Tutorial verwenden wir Wikipedia als unsere Website, da sie alle Informationen enthält, die wir benötigen, und verwenden dann Scrapy on Python als Tool zum Scrapen unserer Informationen.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Ein paar Vorbehalte, bevor wir beginnen:

Data Scraping beinhaltet die Erhöhung der Serverlast für die Site, die Sie scrapen, was höhere Kosten für die Unternehmen bedeutet, die die Site hosten, und eine geringere Qualität für andere Benutzer dieser Site. Die Qualität des Servers, auf dem die Website läuft, die Datenmenge, die Sie zu erhalten versuchen, und die Rate, mit der Sie Anfragen an den Server senden, werden die Auswirkungen, die Sie auf den Server haben, moderieren. Vor diesem Hintergrund müssen wir sicherstellen, dass wir uns an einige Regeln halten.

Die meisten Websites haben auch eine Datei namens robots.txt in ihrem Hauptverzeichnis. Diese Datei legt Regeln dafür fest, auf welche Verzeichnisse Seiten Scraper nicht zugreifen sollen. Auf der Seite mit den Allgemeinen Geschäftsbedingungen einer Website erfahren Sie normalerweise, welche Richtlinien zum Data Scraping gelten. Beispielsweise enthält die Konditionsseite von IMDB die folgende Klausel:

Roboter und Screen Scraping: Sie dürfen Data Mining, Roboter, Screen Scraping oder ähnliche Tools zum Sammeln und Extrahieren von Daten auf dieser Website nicht verwenden, außer mit unserer ausdrücklichen schriftlichen Zustimmung, wie unten angegeben.

Bevor wir versuchen, die Daten einer Website zu erhalten, sollten wir immer die Bedingungen der Website und robots.txt überprüfen, um sicherzustellen, dass wir legale Daten erhalten. Beim Erstellen unserer Scraper müssen wir auch sicherstellen, dass wir einen Server nicht mit Anfragen überfordern, die er nicht verarbeiten kann.

Glücklicherweise erkennen viele Websites die Notwendigkeit für Benutzer, Daten zu erhalten, und stellen die Daten über APIs zur Verfügung. Wenn diese verfügbar sind, ist es normalerweise viel einfacher, Daten über die API zu erhalten als durch Scraping.

Wikipedia erlaubt Data Scraping, solange die Bots nicht „viel zu schnell“ sind, wie in ihrer robots.txt angegeben. Sie bieten auch herunterladbare Datensätze, damit Benutzer die Daten auf ihren eigenen Maschinen verarbeiten können. Wenn wir zu schnell gehen, blockieren die Server automatisch unsere IP, also implementieren wir Timer, um ihre Regeln einzuhalten.

Erste Schritte, Installation relevanter Bibliotheken mit Pip

Lassen Sie uns zunächst Scrapy installieren.

Windows

Installieren Sie die neueste Version von Python von https://www.python.org/downloads/windows/

Hinweis: Windows-Benutzer benötigen außerdem Microsoft Visual C++ 14.0, das Sie hier von „Microsoft Visual C++ Build Tools“ herunterladen können.

Sie sollten auch sicherstellen, dass Sie die neueste Version von Pip haben.

Geben Sie in cmd.exe Folgendes ein:

 python -m pip install --upgrade pip pip install pypiwin32 pip install scrapy

Dadurch werden Scrapy und alle Abhängigkeiten automatisch installiert.

Linux

Zuerst möchten Sie alle Abhängigkeiten installieren:

Geben Sie im Terminal Folgendes ein:

 sudo apt-get install python3 python3-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

Sobald das alles installiert ist, geben Sie einfach Folgendes ein:

 pip install --upgrade pip

Um sicherzustellen, dass Pip aktualisiert wird, und dann:

 pip install scrapy

Und es ist alles fertig.

Mac

Zuerst müssen Sie sicherstellen, dass Sie einen C-Compiler auf Ihrem System haben. Geben Sie im Terminal Folgendes ein:

 xcode-select --install

Installieren Sie danach Homebrew von https://brew.sh/.

Aktualisieren Sie Ihre PATH-Variable, sodass Homebrew-Pakete vor Systempaketen verwendet werden:

 echo "export PATH=/usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc source ~/.bashrc

Python installieren:

 brew install python

Und dann stellen Sie sicher, dass alles aktualisiert ist:

 brew update; brew upgrade python

Danach installieren Sie einfach Scrapy mit pip:

 pip install Scrapy
> ## Überblick über Scrapy, wie die Teile zusammenpassen, Parser, Spinnen usw

Sie werden ein Skript namens „Spider“ schreiben, das Scrapy ausführen soll, aber keine Sorge, Scrapy-Spinnen sind trotz ihres Namens überhaupt nicht beängstigend. Die einzige Ähnlichkeit, die Scrapy-Spinnen und echte Spinnen haben, ist, dass sie gerne im Netz kriechen.

Innerhalb der Spinne befindet sich eine von Ihnen definierte class , die Scrapy mitteilt, was zu tun ist. Zum Beispiel, wo mit dem Crawlen begonnen werden soll, welche Arten von Anfragen gestellt werden, wie Links auf Seiten gefolgt werden und wie Daten geparst werden. Sie können sogar benutzerdefinierte Funktionen hinzufügen, um Daten zu verarbeiten, bevor Sie sie wieder in eine Datei ausgeben.

## Schreiben Sie Ihre erste Spinne, schreiben Sie eine einfache Spinne, um praktisches Lernen zu ermöglichen

Um unsere erste Spinne zu starten, müssen wir zuerst ein Scrapy-Projekt erstellen. Geben Sie dazu Folgendes in Ihre Befehlszeile ein:

 scrapy startproject oscars

Dadurch wird ein Ordner mit Ihrem Projekt erstellt.

Wir beginnen mit einer einfachen Spinne. Der folgende Code ist in ein Python-Skript einzugeben. Öffnen Sie ein neues Python-Skript in /oscars/spiders und nennen Sie es oscars_spider.py

Wir werden Scrapy importieren.

 import scrapy

Dann beginnen wir mit der Definition unserer Spider-Klasse. Zuerst legen wir den Namen fest und dann die Domains, die der Spider schaben darf. Schließlich sagen wir der Spinne, wo sie mit dem Kratzen beginnen soll.

 class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ['https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture']

Als nächstes brauchen wir eine Funktion, die die gewünschten Informationen erfasst. Im Moment nehmen wir nur den Seitentitel. Wir verwenden CSS, um das Tag zu finden, das den Titeltext trägt, und extrahieren es dann. Schließlich geben wir die Informationen an Scrapy zurück, damit sie protokolliert oder in eine Datei geschrieben werden.

 def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Speichern Sie nun den Code in /oscars/spiders/oscars_spider.py

Um diese Spinne auszuführen, gehen Sie einfach zu Ihrer Befehlszeile und geben Sie Folgendes ein:

 scrapy crawl oscars

Sie sollten eine Ausgabe wie diese sehen:

 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished)

Herzlichen Glückwunsch, Sie haben Ihren ersten einfachen Scrapy-Schaber gebaut!

Vollständiger Code:

 import scrapy class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Natürlich möchten wir, dass es ein bisschen mehr leistet, also schauen wir uns an, wie Scrapy zum Analysieren von Daten verwendet wird.

Machen wir uns zunächst mit der Scrapy-Shell vertraut. Die Scrapy-Shell kann Ihnen helfen, Ihren Code zu testen, um sicherzustellen, dass Scrapy die gewünschten Daten erfasst.

Um auf die Shell zuzugreifen, geben Sie Folgendes in Ihre Befehlszeile ein:

 scrapy shell “https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture”

Dadurch wird im Grunde die Seite geöffnet, auf die Sie es geleitet haben, und Sie können einzelne Codezeilen ausführen. Beispielsweise können Sie den Roh-HTML-Code der Seite anzeigen, indem Sie Folgendes eingeben:

 print(response.text)

Oder öffnen Sie die Seite in Ihrem Standardbrowser, indem Sie Folgendes eingeben:

 view(response)

Unser Ziel hier ist es, den Code zu finden, der die gewünschten Informationen enthält. Lassen Sie uns zunächst versuchen, nur die Namen der Filmtitel zu erfassen.

Der einfachste Weg, den benötigten Code zu finden, besteht darin, die Seite in unserem Browser zu öffnen und den Code zu untersuchen. In diesem Beispiel verwende ich Chrome DevTools. Klicken Sie einfach mit der rechten Maustaste auf einen beliebigen Filmtitel und wählen Sie „Inspizieren“:

Verwenden von Chrome DevTools zum Überprüfen von HTML und CSS
Chrome DevTools-Fenster. (Große Vorschau)

Wie Sie sehen können, haben die Oscar-Gewinner einen gelben Hintergrund, während die Nominierten einen einfachen Hintergrund haben. Es gibt auch einen Link zum Artikel über den Filmtitel, und die Links für Filme enden mit film) . Jetzt, da wir das wissen, können wir einen CSS-Selektor verwenden, um die Daten zu erfassen. Geben Sie in der Scrapy-Shell Folgendes ein:

 response.css(r"tr[] a[href*='film)']").extract()

Wie Sie sehen können, haben Sie jetzt eine Liste aller Oscar-Gewinner für den besten Film!

 > response.css(r"tr[] a[href*='film']").extract() ['<a href="/wiki/Wings_(1927_film)" title="Wings (1927 film)">Wings</a>', ... '<a href="/wiki/Green_Book_(film)" title="Green Book (film)">Green Book</a>', '<a href="/wiki/Jim_Burke_(film_producer)" title="Jim Burke (film producer)">Jim Burke</a>']

Zurück zu unserem Hauptziel: Wir möchten eine Liste der Oscar-Gewinner für den besten Film zusammen mit ihrem Regisseur, den Hauptdarstellern, dem Veröffentlichungsdatum und der Laufzeit. Dazu benötigen wir Scrapy, um Daten von jeder dieser Filmseiten zu erfassen.

Wir müssen ein paar Dinge umschreiben und eine neue Funktion hinzufügen, aber keine Sorge, es ist ziemlich einfach.

Wir beginnen damit, den Scraper auf die gleiche Weise wie zuvor zu initiieren.

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"]

Aber dieses Mal werden sich zwei Dinge ändern. Zuerst importieren wir time zusammen mit scrapy , weil wir einen Timer erstellen möchten, um zu beschränken, wie schnell der Bot scrapt. Wenn wir die Seiten zum ersten Mal analysieren, möchten wir außerdem nur eine Liste der Links zu jedem Titel erhalten, damit wir stattdessen Informationen von diesen Seiten abrufen können.

 def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req

Hier machen wir eine Schleife, um nach jedem Link auf der Seite zu suchen, film) mit dem gelben Hintergrund darin endet, und dann fügen wir diese Links zu einer Liste von URLs zusammen, die wir an die Funktion parse_titles senden, um sie weiterzugeben. Wir fügen auch einen Timer ein, damit er nur alle 5 Sekunden Seiten anfordert. Denken Sie daran, dass wir die Scrapy-Shell verwenden können, um unsere response.css -Felder zu testen, um sicherzustellen, dass wir die richtigen Daten erhalten!

 def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Die eigentliche Arbeit wird in unserer Funktion parse_data erledigt, wo wir ein Wörterbuch namens data erstellen und dann jeden Schlüssel mit den gewünschten Informationen füllen. Auch hier wurden alle diese Selektoren wie zuvor gezeigt mit Chrome DevTools gefunden und dann mit der Scrapy-Shell getestet.

Die letzte Zeile gibt das Datenwörterbuch zum Speichern an Scrapy zurück.

Vollständiger Code:

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Manchmal möchten wir Proxys verwenden, da Websites versuchen, unsere Scraping-Versuche zu blockieren.

Dazu müssen wir nur ein paar Dinge ändern. In unserem Beispiel müssen wir es in unserem def parse() wie folgt ändern:

 def parse(self, response): for href in (r"tr[] a[href*='film)']::attr(href)").extract() : url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) req.meta['proxy'] = "https://yourproxy.com:80" yield req

Dadurch werden die Anfragen über Ihren Proxy-Server geleitet.

Bereitstellung und Protokollierung, zeigen, wie man einen Spider in der Produktion tatsächlich verwaltet

Jetzt ist es Zeit, unsere Spinne laufen zu lassen. Um Scrapy mit dem Scrapen zu beginnen und dann in eine CSV-Datei auszugeben, geben Sie Folgendes in Ihre Eingabeaufforderung ein:

 scrapy crawl oscars -o oscars.csv

Sie sehen eine große Ausgabe, und nach ein paar Minuten ist sie abgeschlossen und Sie haben eine CSV-Datei in Ihrem Projektordner.

Ergebnisse kompilieren, zeigen, wie die in den vorherigen Schritten zusammengestellten Ergebnisse verwendet werden

Wenn Sie die CSV-Datei öffnen, sehen Sie alle gewünschten Informationen (sortiert nach Spalten mit Überschriften). Es ist wirklich so einfach.

Eine CSV-Datei mit Oscar-prämierten Filmen und zugehörigen Informationen
Liste und Informationen zu Oscar-prämierten Filmen. (Große Vorschau)

Mit Data Scraping können wir fast jeden benutzerdefinierten Datensatz erhalten, den wir wollen, solange die Informationen öffentlich verfügbar sind. Was Sie mit diesen Daten machen möchten, bleibt Ihnen überlassen. Diese Fähigkeit ist äußerst nützlich, um Marktforschung zu betreiben, Informationen auf einer Website auf dem neuesten Stand zu halten und vieles mehr.

Es ist ziemlich einfach, Ihren eigenen Web Scraper einzurichten, um selbst benutzerdefinierte Datensätze zu erhalten, aber denken Sie immer daran, dass es möglicherweise andere Möglichkeiten gibt, die benötigten Daten zu erhalten. Unternehmen investieren viel in die Bereitstellung der von Ihnen gewünschten Daten, daher ist es nur fair, dass wir ihre Geschäftsbedingungen respektieren.

Zusätzliche Ressourcen, um mehr über Scrapy und Web Scraping im Allgemeinen zu erfahren

  • Die offizielle Scrapy-Website
  • Scrapys GitHub-Seite
  • „Die 10 besten Data Scraping Tools und Web Scraping Tools“, Scraper API
  • „5 Tipps für Web Scraping, ohne blockiert oder auf die schwarze Liste gesetzt zu werden“, Scraper API
  • Parsel, eine Python-Bibliothek zur Verwendung regulärer Ausdrücke zum Extrahieren von Daten aus HTML.