Suche auf einer Website

Du hast eine Idee für ein Projekt?
Antworten
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Erstmal ein Hallo in die Runde!

Ich bin absoluter Python Neuling! Neben HTML und CSS verfüge ich auch über kein Programmierkenntnisse. Mein erstes Python Buch verschlinge ich in jeder freien Minute die mir zur verfügung steht und bin davon absolut begeistert!

Hoffentlich habe ich jetzt hier den richtigen Bereich des Forums erwählt in dem ich mein Frage stelle.

Mein Erstes Programm soll folgendes können:
Mit BeautifulSoup4 und requests greife ich auf die Website willhaben.at zu und lasse mir ausgeben, wie viele Treffer bei einem speziellen Suchbegriff online sind. Diese Anfrage soll nun alle 5 Minuten stattfinden und die Erste Ausgabe soll immer mit der letzten verglichen werden. Wenn nun ein neuer Artikel bei willhaben.at online gestellt wird, der in meine Suche fällt, soll es mir einen Treffer anzeigen. Wenn ein Treffer erscheint, soll die Erste Anfrage wieder resettet werden, damit wieder neu verglichen werden kann. Ich hoffe ich konnte es so erklären, dass man es versteht ;)

ZB. Das Keyword: Handschuhe gibt mir 10.993 Ergebnisse. Wenn mehr als 10.993 Artikel online stehen, zeigt es mir einen Treffer an. Da es dann zb. 10.998 Handschuhe sind, soll das Programm nun diese Zahl mit den erneut gesuchten vergleichen.
Natürlich weiß ich, dass es auf solchen Seiten eine Suchfunktion gibt. Diese schickt jedoch nur einmal täglich eine Mail mit den Suchbegriffen aus. Mit meinem Programm möchte ich sofort über neue Artikel benachrichtig werden.

Hier möchte ich mal zeigen, was ich bis jetzt so erstellt habe und würde um etwas Hilfe bitten, da ich als Neuling da wirklich nicht mehr weiter weiß:
Ich würde mich wirklich sehr über ein paar helfende Kommentare freuen ;)

Code: Alles auswählen

from bs4 import BeautifulSoup
import requests
import schedule
import time

suchbegriff = input("Suchbegriff eingeben: ")
url = f"https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz?sfId=bf6fcfc2-4ec6-4660-b7a7-ed7c54cc051d&isNavigation=true&keyword={suchbegriff}"
page = requests.get(url).text
doc = BeautifulSoup(page, "html.parser")

exponate = doc.find(class_="Text-sc-10o2fdq-0 dPLjLe")
anzahl = str(exponate).split(">")[-2].split("A")[-2][:-1]
print(anzahl)

def suche():
    url = f"https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz?sfId=bf6fcfc2-4ec6-4660-b7a7-ed7c54cc051d&isNavigation=true&keyword={suchbegriff}"
    page = requests.get(url).text
    doc = BeautifulSoup(page, "html.parser")
    page_text = doc.find(class_="Text-sc-10o2fdq-0 dPLjLe")
    pages = str(page_text).split(">")[-2].split("A")[-2][:-1]
    print(pages)
    if pages != anzahl:
        print("Ergebnis!!!")
    else:
        print("nichts neues")


schedule.every(5).seconds.do(suche)

while True:
    schedule.run_pending()
    time.sleep(1)
LG Michael
rogerb
User
Beiträge: 877
Registriert: Dienstag 26. November 2019, 23:24

@cougar,

Dies wäre eine Möglichkeit. Die Funktion gibt die Anzahl zurück und prüft ob es eine Änderung zum letzten Wert gab.

Code: Alles auswählen

import time
import requests
from bs4 import BeautifulSoup


def get_search_result_count(suchbegriff):
    url = "https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz"
    params = {
        "sfId": "bf6fcfc2-4ec6-4660-b7a7-ed7c54cc051d",
        "isNavigation": True,
        "keyword": suchbegriff,
    }
    response = requests.get(url, params=params)
    html = BeautifulSoup(response.text, "html.parser")
    result_count_element = html.find(class_="Text-sc-10o2fdq-0 dPLjLe")
    return int(result_count_element.text.split()[0].replace(".", ""))


def main():
    last_count = 0
    while True:
        new_count = get_search_result_count("Handschuhe")
        if new_count != last_count:
            print(f"Number of result changed from {last_count} to {new_count}")
            last_count = new_count
        else:
            print(f"No change from last request, still {last_count} results")

        # wait one hour before sending new request
        time.sleep(3600)


if __name__ == "__main__":
    main()
"schedule" würde ich nicht benutzen, statt dessen sollte dein Betriebssystem dieses Script periodisch aufrufen.
Zur Simulation habe ich hier eine while-Schleife mit einer Stunde Wartezeit gewählt.

Öfter würde ich die Seite auch nicht aufrufen. Das erzeugt nur unnötige Anfragen an den Server. Es kann auch sein, dass du blockiert wirst, wenn du es zu häufig versuchst.
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Danke dir vielmals für deine Antwort! Das ist wirklich eine sehr große Hilfe!!

Ich habe es noch ein kleines bisschen verändert.
Was ich leider noch nicht ganz versteh ist das letzte if (__name__) Könntest du mir das kurz erklären was das genau macht??

Ein weitere Frage hätte ich noch. Besteht die Möglichkeit ein Python Script auf einen Webserver zu packen und das Programm dann online auszuführen? Ziel ist es, dass man diese Suchanfrage dauerhaft laufen lassen kann und dann immer per Mail benachrichtigt wird, wenn ein neuer Artikel online kommt.



Code: Alles auswählen

import time
import requests
from bs4 import BeautifulSoup


def get_search_result_count(suchbegriff):
    url = "https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz"
    params = {
        "sfId": "bf6fcfc2-4ec6-4660-b7a7-ed7c54cc051d",
        "isNavigation": True,
        "keyword": suchbegriff,
    }
    response = requests.get(url, params=params)
    html = BeautifulSoup(response.text, "html.parser")
    result_count_element = html.find(class_="Text-sc-10o2fdq-0 dPLjLe")
    return int(result_count_element.text.split()[0].replace(".", ""))


def main():
    last_count = 0
    while True:
        new_count = get_search_result_count(search)
        if new_count != last_count:
            print(f"Nummer hat sich geändert von {last_count} auf {new_count}")
            if last_count < new_count:
                print("Neuer Treffer")
                # Hier werde ich noch versuchem mit SMTP eine Mail zu senden
            elif last_count > new_count:
                print("Artikel weniger")
            last_count = new_count
        else:
            print(f"Keine Änderung! {last_count} Ergebnisse")

        # wait one hour before sending new request
        time.sleep(3600)

search = input("Suche eingeben: ")

if __name__ == "__main__":
    main()
rogerb
User
Beiträge: 877
Registriert: Dienstag 26. November 2019, 23:24

@cougar,

code auf Modulebene, wird ausgeführt, wenn dieses Modul von anderen Modulen importiert wird.
Daher schreibt man keinen code direkt auf Modulebene, sondern nur in Funktionen.

Code: Alles auswählen

search = input("Suche eingeben: ")
würde dann also ausgeführt, obwohl das sicher nicht erwünscht wäre. Die Lösung ist ein bedingter Aufruf der main() Funktion.
Nur wenn dieses Modul direkt aufgerufen wird, also nicht importiert wird, ist die Bedingung

Code: Alles auswählen

if __name__ == "__main__":
wahr. Und nur dann geht es in die main() Funktion.
Das nennt man auch "Import guard", also Schutz vor Ausführung durch Import.

Die Zeile

Code: Alles auswählen

search = input("Suche eingeben: ")
muss also an den Anfang der main() Funktion.

Und ja, man kann das Script zum Beispiel auf Linux vom Crontab aufrufen lassen. Auf Windows macht das der Task-Scheduler.
Dann sollte es keine while-True Schleife mehr geben. Statt dessen started Crontab das Script einmal pro Stunde, lässt es einmal durchlaufen und stoppt dann wieder.
Dazu muss die letzte gefundene Anzahl von Treffern außerhalb des Scripts in einer Datei gespeichert werden.

Der Ablauf wäre dann grob:
- Crontab startet script
- script liest Anzahl aus Datei
- script holt neue Anzahl von Webseite
- Vergleich mit letzter Anzahl aus der Datei
- Falls geändert: Email versenden und Speichern der neuen Anzahl in Datei
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Vielen Dank für deine Hilfe!
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Eine Frage dazu ist mir jetzt doch noch eingefallen.
Wenn das Programm mehrere Suchbegriff gleichzeitig testen soll. Wird das alles in der Funktion main() gemacht oder gibt es ne Möglichkeit mehrere Funktionen parallel laufen zu lassen?
rogerb
User
Beiträge: 877
Registriert: Dienstag 26. November 2019, 23:24

Wieviele Suchbegriffe willst du denn abfragen?

Die Funktion "get_search_result_count" muss mit den Entsprechenden Suchbegriffen aufgerufen werden. Der Rückgabewert ist die Anzahl für den entsprechenden Suchbegriff.
Beides sollte zusammen zum Beispiel in einem Dictionary gespeichert werden um die Zuordnung Suchbegriff zu Anzahl zu behalten.

Mehrere Funktionen brauchst du nicht, da die eine alle Suchbegriffe abfragen kann.
Das kann man zwar parallel machen, bei vielen gleichzeitigen Anfragen könnte der Server das aber als Angriff einstufen. Das sollte man also nicht übertreiben.
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Es wäre so max. 15-30 Suchbegriffe
rogerb
User
Beiträge: 877
Registriert: Dienstag 26. November 2019, 23:24

Dann besteht ja kein Grund es parallel zu machen.

Ein Beispiel für Handschuhe und Schals. Das kann man beliebig erweitern.

Code: Alles auswählen

import time
import requests
from bs4 import BeautifulSoup

# Suchbegriffe eintragen
COUNT_RESULTS = {"Handschuhe": 0, "Schals": 0}


def get_search_result_count(suchbegriff):
    url = "https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz"
    params = {
        "sfId": "bf6fcfc2-4ec6-4660-b7a7-ed7c54cc051d",
        "isNavigation": True,
        "keyword": suchbegriff,
    }
    response = requests.get(url, params=params)
    html = BeautifulSoup(response.text, "html.parser")
    result_count_element = html.find(class_="Text-sc-10o2fdq-0 dPLjLe")
    return int(result_count_element.text.split()[0].replace(".", ""))


def main():
    while True:
        new_count_results = {}
        for search_term, last_count in COUNT_RESULTS.items():
            new_count = get_search_result_count(search_term)
            if new_count != last_count:
                print(f"Nummer für Suchbegriff '{search_term}' hat sich geändert von {last_count} auf {new_count}")
                difference = new_count - last_count
                if difference < 0:
                    print(f"{abs(difference)} Artikel weniger")
                    # Hier werde ich noch versuchem mit SMTP eine Mail zu senden
                elif difference > 0:
                    print(f"{difference} Artikel mehr")
                new_count_results[search_term] = new_count
            else:
                print(f"Keine Änderung für Suchbegriff '{search_term}'! {last_count} Ergebnisse")

        COUNT_RESULTS.update(new_count_results)

        # wait one hour before sending new request
        time.sleep(3600)


if __name__ == "__main__":
    main()
Auf Dauer sollten die Ergebnisse in einer Datei oder Datenbank gespeichert werden.
cougar
User
Beiträge: 6
Registriert: Samstag 22. Januar 2022, 19:09

Deine Antwort hat mir wirklich extrem weitergeholfen!! Danke vielmals!

Denkst du, dass man hier wen finden kann, der einen Server besitzt und so ein Script darauf laufen lässt? So das ich es jederzeit (Passwort geschützt) über das Internet erreichen kann und bedienen kann? (Natürlich gegen Bezahlung!!)
__deets__
User
Beiträge: 11922
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sowas gibt es ja als Angebote. Ein Privatmensch hier wird das wohl eher nicht machen.
Antworten