2

Preisalarm für Amazon-Produkte in Python coden – Anfänger-Tutorial

Wie wäre es, wenn du mit einem einfachen Python-Tool, nie wieder einen super Preis-Deal verpassen würdest.

In diesem Tutorial lernst du, wie du mit ein paar Zeilen Python-Code, die Preise von Amazon-Produkte überwachen kannst.

Mit ein paar Änderungen lässt sich das Skript sogar auf weitere Webshops erweitern.

Das Tool ist besonders hilfreich, wenn große Promotions, wie bspw. Black-Friday oder Cyber-Monday anstehen, damit du dir die besten Deals sichern kannst.

Vorüberlegung & grobe Planung des Preisalarms

Ich gehe davon aus, dass fast jeder von uns mal eine Produktseite als Favorit im Browser gespeichert hatte, in der Hoffnung, dass der Preis irgendwann fällt.

Dieses Tutorial zeigt dir, wie du ein eigenes Skript schreibst, dass insbesondere Amazon-Produktseiten scraped und dann den Preis des Produkts überprüft.

Die folgende Anleitung ist so einfach wie möglich gehalten, jedoch ist es immer hilfreich, wenn du ein paar Kenntnisse in der Programmierung oder IT mitbringst.

Nachfolgend findest du eine Übersicht der ungefähren Aufgaben, die wir für unseren Preis-Tracker benötigen:

  • CSV-Dateien erstellen. Die CSV-Datei enthält unsere Produkt-Links sowie eingetragene Wunschpreise.
  • Das Python-Modul "Beautiful Soup" importieren und eine Funktion erstellen, die alle Links in unserer CSV-Datei ausliest und dann im Browser öffnet.
  • Gefundene Daten (insb. Produktpreis) in einer Datenbank-Tabelle abspeichern, damit wir historische Preis-Trends verfolgen können (z.B. steigt der Preis des Produkts oder fällt er).
  • Das Skript automatisch nach einem Zeitplan auszuführen (z.B. 1x am Tag).
  • Optional: E-Mail an uns selbst schicken, wenn ein Preis niedriger als der Wunschpreis ist.

Hast du weitere Ideen? Du kannst natürlich weitere Funktionen einbauen, um den Preis-Tracker noch komfortabler oder flexibler zu machen. Du könntest etwa einen Wunsch-Suchbegriff ("Kaffeemaschinen") eingeben und dein Skript die ersten 5 Produkte in die CSV abspeichern und dann die Preise überprüfen lassen.

Doch fangen wir zunächst klein an!

Erste Schritte

Ich arbeite schon länger mit Web Scraping, um lästige Aufgaben zu automatisieren oder an interessante Daten zu kommen. Als ich mir mehrere Webshops für dieses Tutorial angeschaut habe ist mir aufgefallen, dass HTML-Struktur der meisten Shops sehr ähnlich ist. Daher können wir den Preis-Tracker später in allen Shops verwenden, um an die besten Preise für unsere Wunsch-Produkte zu kommen.

Auf LerneProgrammieren habe ich bereits ein ausführliches Tutorial zu Beautiful Soup verfasst. Dort findest du eine gute Anleitung, wie das Python-Paket funktioniert und wie es sich für das Web-Scraping einsetzen lässt.

Da ich davon ausgehe, dass du Beautiful Soup noch nicht kennst, findest du nachfolgend meine kurze Erklärung:

Kurz gesagt, Beautiful Soup ist ein Tool, mit dem du auf alle HTML-Elemente einer Website zugreifen kannst. Selbst wenn du nur wenige Kenntnisse in HTML hast, wirst du schnell verstehen, wie Beautiful Soup funktioniert.

Legen wir los mit den einfachsten Aufgaben.

CSV-Datei erstellen

CSV für Preisalarm-Produkte

Du brauchst eine Datei namens preistracker_produkte.csv mit den Produktlinks, die du überwachen möchtest.

Der Inhalte meiner CSV-Datei sieht wie folgt aus, wenn ich sie in Excel öffne:

preistracker struktur csv

Datenbank/Datei zum Speichern der Ergebnisse

Sobald dein Scraper die Ergebnisse aus dem Webshop gezogen hat, müssen sie irgendwo abgelegt werden. Ich benutze dafür eine simple Excel-Datei namens produkt_historie.xlsx. Selbstverständlich könntest du auch hier eine CSV-Datei, anstatt XLSX-Datei benutzen.

Auf die Struktur der produkt_historie.xlsx gehen wir im späteren Abschnitt noch ein.

Python-Skript

Das Python-Skript speichere ich in eine Datei namens preistracker.py.

Hast du alle Dateien angelegt, sollte dein Projekt-Ordner folgende Dateien enthalten:

preistracker dateistruktur

 

Das tägliche (oder auch stündliche) Aufrufen werden wir später mit dem Windows Scheduler durchführen. Wenn du nicht unter Windows arbeitest, gibst es ebenfalls mehrere Möglichkeiten ein Skript nach festgelegten Zeitabständen automatisch zu starten (z.B. Cronjobs)..

Module & Produkt-Links importieren

Um Webseiten aufzurufen und zu scrapen benötigt unser Skript (preistracker.py) ein paar Python-Module.

Nachfolgend eine Übersicht mit einer kurzen Erklärung zu den Modulen:

  • requests: Requests wird sich darum kümmern, die URLs zu besuchen, die wir in der Produkt-Tracker-CSV gespeichert haben.
  • BeautifulSoup: Wird zum Scrapen von Webinhalten benutzt
  • datetime: Kann Datum- und Zeitwerte manipulieren
  • time: Ermöglicht mitunter den "sleep" Befehl, der Pausen ermöglicht
  • glob: Zeigt Dateinamen innerhalb eines Ordners an

Wenn du die Module noch nicht heruntergeladen hast, kannst du das mit dem pip-Befehl machen.

pip install requests
pip install bs4
pip install pandas

Wir starten mit dem Import der Module und definieren einen User-Agent. Diesen speichern wir in der Variablen headers.

import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime
from time import sleep
from glob import glob

headers = ({'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
            'Accept-Language': 'de;q=0.5'})

Der User-Agent wird bei jedem Aufrufen einer Webseite mitgesendet. Er enthält Informationen über den Browser, die Browser-Version, das Betriebssystem, verwendete lokale Sprache u.v.m. Du kannst den o.g. User-Agent benutzen, da er von den meisten Websites akzeptiert wird.

Es wird Zeit, die CSV-Datei zu importieren und die URLs aufzurufen. Folgender Code, wird unter die Variable headers eingefügt:

# CSV-Datei importieren
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink

# Rufe Produkt-URL auf
website = requests.get(produkteTrackerURLS[0], headers=headers)

# Beautiful-Soup Objekt, dass alle DOM-Elemente der URL enthält
soup = BeautifulSoup(website.content, features="lxml")

Erklärung:

  • Die CSV-Datei namens preistracker_produkte.csv wird (mit dem Semikolon als Trennzeichen) ausgelesen und in der Variablen produkteTracker gespeichert.
  • In der nächsten Zeile lesen wir die Einträge der Spalte "Produktlink" aus und speichern das Ergebnis in der Variablen produkteTrackerURLS. Jetzt haben wir alle URLs ausgelesen und können sie im Anschluss aufrufen.
  • Die Methode requests.get ruft die erste URL auf und speichert das Ergebnis in der Variablen website.
  • Dann lassen wir sie durch Beautiful Soup laufen und speichern das Ergebnis in der Variablen soup (für Beautiful Soup). Dies wird das HTML-Output in einem übersichtlicherem Format abspeichern.

Hinweis: Wenn du wissen möchtest, welche Inhalte in der Variablen soup gespeichert werden, kannst du einfach folgenden Befehl in die nächste Zeile schreiben.

print(soup)

Ungefähre Ausgabe:

preistracker soup object

Wie du am obigen Screenshot siehst, sind dort alle HTML-Elemente der aufgerufenen Webseite gespeichert.

Welche HTML-Inhalte benötigen wir?

Jetzt stellt sich uns die Frage, welche Inhalte wir aus dem BeautifulSoup-Objekt benötigen.

Der Preis ist offensichtlich, schließlich ist das der Grund für dieses Tutorial.

Doch wie wäre es zusätzlich mit dem Produktnamen/-titel. Das wäre hilfreich, um ein paar Details in der Excel-Datei zu speichern, damit du die Produkte leichter überprüfen kannst.

Weiterhin könnten wir die Anzahl der Bewertungen mit übernehmen. Wenn dich diese Informationen nicht interessieren, kannst du diesen Schritt überspringen. Jedoch ist es sehr einfach, diese Informationen mit in der Excel-Datei abzuspeichern, da wir die Struktur sowieso in Kürze auswerten.

soup.find()

Im nachfolgenden Code wirst du immer wieder die Methode soup.find() finden. Hier versuchen wir, ein Element der abgespeicherten Website mithilfe eines HTML-Tags (p, h1, div, span, etc.) und/oder den Attributen (name, id, class) zu finden.

soup.select()

Mit soup.select() benutzen wir CSS Selektoren.

Elemente im Quellcode finden

Du kannst die Elemente auch finden, in dem du die Entwicklertools (Rechtsklick, Untersuchen) deines Browsers nutzt. Dort kannst du durch den Quellcode der Webseite navigieren.

preistracker html elemente finden

Elemente mit den Browser-Entwicklertools manuell finden

Alternativ gibt es praktische Chrome-Add-ons (Erweiterungen), wie bspw. SelectorGadget. Diese Add-ons machen es noch leichter, die richtigen Elemente zu finden.

Diese Elemente brauchst du

Folgende Elemente konnte ich auf der Website finden. Diese habe ich mir notiert:

# Produkt Titel
id='productTitle'

# Preis
class='a-offscreen'

# Bewertung
class='a-star-4-5'

# Anzahl Bewertungen
id='acrCustomerReviewText'

# Verfügbarkeit
id='availability'
class='a-color-state'

Im obigen Code habe ich mir die Attribute und Elemente aufgeschrieben, die wir benötigen, um unsere Produktdaten abzurufen.

Hinweis zur Aktualität der Elemente

Webseiten ändern sich ständig. Wenn du diesen Artikel Monate oder Jahre, nach dessen Veröffentlichung liest, kann es sein, dass die o.g. Elemente nicht mehr existieren. Das wirst du daran merken, dass dein Code keine Ergebnisse (Produkttitel, Preis-Daten etc.) zurückliefert.

Sollte das der Fall sein, kannst du das selbst beheben! Inspiziere die jeweiligen Elemente, auf der Website, die du scrapen möchtest. Aktualisiere dann die Element-ID's und Klassen. Vereinfach gesagt, musst du nur die Selektoren & Tags korrigieren, die dein Code abruft.

Solltest du hier nicht weiterkommen, kannst du einen Kommentar unten diesem Tutorial hinterlassen und ich werde versuchen, dir zu helfen.

Benötigte Elemente dekonstruieren

Produkt-Titel

Den Titel unseres Produkts zu bekommen, sollte einfach sein. Dafür benutzen wir soup.find und fügen die bereits gefundene ID productTitle ein. Um den Text aus einem Element zu erhalten, hängen wir die Methode .get_text() an. Schlussendlich werden die HTML-Tags mit .strip() entfernt.

Das Ergebnis soll in der Variablen titel abgespeichert werden.

Der Code sieht wie folgt aus:

titel = soup.find(id='productTitle').get_text().strip()

print(titel)

Den print-Befehl kannst du später weglassen. Jedoch können wir damit schnell und einfach überprüfen, dass der richtige Text ausgegeben wird.

Wenn du obigen Code ausführst und mindestens eine Produkt-URL in deiner preistracker_produkte.csv eingefügt hast, bekommst du folgende Ausgabe

Produkt-Titel Ausgabe:

Melitta Easy 1023-02 Filter-Kaffeemaschine aus Kunststoff, schwarz

Produkt-Preis

Der Teil mit dem Preis ist ein wenig herausfordernder. Es empfiehlt sich ein paar Codezeilen einzufügen, um es richtig hinzubekommen.

preis = float(soup.find('span', {'class':'a-offscreen' }).get_text().replace('.', '').replace('€', '').replace(',', '.').strip())

print(preis)

Kurze Erklärung zur preis-Variable:

Wir suchen das Klasse a-offscreen in allen <span>-Elementen. Dann extrahieren wir den Text mit get_text().

Produkte mit Preisen über 1.000 € haben einen Punkt (Tausender-Trennzeichen). Diesen Punkt wollen wir entfernen. Dafür wird die Methode .replace() angehangen. Die Methode sucht nach dem "Punkt" und ersetzt ihn mit einem leeren Wert. Gleiches gilt für das Euro-Zeichen (€) und die Kommazahl des Preises (,).

Unser manipulierter Preis wird als Kommazahl (float) in der Variablen preis gespeichert.

Ausgabe Produkt-Preis:

28.99

Try-Except-Block:

Nachfolgend führen wir einen try/except-Block hinzu, damit das Skript nicht abstürzt, wenn der Preis nicht gefunden werden konnte (z.B. wenn das Produkt nicht mehr verfügbar ist).

  • Der try-Block versucht den Preis zu finden.
  • Wurde der Preis nicht gefunden, wird der except-Block ausgeführt, welcher einen leeren Eintrag in der preis-Variablen abspeichert.

Natürlich könnten wir Stunden damit verbringen, die exakten HTML-Elemente ausfindig zu machen. Jedoch können wir, wie der Try-Except-Block zeigt, flexibel auf mögliche Fehlerquellen reagieren und das Skript somit schneller zum Erfolg bringen.

Der Code inklusive Try-Except sieht wie folgt aus:

try:
    preis = float(soup.find('span', {'class':'a-offscreen' }).get_text().replace('.', '').replace('€', '').replace(',', '.').strip())    
except:
    preis = ''

print(preis)

Produkt-Bewertung

Die Produkt-Bewertung suchen wir diesmal mit dem soup.select Befehl. Dann wählen wir das erste zurückgegebene Element aus und manipulieren es, mit den zuvor benutzten Methoden.

So sieht der Code aus:

bewertung = float(soup.select('.a-star-4-5')[0].get_text().split(' ')[0].replace(",", "."))

print(bewertung)

Anzahl der Bewertung

Um die Anzahl der Bewertungen zu erhalten, kannst du die letzte Codezeile fast vollständig kopieren. Füge die korrekt ID ein und entferne das Tausender-Trennzeichen.

Da es bei Bewertungen keine Kommazahl, sondern nur Ganzzahlen (50 Bewertungen) gibt, musst du außerdem den Datentyp float gegen int austauschen.

bewertungAnzahl = int(soup.select('#acrCustomerReviewText')[0].get_text().split(' ')[0].replace(".", ""))

print(bewertungAnzahl)

Optional: Verfügbarkeit des Produkts

Wenn du wissen möchtest, ob ein Produkt verfügbar ist, kannst du folgenden Code einfügen:

try:
    soup.select('#availability .a-color-state')[0].get_text().strip()
    aufLager = 'Nicht verfügbar'
except:
    aufLager = 'Verfügbar'

print(aufLager)

Das Skript ausführen

Wenn du obige Elemente in Variablen eingefügt hast und entsprechende print-Befehle benutzt, solltest du ungefähr folgende Ausgabe bekommen:

preistracker scraper output

Als Zwischenstand findest du den bisherigen Python-Code:

import requests 
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime 
from time import sleep 
from glob import glob 

headers = ({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 'Accept-Language': 'de;q=0.5'})

# CSV-Datei importieren
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink

# Rufe Produkt-URL auf
website = requests.get(produkteTrackerURLS[0], headers=headers)

# Beautiful-Soup Objekt, dass alle DOM-Elemente der URL enthält
soup = BeautifulSoup(website.content, features="lxml")

# Produkt-Titel
titel = soup.find(id='productTitle').get_text().strip()
print(titel)

# Produkt-Preis mit try-except Block
try:
    preis = float(soup.find('span', {'class':'a-offscreen' }).get_text().replace('.', '').replace('€', '').replace(',', '.').strip())    
except:
    preis = ''
print(preis)

# Bewertung
bewertung = float(soup.select('.a-star-4-5')[0].get_text().split(' ')[0].replace(",", "."))
print(bewertung)

# Anzahl der Bewertungen
bewertungAnzahl = int(soup.select('#acrCustomerReviewText')[0].get_text().split(' ')[0].replace(".", ""))
print(bewertungAnzahl)

# Verfügbarkeit prüfen
try:
    soup.select('#availability .a-color-state')[0].get_text().strip()
    aufLager = 'Nicht verfügbar'
except:
    aufLager = 'Verfügbar'

print(aufLager)

Alle Daten auslesen und in Excel-Dateien abspeichern

Wie du bis jetzt gelernt hast, ist es einfach, die einzelnen Elemente abzufragen. Nachdem der Prototyp fertig ist, können wir das Skript so erweitern, damit wir folgende Funktionen abdecken:

  1. Alle Produkt-URLs aus der CSV-Datei auslesen (preistracker_produkte.csv)
  2. While-Schleife benutzen, um jedes Produkt zu scrapen und die Informationen zwischenspeichern
  3. Alle Ergebnisse, einschließlich der vorherigen Suchen, in die Excel-Datei (produkt_historie.xlsx) abspeichern

Preis-Tracker Produkte

Die Datei preistracker_produkte.csv enthält, wie ganz oben im Tutorial gezeigt, nur zwei Spalten ("Produktlink", "Wunschpreis"). Hier fügst du die Produkt-URLs hinzu, die du nach deinem Wunschpreis überwachen möchtest.

Produkt Historie erstellen

Genauso verhält es sich mit der Datei produkt_historie.xlsx. Vor dem ersten Durchlauf des Skripts musst du eine leere Datei in deinem Projektordner anlegen.

1. DataFrames erstellen & das Speichern vorbereiten

Erstelle einen leeren DataFrame im oberen Teil deines Skripts und speichere ihn in einer Variablen. Diesen übergeordneten DataFrame benutzen wir später zum Erstellen der Excel-Datei (Produkt-Historie).

Siehe markierte Zeile mit der Variablen produkteTrackerLog:

# CSV-Datei importieren & leeres DataFrame vorbereiten
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink
produkteTrackerLog = pd.DataFrame()

Die Excel-Datei soll im Dateinamen einen Zeitstempel (Datum und Uhrzeit) bekommen. Um das vorzubereiten, speichern wir die jetzige Zeit in der Variablen now ab.

# CSV-Datei importieren & leeres DataFrame vorbereiten
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink
produkteTrackerLog = pd.DataFrame()
    
now = datetime.now().strftime('%Y-%m-%d %Hh%Mm')

Wenn du das erledigt hast, kannst du wieder in die letzte Zeile deines Scraper-Prototyps zurückkehren.

Dort erstellen wir einen DataFrame, dem wir die zuvor gescrapten Produktdaten mitgeben. Berücksichtige hier die entsprechenden Spaltennamen der leeren Datei produkt_historie.xlsx

# Daten im DataFrame namens "log" abspeichern
log = pd.DataFrame({'Datum': now.replace('h',':').replace('m',''),                                
                      'URL': url,
                      'Titel': titel,                                
                      'Preis': preis,
                      'Wunschpreis': produkteTracker.Wunschpreis[x],
                      'Verfügbarkeit': aufLager,
                      'Bewertung': bewertung,
                      'BewertungAnzahl': bewertungAnzahl}, index=[x])

Preis-Alarm:

Im nächsten Schritt erstellen wir den Auslöser für unseren Preisalarm.

Um die Komplexität dieses Tutorials nicht zu überreizen, benutzen wir für den Preis-Alarm den print-Befehl.

Du kannst den folgenden try-Block jedoch auch um weitere Funktionen ergänzen, wie bspw. einer E-Mail-Benachrichtigung.

Ein Tutorial zum Versenden von Emails in Python habe ich dir verlinkt. Dort lernst du alles, um die Email-Funktion in dieses Skript einzufügen.

try:
  # PREIS-ALARM: Hier kannst du eine Email-Benachrichtigung einbauen
  if preis < produkteTracker.Wunschpreis[x]:
    print('!!!!!! PREIS-ALARM: ' +titel+ ' hat deinen Wunschpreis erreicht !!!!!!')
except:
  # Kein Wunschpreis entdeckt                
  pass

Der obige try/except-Block erledigt Folgendes:

Wenn der Preis der Produktseite kleiner ist als der Wunschpreis des Produktes, wird ein Preis-Alarm ausgelöst. Sollte die Bedingung nicht eintreffen (except), passiert nichts (pass).

Als Nächstes fügen, wir die Daten aus unserem DataFrame log mit .append in das übergeordnete DataFrame produkteTrackerLog ein. Darauf folgt eine print-Meldung sowie eine kurze Pause (5 Sekunden), damit du den Webshop nicht mit zu vielen Requests überlädst.

# Zwischengespeicherte Produktdaten in "log" an das Ende des produkteTrackerLog-DataFrame anhängen
produkteTrackerLog = produkteTrackerLog.append(log)
print('Hinzugefügt: '+'\n' + titel + '\n\n')            
sleep(5) # Pause zwischen Requests

2. For-Schleife einfügen

Unser Skript liest derzeit nur den ersten Eintrag der CSV-Datei (preistracker_produkte.csv) aus. Damit er alle Einträge ausliest, sprich über alle Produktlinks iteriert, müssen wir eine for-Schleife einfügen.

Das ist super einfach (siehe markierte Zeile 17):

(Beachte bitte, dass du den gesamten Code unter der for-Schleife einrückst oder benutze meinen folgenden Code)

import requests 
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime 
from time import sleep 
from glob import glob 

headers = ({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 
            'Accept-Language': 'de;q=0.5'})
 
# CSV-Datei importieren & leeres DataFrame vorbereiten
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink
produkteTrackerLog = pd.DataFrame()

now = datetime.now().strftime('%Y-%m-%d %Hh%Mm')
    
for x, url in enumerate(produkteTrackerURLS):

    # Rufe Produkt-URL auf
    website = requests.get(url, headers=headers)

    # Beautiful-Soup Objekt, dass alle DOM-Elemente der URL enthält
    soup = BeautifulSoup(website.content, features="lxml")

    # Produkt-Titel
    titel = soup.find(id='productTitle').get_text().strip()

    # Produkt-Preis mit try-except Block
    try:
        preis = float(soup.find('span', {'class':'a-offscreen' }).get_text().replace('.', '').replace('€', '').replace(',', '.').strip())    
    except:
        preis = ''

    # Bewertung
    bewertung = float(soup.select('.a-star-4-5')[0].get_text().split(' ')[0].replace(",", "."))

    # Anzahl der Bewertungen
    bewertungAnzahl = int(soup.select('#acrCustomerReviewText')[0].get_text().split(' ')[0].replace(".", ""))

    # Verfügbarkeit prüfen
    try:
        soup.select('#availability .a-color-state')[0].get_text().strip()
        aufLager = 'Nicht verfügbar'
    except:
        aufLager = 'Verfügbar'

    # Daten im DataFrame namens "log" abspeichern
    log = pd.DataFrame({'Datum': now.replace('h',':').replace('m',''),                                
                        'URL': url,
                        'Titel': titel,                                
                        'Preis': preis,
                        'Wunschpreis': produkteTracker.Wunschpreis[x],
                        'Verfügbarkeit': aufLager,
                        'Bewertung': bewertung,
                        'BewertungAnzahl': bewertungAnzahl}, index=[x])

    try:
        # PREIS-ALARM: Hier kannst du eine Email-Benachrichtigung einbauen
        if preis < produkteTracker.Wunschpreis[x]:
            print('!!!!!! PREIS-ALARM: ' +titel+ ' hat deinen Wunschpreis erreicht !!!!!!')
    
    except:
        # Kein Wunschpreis entdeckt                
        pass
    
    # Zwischengespeicherte Produktdaten in "log" an das Ende des produkteTrackerLog-DataFrame anhängen
    produkteTrackerLog = produkteTrackerLog.append(log)
    print('Hinzugefügt: '+'\n' + titel + '\n\n')            
    sleep(5) # Pause zwischen Requests

3. Daten im .xlsx-Format abspeichern

Um die Daten schlussendlich in einer Excel-Datei abzuspeichern, fügst du folgenden Code ein.

Code - Xlsx-Datei speichern:

# Datei der letzten Preis-Tracking-Suche finden & auslesen
letzteSuche = glob('./*.xlsx')[-1] # Dateipfad zur zuletzt gespeicherten Datei
suchHistorie = pd.read_excel(letzteSuche)

# Daten der letzten Preis-Tracker-Suche in neue XSLX-Datei abspeichern
outputDatei = suchHistorie.append(produkteTrackerLog, sort=False)    
outputDatei.to_excel('produkt_historie_{}.xlsx'.format(now), index=False) # Erstellt Excel-Datei mit Datum-/Zeitformat
print('Preis-Tracking abgeschlossen')

Erklärung zum Code:

Im obigen Code suchen wir mit der glob() Funktion den Dateipfad zur zuletzt gespeicherten .xlsx-Datei. Wurde das Skript noch nie gestartet, wird die leere Datei "produkt_historie.xlsx" (enthält nur Spaltennamen) benutzt.

Die Datei der letzten Suche (letzteSuche) wird dann mit dem Pandas-Befehl pd.read_excel() ausgelesen und in der Variablen suchHistorie gespeichert.

Im Anschluss erstellen wir die zu erstellende Output-Datei. Alle Daten aus dem produkteTrackerLog-DataFrame werden den Daten der letzten Suche mit der .append()-Funktion angehängt. Die Variable outputDatei enthält jetzt sowohl die alten als auch die neuen Produktdaten.

Von hier aus übertragen wir die Variablendaten in eine Excel-Datei mit dem Befehl .to_excel(). Durch die übergebenen Parameter wird ein entsprechender Dateiname (produkt_historie + Datumsformat + .xlsx) erstellt.

Zu guter Letzt führen wir einen print-Befehl aus, um zu signalisieren, dass das Skript erfolgreich ausgeführt wurde.

Fehlermeldung beim Ausführen? Openpyxl installieren

In manchen Fällen kommt es vor, dass alles korrekt integriert wurde, jedoch ein Fehler mit "openpyxl" auftaucht.

Sollte das bei dir der Fall sein, wurde das Modul wahrscheinlich noch nicht installiert.

Gehe bitte wie folgt vor, um openpyxl zu installieren. Öffne dein Terminal und gib folgenden Befehl ein:

pip install openpyxl

Führe dein Python-Skript danach erneut aus. Der Fehler sollte jetzt weg sein.

Das fertige Preis-Tracker-Skript

Nachfolgend findest du den gesamten Code des Preis-Tracker-Skripts:

import requests 
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime 
from time import sleep 
from glob import glob 

headers = ({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 
            'Accept-Language': 'de;q=0.5'})


# CSV-Datei importieren & leeres DataFrame vorbereiten
produkteTracker = pd.read_csv('preistracker_produkte.csv', sep=';')
produkteTrackerURLS = produkteTracker.Produktlink
produkteTrackerLog = pd.DataFrame()

now = datetime.now().strftime('%Y-%m-%d %Hh%Mm')       

for x, url in enumerate(produkteTrackerURLS):

    # Rufe Produkt-URL auf
    website = requests.get(url, headers=headers)

    # Beautiful-Soup Objekt, dass alle DOM-Elemente der URL enthält
    soup = BeautifulSoup(website.content, features="lxml")

    # Produkt-Titel
    titel = soup.find(id='productTitle').get_text().strip()

    # Produkt-Preis mit try-except Block
    try:
        preis = float(soup.find('span', {'class':'a-offscreen' }).get_text().replace('.', '').replace('€', '').replace(',', '.').strip())    
    except:
        preis = ''

    # Bewertung
    bewertung = float(soup.select('.a-star-4-5')[0].get_text().split(' ')[0].replace(",", "."))

    # Anzahl der Bewertungen
    bewertungAnzahl = int(soup.select('#acrCustomerReviewText')[0].get_text().split(' ')[0].replace(".", ""))

    # Verfügbarkeit prüfen
    try:
        soup.select('#availability .a-color-state')[0].get_text().strip()
        aufLager = 'Nicht verfügbar'
    except:
        aufLager = 'Verfügbar'

    # Daten im DataFrame namens "log" abspeichern
    log = pd.DataFrame({'Datum': now.replace('h',':').replace('m',''),                                
                        'URL': url,
                        'Titel': titel,                                
                        'Preis': preis,
                        'Wunschpreis': produkteTracker.Wunschpreis[x],
                        'Verfügbarkeit': aufLager,
                        'Bewertung': bewertung,
                        'BewertungAnzahl': bewertungAnzahl}, index=[x])

    try:
        # PREIS-ALARM: Hier kannst du eine Email-Benachrichtigung einbauen
        if preis < produkteTracker.Wunschpreis[x]:
            print('!!!!!! PREIS-ALARM: ' +titel+ ' hat deinen Wunschpreis erreicht !!!!!!')
    
    except:
        # Kein Wunschpreis entdeckt                
        pass
    
    # Zwischengespeicherte Produktdaten in "log" an das Ende des produkteTrackerLog-DataFrame anhängen
    produkteTrackerLog = produkteTrackerLog.append(log)
    print('Hinzugefügt: '+'\n' + titel + '\n\n')            
    sleep(5) # Pause zwischen Requests    

# Datei der letzten Preis-Tracking-Suche finden & auslesen
letzteSuche = glob('./*.xlsx')[-1] # Dateipfad zur zuletzt gespeicherten Datei
suchHistorie = pd.read_excel(letzteSuche)

# Daten der letzten Preis-Tracker-Suche in neue XSLX-Datei abspeichern
outputDatei = suchHistorie.append(produkteTrackerLog, sort=False)    
outputDatei.to_excel('produkt_historie_{}.xlsx'.format(now), index=False) # Erstellt Excel-Datei mit Datum-/Zeitformat
print('Preis-Tracking abgeschlossen')

Wenn alles korrekt implementiert wurde, solltest du ungefähr folgenden Output erhalten:

preistracker finales output

Das war's schon!

Du hast jetzt alles erstellt, um URLs aus einer CSV-Datei auszulesen, Daten von allen URLs zu scrapen und diese Daten dann in einer Excel-Datei zu speichern.

Alles, was jetzt noch fehlt, ist das automatische Ausführen des Skripts.

Diese Aufgabe lösen wir im nächsten Schritt.

Skript automatisch ausführen mit Aufgabenplanung

In diesem Abschnitt wirst du ausschließlich lernen, wie du die Windows Aufgabenplanung (Scheduler) benutzt, um dein Skript nach geplanten Zeitpunkten zu starten.

Doch auch für Mac- oder Linuxbenutzer, gibt es passende Tools, um diese Aufgabe zu bewerkstelligen (z.B. Cronjobs).

Eine automatisierte Aufgabe einzurichten, um unser Python-Skript auszuführen, ist in wenigen Schritten erledigt.

1. Aufgabenplanung öffnen & Trigger erstellen

Öffne die "Aufgabenplanung" in Windows. Wenn du nicht weißt, wo du sie findest, tippe die Windows-Taste auf deiner Tastatur an und gib das Wort Aufgabenplanung ein.

python preistracker scheduler

Sobald die Aufgabenplanung geöffnet ist, klickst du auf "Aufgabe erstellen". Gehen anschließend auf den Tab/Reiter "Trigger". Klicke auf "Neu...", um einen neuen Trigger zu erstellen.

Wähle jetzt das Intervall aus, in dem dein Skript ausgeführt werden soll (bspw. "täglich"). Klicke dann auf "OK", um den Trigger zu erstellen.

python preistracker scheduler trigger

2. Aktion erstellen

Als Nächstes klickst du auf den Reiter "Aktionen" und dann auf "Neu...".

python preistracker scheduler aktion

Hier fügst du eine Aktion hinzu und wählst den Speicherort deiner Python-Installation.

Meine Python-Installation (Version 3.8) befindet sich im Ordner %APPDATA%\Local\Programs\Python\Python38-32, wie du auf obigen Screenshot siehst.

In das Argumente-Feld trägst du den Namen der auszuführenden Python-Datei ein (preistracker.py).

In das "Starten in" Feld gibst du den Pfad an, in dem sich das Python-Skript befindet.

Bestätige deine Eingaben mit einem Klick auf "OK".

Ab jetzt ist deine Aufgabe bereit, ausgeführt zu werden. Du kannst auch weitere Optionen der Aufgabenplanung erkunden und einen Testlauf machen, um sicherzustellen, dass es funktioniert.

python scheduler aktive aufgaben

Das ist der grundlegende Weg, um deine Skripte mit der Windows Aufgabenplanung automatisch laufen zu lassen.

Fazit

Wenn du dem Preistracker-Tutorial bis hierhin gefolgt bist, wirst du mir sicher zustimmen, dass wir bereits eine Menge interessanter Funktionen abgedeckt haben. Du bist jetzt in der Lage, um Daten von Webshops zu scrapen und diese in beliebigen Datenformaten abzuspeichern.

Jetzt ist es an der Zeit, das Skript nachzubauen und weitere Webshops zu erforschen, um ein noch besseres Skript zu erstellen.

 

  • 5. Juni 2022
Click Here to Leave a Comment Below 2 comments
Manuel - 17. Februar 2023

Dieser Artikel hat viele meiner Fragen zum Thema „Preisalarm Tutorial Python“ beantwortet. Ich habe den Artikel sehr gerne gelesen und interessante Ideen daraus schöpfen können. Macht weiter so und schreibt interessante Artikel über Coding-Themen.

Reply
Xaver Stiensmeier - 28. Februar 2023

Die Aussage, dass der Code am Ende für alle Seiten benutzt werden kann, ist sehr gewagt und falsch. Viele Seiten sind anders aufgebaut. Selbst die hier gewählte Zielseite Amazon kann damit nicht immer zuverlässig geparsed werden.

Als Einsteigertutorial aber sehr gut.

Reply

Leave a Reply: