In diesem Artikel erfahren Sie:
- Die Hauptursachen für einen langsamen Web-Scraping-Prozess
- Verschiedene Techniken zur Beschleunigung des Web-Scraping
- Wie Sie ein Beispiel-Python-Scraping-Skript für eine schnellere Datenabfrage optimieren können
Lassen Sie uns loslegen!
Gründe für einen langsamen Scraping-Prozess
Entdecken Sie die wichtigsten Gründe, warum Ihr Web-Scraping-Prozess langsam sein könnte.
Grund Nr. 1: Langsame Serverantworten
Einer der wichtigsten Faktoren, die Ihre Web-Scraping-Geschwindigkeit beeinflussen, ist die Server-Reaktionszeit. Wenn Sie eine Anfrage an eine Website senden, verarbeitet der Server Ihre Anfrage und antwortet darauf. Wenn der Server langsam ist, dauert die Bearbeitung Ihrer Anfragen länger. Gründe für einen langsamen Server sind hoher Traffic, begrenzte Ressourcen oder Netzwerkverlangsamungen.
Leider können Sie wenig tun, um einen Zielserver zu beschleunigen. Das liegt außerhalb Ihrer Kontrolle, es sei denn, die Verlangsamung ist auf eine überwältigende Anzahl von Anfragen Ihrerseits zurückzuführen. Wenn dies der Fall ist, verteilen Sie Ihre Anfragen über einen längeren Zeitraum, indem Sie zufällige Verzögerungen zwischen ihnen einfügen.
Grund Nr. 2: Langsame CPU-Verarbeitung
Die CPU-Verarbeitungsgeschwindigkeit spielt eine entscheidende Rolle dabei, wie schnell Ihre Scraping-Skripte arbeiten können. Wenn Sie Ihre Skripte nacheinander ausführen, muss Ihre CPU jede Operation einzeln verarbeiten, was zeitaufwändig sein kann. Dies macht sich besonders bemerkbar, wenn Ihre Skripte komplexe Berechnungen oder Datenumwandlungen beinhalten.
Darüber hinaus nimmt das Parsing von HTML einige Zeit in Anspruch und kann Ihren Scraping-Prozess erheblich verlangsamen. Weitere Informationen finden Sie in unserem Artikel über HTML-Web-Scraping.
Grund Nr. 3: Begrenzte E/A-Operationen
Eingabe-/Ausgabeoperationen (I/O) können leicht zum Engpass Ihres Scraping-Vorgangs werden. Dies gilt insbesondere dann, wenn Ihre Zielwebsite aus mehreren Seiten besteht. Wenn Ihr Skript so konzipiert ist, dass es auf Antworten von externen Ressourcen wartet, bevor es fortfährt, kann dies zu erheblichen Verzögerungen führen.
Das Senden einer Anfrage, das Warten auf die Antwort des Servers, die Verarbeitung dieser Antwort und das Weiterleiten zur nächsten Anfrage ist keine effiziente Methode für das Web-Scraping.
Weitere Gründe
Weitere Gründe, die Ihr Web-Scraping-Skript verlangsamen, sind:
- Ineffizienter Code: Eine schlecht optimierte Scraping-Logik kann den gesamten Scraping-Prozess verlangsamen. Vermeiden Sie ineffiziente Datenstrukturen, unnötige Schleifen oder übermäßige Protokollierung.
- Ratenbegrenzung: Wenn die Zielwebsite die Anzahl der Anfragen begrenzt, die ein Benutzer in einem bestimmten Zeitraum stellen kann, wird Ihr automatisierter Scraper dadurch verlangsamt. Die Lösung? Proxy-Dienste!
- CAPTCHAs und andere Anti-Scraping-Lösungen: CAPTCHAs und Anti-Bot-Maßnahmen können Ihren Scraping-Prozess unterbrechen, da sie eine Benutzerinteraktion erfordern. Entdecken Sie weitere Anti-Scraping-Techniken.
Techniken zur Beschleunigung des Web-Scrapings
In diesem Abschnitt lernen Sie die beliebtesten Methoden zur Beschleunigung des Web-Scrapings kennen. Wir beginnen mit einem einfachen Python-Scraping-Skript und zeigen Ihnen, wie sich verschiedene Optimierungen darauf auswirken.
Hinweis: Die hier vorgestellten Techniken funktionieren mit jeder Programmiersprache oder Technologie. Python wird nur der Einfachheit halber verwendet und weil es eine der besten Programmiersprachen für das Web-Scraping ist.
Dies ist das ursprüngliche Python-Skript zum Scraping:
import requests
from bs4 import BeautifulSoup
import csv
import time
def scrape_quotes_to_scrape():
# Array mit den URLs der zu scrapendenden Seite
urls = [
"http://quotes.toscrape.com/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
"https://quotes.toscrape.com/page/4/",
"https://quotes.toscrape.com/page/5/",
"https://quotes.toscrape.com/page/6/",
"https://quotes.toscrape.com/page/7/",
„https://quotes.toscrape.com/page/8/”,
„https://quotes.toscrape.com/page/9/”,
„https://quotes.toscrape.com/page/10/”
]
# wo die gescrapten Daten gespeichert werden sollen
quotes = []
# Seiten nacheinander scrapen
for url in urls:
print(f"Seite scrapen: '{url}'")
# GET-Anfrage senden, um den HTML-Code der Seite abzurufen
response = requests.get(url)
# HTML-Code der Seite mit BeautifulSoup parsen
soup = BeautifulSoup(response.content, "html.parser")
# alle Zitat-Elemente auf der Seite auswählen
quote_html_elements = soup.select(".quote")
# die Zitat-Elemente durchlaufen und ihren Inhalt scrapen
for quote_html_element in quote_html_elements:
# den Text des Zitats extrahieren
text = quote_html_element.select_one(".text").get_text()
# extrahiere den Autor des Zitats
author = quote_html_element.select_one(".author").get_text()
# extrahiere Tags, die mit dem Zitat verbunden sind
tags = [tag.get_text() for tag in quote_html_element.select(".tag")]
# fülle ein neues Zitat-Objekt und füge es zur Liste hinzu
quote = {
"text": text,
"author": author,
"tags": ", ".join(tags)
}
quotes.append(quote)
print(f"Seite '{url}' erfolgreich gecrawltn")
print("Gecrawlte Daten werden in CSV exportiert")
# exportiere die gescraped Zitate in eine CSV-Datei
with open("quotes.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["text", "author", "tags"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(quotes)
print("Zitate in CSV exportiertn")
# Ausführungszeit messen
start_time = time.time()
scrape_quotes_to_scrape()
end_time = time.time()
execution_time = end_time - start_time
print(f"Ausführungszeit: {execution_time:.2f} Sekunden")
Der oben genannte Scraper zielt auf 10 paginierte URLs der Website „Quotes to Scrape” ab. Für jede URL führt das Skript die folgenden Operationen aus:
- Es sendet eine GET-Anfrage mit
„requests“, um den HTML-Code der Seite abzurufen. - Es führt das Parsing des HTML-Inhalts mit
BeautifulSoupaus. - Extrahiert den Zitattext, den Autor und die Tags für jedes Zitat-Element auf der Seite.
- Speichert die gescrapten Daten in einer Liste von Wörterbüchern.
Schließlich exportiert es die gescrapten Daten in eine CSV-Datei namens quotes.csv.
Um das Skript auszuführen, installieren Sie die erforderlichen Bibliotheken mit:
pip install requests beautifulsoup4
Der Aufruf der Funktion scrape_quotes_to_scrape() wird mit time.time() -Aufrufen umschlossen, um zu messen, wie lange der Scraping-Prozess dauert. Auf unserem Rechner dauert die Ausführung des ursprünglichen Skripts etwa 4,51 Sekunden.
Durch Ausführen des Skripts wird eine Datei namens quotes.csv in Ihrem Projektordner erstellt. Zusätzlich werden Protokolle angezeigt, die in etwa wie folgt aussehen:
Scraping page: 'http://quotes.toscrape.com/'
Page 'http://quotes.toscrape.com/' scraped successfully
Scraping page: 'https://quotes.toscrape.com/page/2/'
Page 'https://quotes.toscrape.com/page/2/' scraped successfully
Scraping page: 'https://quotes.toscrape.com/page/3/'
Page 'https://quotes.toscrape.com/page/3/' scraped successfully
Scraping page: 'https://quotes.toscrape.com/page/4/'
Seite „https://quotes.toscrape.com/page/4/” erfolgreich gecrawlt
Crawling der Seite: „https://quotes.toscrape.com/page/5/”
Seite „https://quotes.toscrape.com/page/5/” erfolgreich gecrawlt
Seite wird gescrapt: 'https://quotes.toscrape.com/page/6/'
Seite 'https://quotes.toscrape.com/page/6/' erfolgreich gescrapt
Seite wird gescrapt: 'https://quotes.toscrape.com/page/7/'
Seite „https://quotes.toscrape.com/page/7/” erfolgreich gecrawlt
Crawling der Seite: „https://quotes.toscrape.com/page/8/”
Seite „https://quotes.toscrape.com/page/8/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/9/” wird gescrapt
Seite „https://quotes.toscrape.com/page/9/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/10/” wird gescrapt
Seite „https://quotes.toscrape.com/page/10/” erfolgreich gecrawlt
Exportieren der gecrawlten Daten in CSV
Zitate in CSV exportiert
Ausführungszeit: 4,63 Sekunden
Diese Ausgabe zeigt deutlich, dass das Skript jede paginierte Webseite von „Quotes to Scrape” nacheinander scrapt. Wie Sie gleich sehen werden, können einige Optimierungen den Ablauf und die Geschwindigkeit dieses Prozesses erheblich verändern.
Nun wollen wir herausfinden, wie man das Web-Scraping beschleunigen kann!
1. Verwenden Sie eine schnellere HTML-Parsing-Bibliothek
Das Parsing von Daten kostet Zeit und Ressourcen, und verschiedene HTML-Parser verwenden unterschiedliche Ansätze, um diese Aufgabe zu erfüllen. Einige konzentrieren sich darauf, einen umfangreichen Funktionsumfang mit einer selbstbeschreibenden API bereitzustellen, während andere der Leistung Vorrang einräumen. Weitere Informationen finden Sie in unserem Leitfaden zu den besten HTML-Parsern.
In Python ist Beautiful Soup der beliebteste HTML-Parser, aber nicht unbedingt der schnellste. Weitere Informationen finden Sie in einigen Benchmarks.
In Wirklichkeit fungiert Beautiful Soup lediglich als Wrapper für verschiedene zugrunde liegende Parser. Sie können den gewünschten Parser bei der Initialisierung über das zweite Argument angeben:
soup = BeautifulSoup(response.content, "html.parser")
Im Allgemeinen wird Beautiful Soup in Kombination mit html.parser verwendet, dem integrierten Parser aus der Standardbibliothek von Python. Wenn Sie jedoch Wert auf Geschwindigkeit legen, sollten Sie lxml in Betracht ziehen. Dies ist einer der schnellsten HTML-Parser, die in Python verfügbar sind, da er auf einer C-Implementierung basiert.
Um lxml zu installieren, führen Sie den folgenden Befehl aus:
pip install lxml
Nach der Installation können Sie es wie folgt mit Beautiful Soup verwenden:
soup = BeautifulSoup(response.content, "lxml")
Führen Sie nun Ihr Python-Scraping-Skript erneut aus. Dieses Mal sollten Sie die folgende Ausgabe sehen:
# der Kürze halber ausgelassen...
Ausführungszeit: 4,35 Sekunden
Die Ausführungszeit sank von 4,61 Sekunden auf 4,35 Sekunden. Diese Änderung mag zwar gering erscheinen, aber die Auswirkungen dieser Optimierung hängen stark von der Größe und Komplexität der zu parsenden HTML-Seiten und der Anzahl der ausgewählten Elemente ab.
In diesem Beispiel hat die Zielwebsite Seiten mit einer einfachen, kurzen und flachen DOM-Struktur. Dennoch ist eine Geschwindigkeitssteigerung von etwa 6 % durch eine kleine Codeänderung ein lohnender Gewinn!
👍 Vorteile:
- Einfach in Beautiful Soup zu implementieren
👎 Nachteile:
- Geringer Vorteil
- Funktioniert nur auf Seiten mit komplexen DOM-Strukturen
- Schnellere HTML-Parser haben möglicherweise eine komplexere API
2. Implementierung von Multiprocessing-Scraping
Multiprocessing ist ein Ansatz zur parallelen Ausführung, bei dem ein Programm mehrere Prozesse erzeugt. Jeder dieser Prozesse läuft parallel und unabhängig auf einem CPU-Kern, um Aufgaben gleichzeitig statt nacheinander auszuführen.
Diese Methode ist besonders vorteilhaft für I/O-gebundene Vorgänge wie Web-Scraping. Der Grund dafür ist, dass der primäre Engpass oft die Zeit ist, die mit dem Warten auf Antworten von Webservern verbracht wird. Durch die Verwendung mehrerer Prozesse können Sie Anfragen gleichzeitig an mehrere Seiten senden und so die Gesamtzeit für das Scraping reduzieren.
Um Ihr Scraping-Skript für Multiprocessing anzupassen, müssen Sie einige wichtige Änderungen an der Ausführungslogik vornehmen. Befolgen Sie die folgenden Schritte, um Ihren Python-Scraper von einem sequenziellen zu einem Multiprocessing-Ansatz umzustellen.
Um mit Multiprocessing in Python zu beginnen, müssen Sie zunächst Pool und cpu_count aus dem Multiprocessing -Modul importieren:
from multiprocessing import Pool, cpu_count
Pool bietet Ihnen alles, was Sie zur Verwaltung eines Pools von Worker-Prozessen benötigen. Mit cpu_count können Sie hingegen die Anzahl der für die parallele Verarbeitung verfügbaren CPU-Kerne ermitteln.
Isolieren Sie als Nächstes die Logik zum Scrapen einer einzelnen URL innerhalb einer Funktion:
def scrape_page(url):
print(f"Scraping page: '{url}'")
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
quote_html_elements = soup.select(".quote")
quotes = []
for quote_html_element in quote_html_elements:
text = quote_html_element.select_one(".text").get_text()
author = quote_html_element.select_one(".author").get_text()
tags = [tag.get_text() for tag in quote_html_element.select(".tag")]
quotes.append({
"text": text,
"author": author,
"tags": ", ".join(tags)
})
print(f"Seite '{url}' erfolgreich gescraptn")
return quotes
Die obige Funktion wird von jedem Worker-Prozess aufgerufen und jeweils auf einem CPU-Kern ausgeführt.
Ersetzen Sie dann den sequenziellen Scraping-Ablauf durch eine Multiprocessing-Logik:
def scrape_quotes():
urls = [
"http://quotes.toscrape.com/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
„https://quotes.toscrape.com/page/4/”,
„https://quotes.toscrape.com/page/5/”,
„https://quotes.toscrape.com/page/6/”,
„https://quotes.toscrape.com/page/7/”,
„https://quotes.toscrape.com/page/8/”,
„https://quotes.toscrape.com/page/9/”,
„https://quotes.toscrape.com/page/10/”
]
# Erstellen eines Prozesspools
with Pool(processes=cpu_count()) as pool:
results = pool.map(scrape_page, urls)
# Glätten der Ergebnisliste
quotes = [quote for sublist in results for quote in sublist]
print("Exportieren der gescrapten Daten in CSV")
with open("quotes_multiprocessing.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["text", "author", "tags"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(Zitate)
print("Zitate in CSV exportiert")
Führen Sie abschließend die Funktion scrape_quotes() aus und messen Sie dabei die Ausführungszeit:
if __name__ == "__main__":
start_time = time.time()
scrape_quotes()
end_time = time.time()
execution_time = end_time - start_time
print(f"Ausführungszeit: {execution_time:.2f} Sekunden")
Beachten Sie, dass die Konstruktion if __name__ == "__main__": erforderlich ist, um zu verhindern, dass bestimmte Teile Ihres Codes beim Importieren des Moduls ausgeführt werden. Ohne diese Überprüfung versucht das Multiprocessing-Modul möglicherweise, neue Prozesse zu starten, was insbesondere unter Windows zu unerwartetem Verhalten führen kann.
Wenn Sie alles zusammenfügen, erhalten Sie:
from multiprocessing import Pool, cpu_count
import requests
from bs4 import BeautifulSoup
import csv
import time
def scrape_page(url):
print(f"Scraping page: '{url}'")
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
quote_html_elements = soup.select(".quote")
quotes = []
for quote_html_element in quote_html_elements:
text = quote_html_element.select_one(".text").get_text()
author = quote_html_element.select_one(".author").get_text()
tags = [tag.get_text() for tag in quote_html_element.select(".tag")]
quotes.append({
"text": text,
"author": author,
"tags": ", ".join(tags)
})
print(f"Seite '{url}' erfolgreich gescraptn")
return quotes
def scrape_quotes():
urls = [
"http://quotes.toscrape.com/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
"https://quotes.toscrape.com/page/4/",
"https://quotes.toscrape.com/page/5/",
"https://quotes.toscrape.com/page/6/",
"https://quotes.toscrape.com/page/7/",
„https://quotes.toscrape.com/page/8/”,
„https://quotes.toscrape.com/page/9/”,
„https://quotes.toscrape.com/page/10/”
]
# Erstellen eines Prozesspools
with Pool(processes=cpu_count()) as pool:
results = pool.map(scrape_page, urls)
# Glätten der Ergebnisliste
quotes = [quote for sublist in results for quote in sublist]
print("Exportieren der gescrapten Daten in CSV")
with open("quotes_multiprocessing.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["text", "author", "tags"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(quotes)
print("Zitate nach CSV exportiert")
if __name__ == "__main__":
start_time = time.time()
scrape_quotes()
end_time = time.time()
execution_time = end_time - start_time
print(f"Ausführungszeit: {execution_time:.2f} Sekunden")
Führen Sie das Skript erneut aus. Dieses Mal werden folgende Protokolle erstellt:
Scraping page: 'http://quotes.toscrape.com/'
Scraping page: 'https://quotes.toscrape.com/page/2/'
Scraping page: 'https://quotes.toscrape.com/page/3/'
Scraping page: 'https://quotes.toscrape.com/page/4/'
Scraping-Seite: 'https://quotes.toscrape.com/page/5/'
Scraping-Seite: 'https://quotes.toscrape.com/page/6/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/7/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/8/'
Seite 'http://quotes.toscrape.com/' erfolgreich gescrapt
Seite wird gescrapt: 'https://quotes.toscrape.com/page/9/'
Seite „https://quotes.toscrape.com/page/3/” erfolgreich gescrapt
Scraping-Seite: „https://quotes.toscrape.com/page/10/”
Seite „https://quotes.toscrape.com/page/4/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/5/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/6/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/7/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/2/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/8/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/9/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/10/” erfolgreich gecrawlt
Exportieren der gecrawlten Daten in CSV
Zitate in CSV exportiert
Ausführungszeit: 1,87 Sekunden
Wie Sie sehen können, ist die Ausführungsreihenfolge nicht mehr sequenziell. Ihr Skript kann nun mehrere Seiten gleichzeitig scrapen. Genauer gesagt kann es bis zu der Anzahl der auf Ihrer CPU verfügbaren Kerne (in unserem Fall 8) scrapen.
Die parallele Verarbeitung führt zu einer Zeitersparnis von rund 145 % und reduziert die Ausführungszeit von 4,61 Sekunden auf 1,87 Sekunden. Das ist beeindruckend!
👍 Vorteile:
- Deutliche Verbesserung der Ausführungszeit
- Von den meisten Programmiersprachen nativ unterstützt
👎 Nachteile:
- Begrenzt durch die Anzahl der auf Ihrem Rechner verfügbaren Kerne
- Die Reihenfolge der URLs in der Liste wird nicht berücksichtigt
- Erfordert viele Änderungen am Code
3. Implementieren Sie Multithreading-Scraping
Multithreading ist eine Programmiertechnik, mit der mehrere Threads gleichzeitig innerhalb eines einzigen Prozesses ausgeführt werden können. Dadurch kann Ihr Skript mehrere Aufgaben gleichzeitig ausführen, wobei jede Aufgabe von einem dedizierten Thread verarbeitet wird.
Multithreading ähnelt zwar dem Multiprocessing, erfordert jedoch nicht unbedingt mehrere CPU-Kerne. Der Grund dafür ist, dass ein einzelner CPU-Kern zahlreiche Threads gleichzeitig ausführen kann, die sich denselben Speicherplatz teilen. Vertiefen Sie dieses Konzept in unserem Leitfaden zu Gleichzeitigkeit vs. Parallelität.
Beachten Sie, dass die Umwandlung eines Scraping-Skripts von einem sequenziellen Ansatz zu einem Multithreading-Ansatz ähnliche Änderungen erfordert wie die im vorherigen Kapitel beschriebenen.
In dieser Implementierung verwenden wir ThreadPoolExecutor aus dem Python-Modul concurrent.futures. Sie können es wie folgt importieren:
from concurrent.futures import ThreadPoolExecutor
ThreadPoolExecutor bietet eine hochentwickelte Schnittstelle zur Verwaltung eines Pools von Threads, die gleichzeitig für Sie ausgeführt werden.
Beginnen Sie wie zuvor damit, die Logik zum Scraping einer einzelnen URL in eine Funktion zu isolieren, genau wie im vorherigen Kapitel. Der wesentliche Unterschied besteht darin, dass Sie nun ThreadPoolExecutor verwenden müssen, um die Funktion in mehreren Threads auszuführen:
quotes = []
# Erstellen Sie einen Thread-Pool mit bis zu 10 Arbeitern.
with ThreadPoolExecutor(max_workers=10) as executor:
# Verwenden Sie map, um die Funktion scrape_page auf jede URL anzuwenden.
results = executor.map(scrape_page, urls)
# Kombinieren Sie die Ergebnisse aller Threads.
for result in results:
quotes.extend(result)
Wenn max_workers None ist oder nicht angegeben wird, wird standardmäßig die Anzahl der Prozessoren auf Ihrem Rechner mit 5 multipliziert. In diesem Fall haben wir nur 10 Seiten, daher ist die Einstellung 10 in Ordnung. Vergessen Sie nicht, dass das Öffnen zu vieler Threads Ihr System verlangsamen und zu Leistungseinbußen statt zu Verbesserungen führen kann.
Das gesamte Scraping-Skript enthält den folgenden Code:
from concurrent.futures import ThreadPoolExecutor
import requests
from bs4 import BeautifulSoup
import csv
import time
def scrape_page(url):
print(f"Scraping page: '{url}'")
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
quote_html_elements = soup.select(".quote")
quotes = []
for quote_html_element in quote_html_elements:
text = quote_html_element.select_one(".text").get_text()
author = quote_html_element.select_one(".author").get_text()
tags = [tag.get_text() for tag in quote_html_element.select(".tag")]
quotes.append({
"text": text,
"author": author,
"tags": ", ".join(tags)
})
print(f"Seite '{url}' erfolgreich gescraptn")
return quotes
def scrape_quotes():
urls = [
"http://quotes.toscrape.com/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
"https://quotes.toscrape.com/page/4/",
"https://quotes.toscrape.com/page/5/",
"https://quotes.toscrape.com/page/6/",
"https://quotes.toscrape.com/page/7/",
„https://quotes.toscrape.com/page/8/”,
„https://quotes.toscrape.com/page/9/”,
„https://quotes.toscrape.com/page/10/”
]
# wo die gescrapten Daten gespeichert werden sollen
quotes = []
# Erstellen eines Thread-Pools mit bis zu 10 Arbeitern
with ThreadPoolExecutor(max_workers=10) as executor:
# Verwenden von map, um die Funktion scrape_page auf jede URL anzuwenden
results = executor.map(scrape_page, urls)
# Kombinieren der Ergebnisse aus allen Threads
for result in results:
quotes.extend(result)
print("Exportieren der gescrapten Daten in CSV")
with open("quotes_multiprocessing.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["text", "author", "tags"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(quotes)
print("Zitate in CSV exportiert")
if __name__ == "__main__":
start_time = time.time()
scrape_quotes()
end_time = time.time()
execution_time = end_time - start_time
print(f"Ausführungszeit: {execution_time:.2f} Sekunden")
Starten Sie das Programm, und es werden folgende Meldungen protokolliert:
Scraping page: 'http://quotes.toscrape.com/'
Scraping page: 'https://quotes.toscrape.com/page/2/'
Scraping page: 'https://quotes.toscrape.com/page/3/'
Scraping page: 'https://quotes.toscrape.com/page/4/'
Scraping-Seite: 'https://quotes.toscrape.com/page/5/'
Scraping-Seite: 'https://quotes.toscrape.com/page/6/'
Scraping-Seite: 'https://quotes.toscrape.com/page/7/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/8/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/9/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/10/'
Seite „http://quotes.toscrape.com/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/6/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/7/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/10/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/8/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/5/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/9/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/4/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/3/” erfolgreich gescrapt
Seite „https://quotes.toscrape.com/page/2/” erfolgreich gescrapt
Exportieren der gescrapten Daten in CSV
Zitate in CSV exportiert
Ausführungszeit: 0,52 Sekunden
Ähnlich wie beim Multiprocessing-Scraping ist die Ausführungsreihenfolge der Seiten nicht mehr sequenziell. Diesmal ist die Leistungssteigerung sogar noch größer als beim Multiprocessing. Das liegt daran, dass das Skript nun 10 Anfragen gleichzeitig ausführen kann und damit die bisherige Grenze von 8 Anfragen (die Anzahl der CPU-Kerne) überschreitet.
Die Zeitersparnis ist enorm: von 4,61 Sekunden auf 0,52 Sekunden, was einer prozentualen Reduzierung von rund 885 % entspricht!
👍 Vorteile:
- Enorme Verbesserung der Ausführungszeit
- Von den meisten Technologien nativ unterstützt
👎 Nachteile:
- Es ist nicht einfach, die richtige Anzahl von Threads zu finden
- Die Reihenfolge der URLs in der Liste wird nicht berücksichtigt
- Erfordert viele Änderungen am Code
4. Verwendung von Async/Await Scraping
Asynchrone Programmierung ist ein modernes Programmierparadigma, mit dem Sie nicht blockierenden Code schreiben können. Die Idee dahinter ist, Entwicklern die Möglichkeit zu geben, gleichzeitige Vorgänge zu verarbeiten, ohne Multithreading oder Multiprocessing explizit verwalten zu müssen.
Bei einem traditionellen synchronen Ansatz muss jeder Vorgang beendet sein, bevor der nächste beginnen kann. Dies kann zu Ineffizienzen führen, insbesondere bei I/O-gebundenen Aufgaben wie Web-Scraping. Mit asynchroner Programmierung können Sie mehrere I/O-Vorgänge gleichzeitig initiieren und dann auf deren Abschluss warten. Dadurch bleibt Ihr Skript reaktionsschnell und effizient.
In Python wird asynchrones Scraping in der Regel mit dem Modul „asyncio” aus der Standardbibliothek implementiert. Dieses Paket bietet die Infrastruktur zum Schreiben von Single-Thread-Parallelcode mit Coroutinen über die Schlüsselwörter „async ” und „await ”.
Standard-HTTP-Bibliotheken wie requests unterstützen jedoch keine asynchronen Operationen. Daher müssen Sie einen asynchronen HTTP-Client wie AIOHTTP verwenden, der speziell für die nahtlose Zusammenarbeit mit asyncio entwickelt wurde. Diese Kombination hilft Ihnen, mehrere HTTP-Anfragen gleichzeitig zu senden, ohne die Ausführung Ihres Skripts zu blockieren.
Installieren Sie AIOHTTP mit dem folgenden Befehl:
pip install aiohttp
Importieren Sie anschließend asyncio und aiohttp:
import asyncio
import aiohttp
Wie in den vorherigen Kapiteln kapseln Sie die Logik zum Scraping einer einzelnen URL in einer Funktion. Dieses Mal ist die Funktion jedoch asynchron:
async def scrape_url(session, url):
async with session.get(url) as response:
print(f"Scraping page: '{url}'")
html_content = await response.text()
soup = BeautifulSoup(html_content, "html.parser")
# scraping logic...
Beachten Sie die Verwendung der Funktion „await”, um den HTML-Code der Webseite abzurufen.
Um die Funktion parallel auszuführen, erstellen Sie eine AIOHTTP-Sitzung und sammeln Sie mehrere Scraping-Aufgaben:
# gleichzeitige Ausführung der Scraping-Aufgaben
async with aiohttp.ClientSession() as session:
tasks = [scrape_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
# Glättung der Ergebnisliste
quotes = [quote for sublist in results for quote in sublist]
Verwenden Sie schließlich asyncio.run(), um Ihre asynchrone Haupt-Scraping-Funktion auszuführen:
if __name__ == "__main__":
start_time = time.time()
asyncio.run(scrape_quotes())
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time:.2f} seconds")
Ihr asynchrones Scraping-Skript in Python enthält die folgenden Codezeilen:
import asyncio
import aiohttp
from bs4 import BeautifulSoup
import csv
import time
async def scrape_url(session, url):
async with session.get(url) as response:
print(f"Scraping page: '{url}'")
html_content = await response.text()
soup = BeautifulSoup(html_content, "html.parser")
quote_html_elements = soup.select(".quote")
quotes = []
for quote_html_element in quote_html_elements:
text = quote_html_element.select_one(".text").get_text()
author = quote_html_element.select_one(".author").get_text()
tags = [tag.get_text() for tag in quote_html_element.select(".tag")]
quotes.append({
"text": text,
"author": author,
"tags": ", ".join(tags)
})
print(f"Seite '{url}' erfolgreich gescraptn")
return quotes
async def scrape_quotes():
urls = [
"http://quotes.toscrape.com/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
"https://quotes.toscrape.com/page/4/",
"https://quotes.toscrape.com/page/5/",
"https://quotes.toscrape.com/page/6/",
"https://quotes.toscrape.com/page/7/",
„https://quotes.toscrape.com/page/8/“,
„https://quotes.toscrape.com/page/9/“,
„https://quotes.toscrape.com/page/10/“
]
# gleichzeitige Ausführung der Scraping-Aufgaben
async with aiohttp.ClientSession() as session:
tasks = [scrape_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
# Glättung der Ergebnisliste
quotes = [quote for sublist in results for quote in sublist]
print("Exportieren der gescrapten Daten in CSV")
with open("quotes_multiprocessing.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["text", "author", "tags"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(quotes)
print("Zitate in CSV exportiert")
if __name__ == "__main__":
start_time = time.time()
asyncio.run(scrape_quotes())
end_time = time.time()
execution_time = end_time - start_time
print(f"Ausführungszeit: {execution_time:.2f} Sekunden")
Starten Sie das Programm, und Sie erhalten eine Ausgabe wie diese:
Seite scrapen: 'http://quotes.toscrape.com/'
Seite 'http://quotes.toscrape.com/' erfolgreich gescrapt
Seite scrapen: 'https://quotes.toscrape.com/page/3/'
Scraping page: 'https://quotes.toscrape.com/page/7/'
Scraping page: 'https://quotes.toscrape.com/page/9/'
Scraping page: 'https://quotes.toscrape.com/page/6/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/8/'
Seite wird gescrapt: 'https://quotes.toscrape.com/page/10/'
Seite 'https://quotes.toscrape.com/page/3/' erfolgreich gescrapt
Seite wird gecrawlt: 'https://quotes.toscrape.com/page/5/'
Seite wird gecrawlt: 'https://quotes.toscrape.com/page/4/'
Seite 'https://quotes.toscrape.com/page/7/' erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/9/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/6/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/2/” wird gecrawlt
Seite „https://quotes.toscrape.com/page/10/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/5/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/4/” erfolgreich gecrawlt
Seite „https://quotes.toscrape.com/page/8/” erfolgreich gecrawlt.
Seite „https://quotes.toscrape.com/page/2/” erfolgreich gecrawlt.
Gecrawlte Daten werden in CSV exportiert.
Zitate wurden in CSV exportiert.
Ausführungszeit: 0,51 Sekunden
Beachten Sie, dass die Ausführungszeit ähnlich wie beim Multithreading-Ansatz ist, jedoch mit dem zusätzlichen Vorteil, dass Sie Threads nicht manuell verwalten müssen.
👍 Vorteile:
- Enorme Zeitersparnis bei der Ausführung
- Moderne Programmierung basiert auf asynchroner Logik
- Keine manuelle Verwaltung von Threads oder Prozessen erforderlich
👎 Nachteile:
- Nicht so einfach zu beherrschen
- Beachtet nicht die Reihenfolge der URLs in der Liste
- Erfordert dedizierte asynchrone Bibliotheken
5. Weitere Tipps und Ansätze zur Beschleunigung des Scrapings
Weitere Möglichkeiten, das Web-Scraping zu beschleunigen, sind:
- Optimierung der Anforderungsrate: Passen Sie die Abfrageintervalle genau an, um das optimale Gleichgewicht zwischen Geschwindigkeit und Vermeidung von Ratenbegrenzungen oder Sperrungen zu finden.
- Rotierende Proxys: Verwenden Sie rotierende Proxys, um Anfragen auf mehrere IP-Adressen zu verteilen, wodurch die Wahrscheinlichkeit einer Sperrung verringert und ein schnelleres Scraping ermöglicht wird. Siehe die besten rotierenden Proxys.
- Paralleles Scraping mit verteilten Systemen: Verteilen Sie Scraping-Aufgaben auf mehrere Online-Rechner.
- Reduzierung der JavaScript-Rendering: Vermeiden Sie Browser-Automatisierungstools und bevorzugen Sie Tools wie HTTP-Clients als HTML-Parser. Denken Sie daran, dass Browser viele Ressourcen verbrauchen und viel langsamer sind als die meisten herkömmlichen HTML-Parser.
Fazit
In diesem Leitfaden haben wir gesehen, wie man das Web-Scraping beschleunigen kann. Wir haben die Hauptgründe aufgedeckt, warum ein Scraping-Skript langsam sein kann, und verschiedene Techniken untersucht, um diese Probleme mit einem Beispiel-Python-Skript zu beheben. Mit nur wenigen Anpassungen an der Scraping-Logik haben wir eine 8-fache Verbesserung der Ausführungszeit erreicht.
Die manuelle Optimierung Ihrer Web-Scraping-Logik ist zwar entscheidend für die Beschleunigung des Datenabrufprozesses, aber die Verwendung der richtigen Tools ist ebenso wichtig. Bei dynamischen Websites, die Browser-Automatisierungslösungen erfordern, kann es komplizierter werden, da Browser in der Regel langsam und ressourcenintensiv sind.
Um diese Herausforderungen zu bewältigen, probieren Sieden Scraping-Browser aus, eine vollständig gehostete, cloudbasierte Lösung, die speziell für das Scraping entwickelt wurde. Sie lässt sich nahtlos in Puppeteer, Selenium, Playwright und andere beliebte Browser-Automatisierungstools integrieren. Ausgestattet mit einem CAPTCHA-Auto-Solver und unterstützt durch ein Proxy-Netzwerk mit über 150 Millionen Residential-IPs bietet es unbegrenzte Skalierbarkeit für alle Ihre Scraping-Anforderungen!
Melden Sie sich jetzt an und testen Sie gratis.