Grafikkartenpreise
Das Projekt Grafikkartenpreise beschreibt die Vorgehensweise anhand von Methoden zur Datenerhebung, Datenaufbereitung und Datenverfügbarkeit. Das Ziel besteht darin, die Daten in eine leicht lesbare Tabelle zu übertragen, die es dem Endbenutzer ermöglicht, Analysen und Visualisierungen durchzuführen. Zur besseren Nachvollziehbarkeit wird das Projekt in zwei Phasen unterteilt.
Phase 1. Die Datenbeschaffung.
Um mit der Datenbeschaffung beginnen zu können, muss zunächst die Datenquelle bekannt sein. Die Datenbeschaffung wird mit der Pythonbibliothek "Beautifulsoup" und "requests" durchgeführt. Das Ziel ist, die Beschreibung einer Grafikkarte sowie den Preis und die Anzahl der verkauften Exemplare zu extrahieren.
Um Zugang zu den Daten zu erhalten, ist es notwendig, zunächst die Struktur der Website zu analysieren, von der die Daten beschafft werden sollen. Hierfür wird der JavaScript-Code der Website untersucht. Durch die Untersuchung des JavaScript-Codes lässt sich feststellen, wie die Daten auf der Website geladen, angezeigt oder aktualisiert werden. Diese Analyse ermöglicht es, die notwendigen Schritte zu identifizieren, um diese Daten zu erfassen und zu extrahieren.
In diesem Beispiel muss zunächst eine Tabelle mit allen verfügbaren Grafikkartentypen extrahiert werden, um anschließend auf die benötigten Daten zugreifen zu können. Der folgende Codeausschnitt zeigt exemplarisch den Vorgang.
def scraper_card_table(url):
r = requests.get(url)
soup = bs(r.content, "html.parser")
infobox_table = soup.find("ul", {"class": "cat_level_2"})
rows = infobox_table.find_all("li")
card_links = [text.find("a").get("href") for text in rows]
return card_links
Die einzelnen Zeilen haben folgende Funktion:
- r = requests.get(url): Ein HTTP GET-Anforderung wird an die angegebene URL (self.url) gesendet, um den HTML-Inhalt der Seite abzurufen. Das Ergebnis der Anfrage wird in der Variablen r gespeichert.
- soup = bs(r.content, "html.parser"): Der HTML-Inhalt der Seite (r.content) wird mit BeautifulSoup analysiert, um eine Soup-Objektstruktur zu erstellen. Dies ermöglicht es, auf verschiedene Teile des HTML-Dokuments zuzugreifen und sie zu durchsuchen. Der Parser html.parser wird verwendet, um das HTML-Dokument zu analysieren.
- infobox_table = soup.find("ul", {"class": "cat_level_2"}): Mit der Methode find wird nach einem ul-Element gesucht, das die Klasse "cat_level_2" hat. Dieses Element wird normalerweise als Infobox-Tabelle betrachtet.
- rows = infobox_table.find_all("li"): Mit der Methode find_all wird nach allen li-Elementen innerhalb der Infobox-Tabelle gesucht. Diese Elemente enthalten normalerweise Links zu den Karten.
- card_links = [text.find("a").get("href") for text in rows]: Diese Zeile durchläuft jede Zeile (li-Element) in der Infobox-Tabelle und sucht nach einem Link (a-Element) innerhalb der Zeile. Der Wert des href-Attributs jedes Links wird extrahiert und in einer Liste self.card_links gespeichert. self.card_links ist ein Attribut der Klasse CardScraper, das die extrahierten Kartenseiten-Links enthält.
- return card_links: Die Liste der Kartenseiten-Links wird zurückgegeben.
Die Liste enthält Verlinkungen zu den einzelnen Varianten der Grafikkarten. Diese Links werden im nächsten Schritt benötigt.
Die Liste wird nun mittels einer for-Schleife durchlaufen. Dabei führt jeder Link zu einer Grafikkarte und den dazugehörigen Informationen. Im folgenden Codeausschnitt wird die Extraktion der Daten Name, Preis und Anzahl der verkauften Exemplare dargestellt. Der Name enthält die Bezeichnung der Grafikkarte sowie einige technische Daten. Zusätzlich soll der direkte Link der Karte in den Daten enthalten sein.
def scraper_card_type(url):
r = requests.get(url)
soup = bs(r.content, "html.parser")
card_name = soup.find_all("div", {"class": "pname"})
card_price = soup.find_all("div", {"class": "pprice"})
card_sold = soup.find_all("div", {"class": ["psold", "psoldempty"]})
card_url_direct = soup.find_all("a", {"class": "phover-complete-link"})
Die einzelnen Zeilen haben folgende Funktion:
- r = requests.get(url): Eine HTTP-GET-Anfrage wird an die angegebene URL gesendet, um den HTML-Inhalt der Seite abzurufen. Das Ergebnis der Anfrage wird in der Variablen r gespeichert.
- soup = bs(r.content, "html.parser"): Der HTML-Inhalt der Seite wird mit BeautifulSoup analysiert, um eine Objektstruktur zu erstellen. Dies ermöglicht es, auf verschiedene Teile des HTML-Dokuments zuzugreifen und sie zu durchsuchen. Der Parser "html.parser" wird verwendet, um das HTML-Dokument zu analysieren.
- card_name = soup.find_all("div", {"class": "pname"}): Es werden alle div-Elemente mit der Klasse "pname" gesucht. Diese Elemente enthalten normalerweise Informationen über den Namen der Karte.
- card_price = soup.find_all("div", {"class": "pprice"}): Es werden alle div-Elemente mit der Klasse "pprice" gesucht. Diese Elemente enthalten normalerweise Informationen über den Preis der Karte.
- card_sold = soup.find_all("div", {"class": ["psold", "psoldempty"]}): Es werden alle div-Elemente mit den Klassen "psold" oder "psoldempty" gesucht. Diese Elemente enthalten normalerweise Informationen über die Anzahl der verkauften Karten.
- card_url_direct = soup.find_all("a", {"class": "phover-complete-link"}): Es werden alle a-Elemente mit der Klasse "phover-complete-link" gesucht. Diese Elemente enthalten normalerweise den direkten URL-Link zu den Karten.
Die Rohdaten wurden nun in Variablen gespeichert. Die Rohdaten enthalten noch unerwünschte Ziffern und Sonderzeichen, die entfernt werden müssen. Zur Veranschaulichung wird ein Beispiel der verkauften Einheiten einer Grafikkarte dargestellt.
über 2.410 verkauft,
Für die Datensammlung wird ausschließlich die Anzahl der verkauften Exemplare benötigt. In diesem Fall beträgt sie 2.410 Stück. Der Rest der Zeile, also das Wort "über " mit Leerzeichen und das Wort " verkauft," mit Leerzeichen und Komma ist nicht erwünscht und muss entfernt werden, was im folgenden Codeabschnitt dargestellt ist.
card_sold_cleared = [text.get_text().strip().replace("über ", "").replace(" verkauft,", "") for text in card_sold]
- for text in card_sold: Hier wird eine Schleife über jedes Element in der Liste card_sold gestartet. Jedes Element repräsentiert ein BeautifulSoup-Objekt, das ein div-Element auf der Webseite darstellt, das Informationen über den Verkauf einer Karte enthält.
- text.get_text(): Für jedes div-Element wird der Textinhalt mit der Methode get_text() extrahiert. Dies entfernt alle HTML-Tags und gibt nur den reinen Textinhalt zurück.
- .strip(): Die Methode strip() wird verwendet, um führende und nachfolgende Leerzeichen und Zeilenumbrüche zu entfernen.
- .replace("über ", ""): Die Methode replace() wird verwendet, um den Text "über " durch einen leeren String zu ersetzen. Dies entfernt das Wort "über", das oft verwendet wird, um anzuzeigen, wie viele Karten verkauft wurden.
- .replace(" verkauft", ""): Die Methode replace() wird erneut verwendet, um den Text " verkauft" durch einen leeren String zu ersetzen. Dies entfernt die Wörter "verkauft", die oft am Ende des Satzes stehen.
Im Anschluss werden die Daten in einem Dictionary gespeichert und anschließend in ein Pandas DataFrame konvertiert, was weitere Bearbeitungsschritte ermöglicht.
Phase 2. Datenbereinigung.
Ziel dieser Phase ist es, die Daten in einen Zustand zu überführen, der z.B. Analysen oder Visualisierungen ermöglicht. Dabei wird die Spalte "Sold" in eine Ganzzahl und die Spalte "Price" in eine Gleitkommazahl umgewandelt, um z.B. Berechnungen durchführen zu können. Die Spalte "Card_name" wird zur besseren Übersicht in mehrere Spalten aufgeteilt. Hier ein Ausschnitt aus der ersten Zeile der Spalte "Card_name":
24GB ASRock Radeon RX 7900 XTX Phantom Gaming OC Aktiv PCIe 4.0 x16 (Retail)
An diesem Beispiel ist gut zu erkennen, dass zu viele Informationen in einer Zeile enthalten sind, weshalb die Spalte in vier Spalten, "Brand", "VRAM", "model" und "additional description" aufgeteilt wird. Der folgende Codeausschnitt zeigt am Beispiel der Spalte "VRAM" den Vorgang.
data["VRAM"] = data["Card_name"].str.slice(0,4)
In diesem Codeausschnitt wird eine neue Spalte namens "VRAM" im DataFrame "data" erstellt. Die Werte in dieser Spalte werden aus der Spalte "Card_name" abgeleitet. Mit der Methode str.slice(0,4) werden die ersten vier Zeichen jedes Strings in der Spalte "Card_name" extrahiert. Diese Zeichen repräsentieren in der Regel die VRAM (Video Random Access Memory)-Spezifikation des Grafikkartenmodells. Das Ergebnis ist eine eigene Spalte, die ausschließlich den VRAM enthält. Die restlichen Daten werden ähnlich aus der Spalte "Card_name" extrahiert, was zu folgendem Ergebnis führt:
Model | Brand | Additional Description | VRAM | Price | Sold |
---|---|---|---|---|---|
RX 7900 XTX | ASRock Radeon | Phantom Gaming OC Aktiv PCIe 4.0 x16 (Retail) | 24GB | 978 | 2420 |