Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.

Der Autor des heute veröffentlichten Artikels berichtet, dass sein Ziel darin besteht, die Entwicklung eines Web-Scrapers in Python unter Verwendung von Selenium zu beschreiben, der nach Flugpreisen sucht. Bei der Suche nach Tickets werden flexible Daten (+- 3 Tage um die angegebenen Daten herum) verwendet. Der Scraper speichert die Suchergebnisse in einer Excel-Datei und sendet eine E-Mail mit einer Zusammenfassung der gefundenen Informationen an die Person, die ihn gestartet hat. Ziel dieses Projekts ist es, Reisenden bei der Suche nach den besten Angeboten zu helfen.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.

Wenn Sie beim Durcharbeiten des Materials das Gefühl haben, verloren zu gehen – werfen Sie einen Blick auf dieses den Artikel.

Was suchen wir?

Sie sind frei, das hier beschriebene System nach Ihren Wünschen zu nutzen. Ich habe es beispielsweise verwendet, um Wochenendausflüge und Tickets in meine Heimatstadt zu suchen. Wenn Sie ernsthaft auf der Suche nach günstigen Tickets sind – können Sie das Skript auf einem Server ausführen (einfach der Server, für 130 Rubel pro Monat ist das recht geeignet) und so eingestellt werden, dass er ein- oder zweimal am Tag läuft. Die Suchergebnisse werden Ihnen per E-Mail zugesendet. Darüber hinaus empfehle ich, alles so einzurichten, dass das Skript eine Excel-Datei mit den Suchergebnissen in einem Dropbox-Ordner speichert, sodass Sie solche Dateien von überall und jederzeit einsehen können.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Ich habe bisher keine fehlerhaften Tarife gefunden, aber ich nehme an, das ist möglich.

Bei der Suche, wie bereits erwähnt, wird das Konzept «flexibles Datum» verwendet, das Skript findet Angebote, die innerhalb von drei Tagen zu den festgelegten Daten liegen. Obwohl das Skript bei der Ausführung nur in eine Richtung sucht, ist es nicht schwierig, es so anzupassen, dass es Daten für mehrere Flugrichtungen sammeln kann. Damit kann man sogar nach fehlerhaften Tarifen suchen, solche Funde können sehr interessant sein.

Warum braucht man einen weiteren Web-Scraper?

Als ich zum ersten Mal mit Web-Scraping begann, fand ich es ehrlich gesagt nicht besonders spannend. Ich wollte mehr Projekte im Bereich der prädiktiven Modellierung, Finanzanalyse und vielleicht auch im Bereich der Sentiment-Analyse durchführen. Aber ich stellte schnell fest, wie spannend es ist, ein Programm zu erstellen, das Daten von Websites sammelt. Während ich tiefer in dieses Thema eintauchte, wurde mir klar, dass Web-Scraping der "Motor" des Internets ist.

Vielleicht halten Sie das für eine gewagte Aussage. Aber denken Sie daran, dass Google mit einem Web-Scraper begann, den Larry Page mit Java und Python entwickelte. Die Google-Bots durchforsten das Internet, um ihren Nutzern die besten Antworten auf ihre Fragen zu liefern. Web-Scraping hat unzählige Anwendungsmöglichkeiten, und selbst wenn Sie in der Data Science an etwas anderem interessiert sind, werden Sie einige Scraping-Fähigkeiten benötigen, um Daten für Ihre Analysen zu sammeln.

Einige der hier verwendeten Techniken habe ich in einem großartigen Buchs über Web-Scraping, das ich mir kürzlich angeschafft habe. Es enthält viele einfach umsetzbare Beispiele und Ideen zur praktischen Anwendung des Gelernten. Außerdem gibt es ein sehr interessantes Kapitel über das Umgehen von reCaptcha-Überprüfungen. Das war für mich neu, denn ich wusste nicht, dass es spezielle Werkzeuge und sogar ganze Dienste zur Lösung solcher Aufgaben gibt.

Lieben Sie es zu reisen?!

Auf die einfache und ziemlich harmlos scheinende Frage, die in diesem Abschnittstitel steht, erhält man oft eine positive Antwort, begleitet von ein paar Reisegeschichten des Fragestellers. Die meisten von uns stimmen zu, dass Reisen eine wunderbare Möglichkeit ist, in neue kulturelle Kontexte einzutauchen und den eigenen Horizont zu erweitern. Wenn man jedoch jemanden fragt, ob er gerne Flugtickets sucht, bin ich mir sicher, dass die Antwort darauf nicht ganz so positiv ausfallen wird. Eigentlich kommt uns hier Python zu Hilfe.

Die erste Herausforderung, die wir bei der Erstellung eines Systems zur Suche von Flugticketinformationen bewältigen müssen, ist die Auswahl einer geeigneten Plattform, von der wir Informationen beziehen werden. Es war nicht einfach, diese Entscheidung zu treffen, aber letztendlich habe ich mich für den Service Kayak entschieden. Ich habe auch die Dienstleistungen von Momondo, Skyscanner, Expedia und einigen anderen ausprobiert, jedoch waren die Schutzmechanismen dieser Plattformen gegen Bots unbeweglich. Nach mehreren Versuchen, bei denen ich die Systeme davon überzeugen wollte, dass ich ein Mensch bin, wobei ich mit Ampeln, Fußgängerüberwegen und Fahrrädern zu kämpfen hatte, kam ich zu dem Schluss, dass Kayak für mich am besten geeignet ist. Selbst hier gibt es, wenn man in kurzer Zeit zu viele Seiten aufruft, auch Kontrollen. Ich konnte sicherstellen, dass der Bot Anfragen an die Site in Intervallen von 4 bis 6 Stunden sendet, und es hat alles gut funktioniert. Gelegentlich treten auch bei Kayak Schwierigkeiten auf, aber wenn Sie mit Kontrollen belästigt werden, müssen Sie entweder die Probleme manuell lösen, bevor Sie den Bot starten, oder einige Stunden warten, dann sollten die Kontrollen aufhören. Wenn es notwendig ist, können Sie den Code problemlos für eine andere Plattform anpassen, und wenn Sie das tun, lassen Sie es uns in den Kommentaren wissen.

Wenn Sie gerade erst mit Web-Scraping beginnen und nicht wissen, warum einige Websites mit darin gestellten Methoden kämpfen, dann tun Sie sich selbst einen Gefallen und suchen Sie bei Google nach den Begriffen „Web Scraping Etiquette“, bevor Sie mit Ihrem ersten Projekt in diesem Bereich starten. Ihre Experimente könnten schneller enden als gedacht, wenn Sie nicht umsichtig beim Web-Scraping vorgehen.

Erste Schritte

Hier ist eine allgemeine Übersicht darüber, was im Code unseres Web-Scrapers passieren wird:

  • Importieren der benötigten Bibliotheken.
  • Öffnen eines Google Chrome-Tabs.
  • Aufrufen einer Funktion, die den Bot startet, während Sie ihm die Städte und Daten übergeben, die bei der Suche nach Tickets verwendet werden sollen.
  • Diese Funktion ruft die ersten Suchergebnisse ab, die nach dem Kriterium der Attraktivität (best) sortiert sind, und klickt auf die Schaltfläche, um weitere Ergebnisse zu laden.
  • Eine weitere Funktion sammelt Daten von der gesamten Seite und gibt einen Datenrahmen zurück.
  • Die beiden vorherigen Schritte werden unter Verwendung von Sortierarten nach Ticketpreisen (cheap) und nach Fluggeschwindigkeit (fastest) durchgeführt.
  • Der Benutzer des Skripts erhält eine E-Mail mit einer kurzen Übersicht über die Ticketpreise (die günstigsten Tickets und der Durchschnittspreis). Die Datensätze mit Informationen, die nach den drei oben genannten Kriterien sortiert sind, werden als Excel-Datei gespeichert.
  • Alle oben beschriebenen Aktionen werden in Schleifen in festgelegten Zeitintervallen ausgeführt.

Es ist wichtig zu beachten, dass jedes Selenium-Projekt mit einem Webdriver beginnt. Ich verwende Chromedriver, arbeite mit Google Chrome, aber es gibt auch andere Optionen. PhantomJS und Firefox sind ebenfalls beliebt. Nach dem Herunterladen des Drivers muss er in den entsprechenden Ordner verschoben werden, und damit ist die Vorbereitung für die Nutzung abgeschlossen. In den ersten Zeilen unseres Skripts wird ein neuer Tab in Chrome geöffnet.

Beachten Sie, dass ich in meinem Bericht nicht versuche, neue Horizonte bei der Suche nach günstigen Flugtickets zu eröffnen. Es gibt weitaus ausgefeiltere Techniken zur Suche nach solchen Angeboten. Ich möchte den Lesern dieses Materials lediglich eine einfache, aber praktisch anwendbare Methode zur Lösung dieses Problems vorschlagen.

Hier ist der Code, von dem wir oben gesprochen haben.

from time import sleep, strftime
from random import randint
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import smtplib
from email.mime.multipart import MIMEMultipart

# Bitte geben Sie hier Ihren Pfad zum Chromedriver an!
chromedriver_path = 'C:/{IHR PFAD HIER}/chromedriver_win32/chromedriver.exe'

driver = webdriver.Chrome(executable_path=chromedriver_path) # Mit diesem Befehl wird das Chrome-Fenster geöffnet
sleep(2)

Am Anfang des Codes sieht man die Importbefehle für die Pakete, die in unserem gesamten Projekt verwendet werden. So randint wird verwendet, damit der Bot für eine zufällige Anzahl von Sekunden „schläft“, bevor er mit einer neuen Suchoperation beginnt. Normalerweise kommt kein Bot ohne dies aus. Wenn Sie den obigen Code ausführen, öffnet sich ein Chrome-Fenster, das der Bot für die Arbeit mit Websites verwenden wird.

Lassen Sie uns ein kleines Experiment durchführen und in einem neuen Fenster die Website kayak.com öffnen. Wir wählen die Stadt aus, von der wir fliegen möchten, und die Stadt, in die wir gelangen möchten, sowie die Flugdaten. Achten Sie bei der Datenauswahl darauf, dass ein Zeitraum von +-3 Tagen eingehalten wird. Ich habe den Code so geschrieben, dass er das zurückgibt, was die Website auf solche Anfragen antwortet. Wenn Sie jedoch beispielsweise nur für festgelegte Daten Tickets suchen möchten, ist es sehr wahrscheinlich, dass Sie den Bot-Code anpassen müssen. Während ich über den Code spreche, gebe ich entsprechende Erklärungen, aber wenn Sie das Gefühl haben, dass Sie verwirrt sind, lassen Sie es mich wissen.

Jetzt klicken wir auf die Schaltfläche Suche starten und sehen uns den Link in der Adresszeile an. Er sollte ähnlich sein wie der Link, den ich im folgenden Beispiel verwende, wo die Variable kayak, die die URL speichert, deklariert wird und die Methode get des Webdrivers verwendet wird. Nach dem Klicken auf die Suchschaltfläche sollten die Ergebnisse auf der Seite angezeigt werden.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Als ich den Befehl verwendete get Mehr als zwei- bis dreimal innerhalb weniger Minuten wurde mir angeboten, die Überprüfung mit reCaptcha durchzuführen. Diese Überprüfung kann manuell durchgeführt werden, und man kann mit den Experimenten fortfahren, bis das System entscheidet, eine neue Überprüfung einzuleiten. Als ich das Skript getestet habe, hatte ich den Eindruck, dass die erste Suchsitzung immer problemlos verläuft. Wenn Sie also mit dem Code experimentieren möchten, müssen Sie nur gelegentlich manuell die Überprüfung bestehen und den Code mit langen Intervallen zwischen den Suchsitzungen ausführen lassen. Ganz ehrlich, wem wären Informationen über Ticketpreise, die mit zehnminütigen Abständen zwischen den Suchvorgängen gesammelt werden, wirklich nützlich?

Arbeiten mit der Seite unter Verwendung von XPath

So, wir haben das Fenster geöffnet und die Website geladen. Um Preise und weitere Informationen zu erhalten, müssen wir auf die Technologie XPath oder CSS-Selektoren zurückgreifen. Ich habe mich für XPath entschieden und fühlte kein Bedürfnis, CSS-Selektoren zu verwenden, aber es ist durchaus möglich, auch damit zu arbeiten. Die Navigation auf der Seite mit XPath kann kompliziert sein, und selbst wenn Sie die Methoden verwenden, die ich beschrieben habe, dieser in dem Artikel, in dem ich das Kopieren der entsprechenden IDs aus dem Code der Seite verwendet habe, wurde mir klar, dass dies nicht der optimale Weg ist, um auf die benötigten Elemente zuzugreifen. Übrigens bietet das Buch eine hervorragende Erklärung der Grundlagen der Arbeit mit Seiten unter Verwendung von XPath und CSS-Selektoren. So sieht die entsprechende Webdriver-Methode aus. dieser Im Buch finden Sie eine hervorragende Beschreibung der Grundlagen der Arbeit mit Seiten unter Verwendung von XPath und CSS-Selektoren. So sieht die entsprechende Methode des Webdrivers aus.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Also, lassen Sie uns mit der Arbeit am Bot fortfahren. Wir werden die Funktionen des Programms nutzen, um die günstigsten Tickets zu finden. Im nächsten Bild ist der XPath-Selektor-Code rot markiert. Um den Code zu sehen, klicken Sie mit der rechten Maustaste auf das gewünschte Element der Seite und wählen Sie im sich öffnenden Menü "Code untersuchen" (Inspect). Diese Funktion können Sie für verschiedene Elemente der Seite aufrufen, deren Code im Code-Inspektor angezeigt und hervorgehoben wird.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Seitenquellcode anzeigen

Um die Schwächen beim Kopieren von Selektoren aus dem Code zu bestätigen, beachten Sie bitte die folgenden Besonderheiten.

Das ist das Ergebnis beim Kopieren des Codes:

//*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/span

Um so etwas zu kopieren, klicken Sie mit der rechten Maustaste auf den entsprechenden Abschnitt des Codes und wählen Sie im sich öffnenden Menü "Kopieren > XPath kopieren" (Copy > Copy XPath).

Das habe ich verwendet, um die Schaltfläche "Günstigster" zu bestimmen:

cheap_results = '//*[@data-code = "price"]'

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Befehl "Kopieren > XPath kopieren"

Es ist offensichtlich, dass die zweite Option viel einfacher aussieht. Bei ihrer Verwendung wird das Element "a" gesucht, das das Attribut data-code, gleich Preis. Bei Verwendung der ersten Option erfolgt die Suche nach dem Element id dessen Wert gleich ist wtKI-price_aTab, wobei der XPath-Pfad zu dem Element folgendermaßen aussieht /div[1]/div/div/div[1]/div/span/span. Eine solche XPath-Anfrage an die Seite erfüllt ihren Zweck, allerdings nur einmal. Ich kann Ihnen jetzt schon sagen, dass id sich bei der nächsten Seitenladung ändern wird. Die Zeichenfolge wtKI ändert sich dynamisch bei jeder Seitenladung, weshalb der Code, in dem sie verwendet wird, nach einem weiteren Neuladen der Seite nutzlos sein wird. Daher sollten Sie sich etwas Zeit nehmen, um sich mit XPath vertraut zu machen. Dieses Wissen wird Ihnen gute Dienste leisten.

Es ist jedoch zu beachten, dass das Kopieren von XPath-Selektoren bei der Arbeit mit relativ einfachen Websites nützlich sein kann, und wenn Sie damit zufrieden sind, ist dagegen nichts einzuwenden.

Lassen Sie uns nun darüber nachdenken, wie man vorgeht, wenn alle Suchergebnisse in mehreren Zeilen innerhalb einer Liste angezeigt werden müssen. Sehr einfach. Jedes Ergebnis befindet sich innerhalb eines Objekts mit der Klasse resultWrapper. Das Laden aller Ergebnisse kann in einer Schleife erfolgen, die der unten dargestellten ähnlich ist.

Es ist wichtig zu erwähnen, dass wenn Sie das oben Gesagte verstehen, sollten Sie problemlos den Großteil des Codes verstehen, den wir durchgehen werden. Im Laufe der Arbeit mit diesem Code greifen wir auf das, was wir brauchen (eigentlich handelt es sich um ein Element, in das das Ergebnis eingebettet ist), mittels eines Mechanismus zu, um den Pfad anzugeben (XPath). Dies geschieht, um den Text des Elements zu erhalten und ihn in ein Objekt einzufügen, aus dem wir Daten auslesen können (zuerst wird verwendet flight_containers, danach — flights_list).

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Die ersten drei Zeilen werden ausgegeben und wir können klar alles sehen, was wir brauchen. Allerdings gibt es auch interessantere Methoden, um Informationen zu erhalten. Wir müssen die Daten aus jedem Element einzeln entnehmen.

Auf die Arbeit!

Es ist am einfachsten, eine Funktion zum Laden zusätzlicher Ergebnisse zu schreiben, und damit fangen wir an. Ich möchte die Anzahl der Flüge maximieren, über die das Programm Informationen erhält, und dabei gleichzeitig den Dienst nicht misstrauisch machen, was zu einer Überprüfung führen könnte. Daher klicke ich einmal auf die Schaltfläche "Weitere Ergebnisse laden", jedes Mal, wenn die Seite angezeigt wird. In diesem Code sollte man auf den Block achten try, die ich hinzugefügt habe, weil die Schaltfläche manchmal nicht richtig geladen wird. Sollten Sie auf dasselbe Problem stoßen, kommentieren Sie die Aufrufe dieser Funktion im Code aus. start_kayak, die wir im Folgenden betrachten werden.

# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
def load_more():
    try:
        more_results = '//a[@class = "moreButton"]'
        driver.find_element_by_xpath(more_results).click()
        # Вывод этих заметок в ходе работы программы помогает мне быстро выяснить то, чем она занята
        print('sleeping.....')
        sleep(randint(45,60))
    except:
        pass

Jetzt, nach einer ausführlichen Analyse dieser Funktion (manchmal kann ich mich da verlieren), sind wir bereit, die Funktion anzukündigen, die für das Scrapen der Seite verantwortlich ist.

Ich habe bereits den Großteil der notwendigen Inhalte in der nächsten Funktion, die page_scrape, zusammengetragen. Manchmal sind die zurückgegebenen Daten der Schritte des Pfades miteinander kombiniert, um sie zu trennen, verwende ich eine einfache Methode. Zum Beispiel, wenn ich zum ersten Mal die Variablen section_a_list und section_b_list, benutze. Unsere Funktion gibt ein DataFrame zurück flights_df, was uns ermöglicht, die Ergebnisse, die durch verschiedene Daten-Sortiermethoden erhalten wurden, zu trennen und später zu kombinieren.

def page_scrape():
    """This function takes care of the scraping part"""
    
    xp_sections = '//*[@class="section duration"]'
    sections = driver.find_elements_by_xpath(xp_sections)
    sections_list = [value.text for value in sections]
    section_a_list = sections_list[::2] # так мы разделяем информацию о двух полётах
    section_b_list = sections_list[1::2]
    
    # Если вы наткнулись на reCaptcha, вам может понадобиться что-то предпринять.
    # О том, что что-то пошло не так, вы узнаете исходя из того, что вышеприведённые списки пусты
    # это выражение if позволяет завершить работу программы или сделать ещё что-нибудь
    # тут можно приостановить работу, что позволит вам пройти проверку и продолжить скрапинг
    # я использую тут SystemExit так как хочу протестировать всё с самого начала
    if section_a_list == []:
        raise SystemExit
    
    # Я буду использовать букву A для уходящих рейсов и B для прибывающих
    a_duration = []
    a_section_names = []
    for n in section_a_list:
        # Получаем время
        a_section_names.append(''.join(n.split()[2:5]))
        a_duration.append(''.join(n.split()[0:2]))
    b_duration = []
    b_section_names = []
    for n in section_b_list:
        # Получаем время
        b_section_names.append(''.join(n.split()[2:5]))
        b_duration.append(''.join(n.split()[0:2]))

    xp_dates = '//div[@class="section date"]'
    dates = driver.find_elements_by_xpath(xp_dates)
    dates_list = [value.text for value in dates]
    a_date_list = dates_list[::2]
    b_date_list = dates_list[1::2]
    # Получаем день недели
    a_day = [value.split()[0] for value in a_date_list]
    a_weekday = [value.split()[1] for value in a_date_list]
    b_day = [value.split()[0] for value in b_date_list]
    b_weekday = [value.split()[1] for value in b_date_list]
    
    # Получаем цены
    xp_prices = '//a[@class="booking-link"]/span[@class="price option-text"]'
    prices = driver.find_elements_by_xpath(xp_prices)
    prices_list = [price.text.replace('$','') for price in prices if price.text != '']
    prices_list = list(map(int, prices_list))

    # stops - это большой список, в котором первый фрагмент пути находится по чётному индексу, а второй - по нечётному
    xp_stops = '//div[@class="section stops"]/div[1]'
    stops = driver.find_elements_by_xpath(xp_stops)
    stops_list = [stop.text[0].replace('n','0') for stop in stops]
    a_stop_list = stops_list[::2]
    b_stop_list = stops_list[1::2]

    xp_stops_cities = '//div[@class="section stops"]/div[2]'
    stops_cities = driver.find_elements_by_xpath(xp_stops_cities)
    stops_cities_list = [stop.text for stop in stops_cities]
    a_stop_name_list = stops_cities_list[::2]
    b_stop_name_list = stops_cities_list[1::2]
    
    # сведения о компании-перевозчике, время отправления и прибытия для обоих рейсов
    xp_schedule = '//div[@class="section times"]'
    schedules = driver.find_elements_by_xpath(xp_schedule)
    hours_list = []
    carrier_list = []
    for schedule in schedules:
        hours_list.append(schedule.text.split('n')[0])
        carrier_list.append(schedule.text.split('n')[1])
    # разделяем сведения о времени и о перевозчиках между рейсами a и b
    a_hours = hours_list[::2]
    a_carrier = carrier_list[1::2]
    b_hours = hours_list[::2]
    b_carrier = carrier_list[1::2]

    
    cols = (['Out Day', 'Out Time', 'Out Weekday', 'Out Airline', 'Out Cities', 'Out Duration', 'Out Stops', 'Out Stop Cities',
            'Return Day', 'Return Time', 'Return Weekday', 'Return Airline', 'Return Cities', 'Return Duration', 'Return Stops', 'Return Stop Cities',
            'Price'])

    flights_df = pd.DataFrame({'Out Day': a_day,
                               'Out Weekday': a_weekday,
                               'Out Duration': a_duration,
                               'Out Cities': a_section_names,
                               'Return Day': b_day,
                               'Return Weekday': b_weekday,
                               'Return Duration': b_duration,
                               'Return Cities': b_section_names,
                               'Out Stops': a_stop_list,
                               'Out Stop Cities': a_stop_name_list,
                               'Return Stops': b_stop_list,
                               'Return Stop Cities': b_stop_name_list,
                               'Out Time': a_hours,
                               'Out Airline': a_carrier,
                               'Return Time': b_hours,
                               'Return Airline': b_carrier,                           
                               'Price': prices_list})[cols]
    
    flights_df['timestamp'] = strftime("%Y%m%d-%H%M") # время сбора данных
    return flights_df

Ich habe versucht, die Variablen so zu benennen, dass der Code verständlich bleibt. Denken Sie daran, dass Variablen, die mit a beginnend, sich auf die erste Phase des Pfades beziehen, während b er sich auf die zweite bezieht. Lassen Sie uns zur nächsten Funktion übergehen.

Hilfmechanismen

Jetzt haben wir eine Funktion, die es ermöglicht, zusätzliche Suchergebnisse zu laden, sowie eine Funktion zur Verarbeitung dieser Ergebnisse. An dieser Stelle könnte man den Artikel beenden, da diese beiden Funktionen alles Notwendige für das Scraping von Seiten bieten, die man selbst öffnen kann. Allerdings haben wir einige unterstützende Mechanismen, die wir zuvor erwähnt haben, noch nicht betrachtet. Dazu gehört beispielsweise der Code zum Versenden von E-Mails und einige weitere Aspekte. All dies finden Sie in der Funktion start_kayak, die wir uns jetzt ansehen werden.

Um diese Funktion nutzen zu können, sind Informationen über Städte und Daten erforderlich. Anhand dieser Informationen wird ein Link in der Variablen erstellt. kayak, die verwendet wird, um zur Seite zu gelangen, auf der die Suchergebnisse nach ihrer besten Übereinstimmung mit der Anfrage sortiert sind. Nach der ersten Scraping-Sitzung werden wir mit den Preisen arbeiten, die sich in der Tabelle oben auf der Seite befinden. Genauer gesagt, wir werden den niedrigsten Ticketpreis und den Durchschnittspreis finden. All dies, zusammen mit der Vorhersage, die von der Website bereitgestellt wird, wird per E-Mail gesendet. Auf der Seite sollte die entsprechende Tabelle in der oberen linken Ecke sein. Die Arbeit mit dieser Tabelle kann übrigens einen Fehler bei der Suche mit genauen Daten verursachen, da in diesem Fall die Tabelle auf der Seite nicht angezeigt wird.

def start_kayak(stadt_von, stadt_nach, datum_von, datum_bis):
    """Stadtcodes - es handelt sich um die IATA-Codes!
    Datumsformat -  YYYY-MM-DD"""
    
    kayak = ('https://www.kayak.com/flights/' + stadt_von + '-' + stadt_nach +
             '/' + datum_von + '-flexible/' + datum_bis + '-flexible?sort=bestflight_a')
    driver.get(kayak)
    sleep(randint(8,10))
    
    # Manchmal erscheint ein Pop-up, um dies zu prüfen und es zu schließen, kann der try-Block verwendet werden.
    try:
        xp_popup_close = '//button[contains(@id,"dialog-close") and contains(@class,"Button-No-Standard-Style close ")]'
        driver.find_elements_by_xpath(xp_popup_close)[5].click()
    except Exception as e:
        pass
    sleep(randint(60,95))
    print('lade mehr.....')
    
#     load_more()
    
    print('starte den ersten Scrape.....')
    df_flights_best = page_scrape()
    df_flights_best['sort'] = 'beste'
    sleep(randint(60,80))
    
    # Nehmen wir den niedrigsten Preis aus der Tabelle, die sich oben auf der Seite befindet.
    matrix = driver.find_elements_by_xpath('/*[contains(@id,"FlexMatrixCell")]')
    matrix_preise = [preis.text.replace('$','') for preis in matrix]
    matrix_preise = list(map(int, matrix_preise))
    matrix_min = min(matrix_preise)
    matrix_avg = sum(matrix_preise)/len(matrix_preise)
    
    print('wechsel zu den günstigsten Ergebnissen.....')
    günstige_ergebnisse = '//a[@data-code = "price"]'
    driver.find_element_by_xpath(günstige_ergebnisse).click()
    sleep(randint(60,90))
    print('lade mehr.....')
    
#     load_more()
    
    print('starte den zweiten Scrape.....')
    df_flights_cheap = page_scrape()
    df_flights_cheap['sort'] = 'günstig'
    sleep(randint(60,80))
    
    print('wechsel zu den schnellsten Ergebnissen.....')
    schnelle_ergebnisse = '//a[@data-code = "duration"]'
    driver.find_element_by_xpath(schnelle_ergebnisse).click()  
    sleep(randint(60,90))
    print('lade mehr.....')
    
#     load_more()
    
    print('starte den dritten Scrape.....')
    df_flights_fast = page_scrape()
    df_flights_fast['sort'] = 'schnell'
    sleep(randint(60,80))
    
    # Speichern des neuen Frames in einer Excel-Datei, deren Name die Städte und Daten widerspiegelt.
    final_df = df_flights_cheap.append(df_flights_best).append(df_flights_fast)
    final_df.to_excel('search_backups//{}_flights_{}-{}_von_{}_nach_{}.xlsx'.format(strftime("%Y%m%d-%H%M"),
                                                                                   stadt_von, stadt_nach, 
                                                                                   datum_von, datum_bis), index=False)
    print('Df gespeichert.....')
    
    # Man kann beobachten, wie die Vorhersage, die von der Website gegeben wird, mit der Realität übereinstimmt.
    xp_loading = '//div[contains(@id,"advice")]'
    loading = driver.find_element_by_xpath(xp_loading).text
    xp_prediction = '//span[@class="info-text"]'
    vorhersage = driver.find_element_by_xpath(xp_prediction).text
    print(loading+'n'+vorhersage)
    
    # Manchmal enthält die Variable loading diesen String, der später Probleme beim Versenden der E-Mail verursacht.
    # Wenn dies passiert, ändern wir ihn in "Nicht sicher"
    komisch = '¯_(ツ)_/¯'
    if loading == komisch:
        loading = 'Nicht sicher'
    
    benutzername = 'DEINEEMAIL@hotmail.com'
    passwort = 'DEIN PASSWORT'

    server = smtplib.SMTP('smtp.outlook.com', 587)
    server.ehlo()
    server.starttls()
    server.login(benutzername, passwort)
    msg = ('Betreff: Flug-Scraper
Günstigster Flug: {}nDurchschnittspreis: {}nnEmpfehlung: {}nnEnde der Nachricht'.format(matrix_min, matrix_avg, (loading+'n'+vorhersage)))
    nachricht = MIMEMultipart()
    nachricht['Von'] = 'DEINEEMAIL@hotmail.com'
    nachricht['an'] = 'DEINEANDEREEMAIL@domain.com'
    server.sendmail('DEINEEMAIL@hotmail.com', 'DEINEANDEREEMAIL@domain.com', msg)
    print('E-Mail gesendet.....')

Ich habe dieses Skript mit einem Outlook-Konto (hotmail.com) getestet. Ich habe es nicht auf die korrekte Funktion mit einem Gmail-Konto überprüft, das ist ein sehr beliebtes E-Mail-System, aber es gibt viele mögliche Varianten. Wenn Sie jedoch ein Hotmail-Konto verwenden, reicht es aus, Ihre Daten in den Code einzugeben, damit alles funktioniert.

Wenn Sie herausfinden möchten, was genau in bestimmten Abschnitten des Codes dieser Funktion ausgeführt wird, können Sie sie kopieren und damit experimentieren. Experimente mit dem Code sind der einzige Weg, um ihn wirklich zu verstehen.

Fertiges System

Jetzt, da alles, was wir besprochen haben, erledigt ist, können wir eine einfache Schleife erstellen, in der unsere Funktionen aufgerufen werden. Das Skript fordert den Benutzer auf, Daten zu Städten und Daten einzugeben. Wenn Sie das Skript ständig neu starten, werden Sie wahrscheinlich nicht jedes Mal diese Daten manuell eingeben wollen, daher können die entsprechenden Zeilen während der Testphase auskommentiert werden, während die darunter liegenden, in denen die benötigten Daten festgelegt sind, wieder einkommentiert werden.

city_from = input('Aus welcher Stadt? ')
city_to = input('Wohin? ')
date_start = input('Um welches Abreisedatum möchten Sie suchen? Bitte nur im Format YYYY-MM-DD verwenden ')
date_end = input('Wann zurück? Bitte nur im Format YYYY-MM-DD verwenden ')

# city_from = 'LIS'
# city_to = 'SIN'
# date_start = '2019-08-21'
# date_end = '2019-09-07'

for n in range(0,5):
    start_kayak(city_from, city_to, date_start, date_end)
    print('Iteration {} wurde abgeschlossen @ {}'.format(n, strftime("%Y%m%d-%H%M")))
    
    # Warten Sie 4 Stunden
    sleep(60*60*4)
    print('Schlaf beendet.....')

So sieht der Testlauf des Skripts aus.
Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.
Testlauf des Skripts

Ergebnisse

Wenn Sie es bis zu diesem Punkt geschafft haben — herzlichen Glückwunsch! Jetzt haben Sie einen funktionierenden Web-Scraper, auch wenn ich bereits viele Möglichkeiten zur Verbesserung sehe. Zum Beispiel könnte er mit Twilio integriert werden, um anstelle von E-Mails Textnachrichten zu senden. Sie könnten ein VPN oder etwas ähnliches nutzen, um gleichzeitig Ergebnisse von mehreren Servern zu erhalten. Es gibt auch das gelegentlich auftretende Problem, dass die Website überprüft, ob der Benutzer ein Mensch ist, aber auch dieses Problem kann gelöst werden. Jedenfalls haben Sie jetzt eine Grundlage, die Sie nach Belieben erweitern können. Zum Beispiel könnte die Excel-Datei als Anhang an den Benutzer in einer E-Mail gesendet werden.

Python ist ein hilfreiches Tool zur Suche nach günstigen Flugtickets für Reisende.

Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte melden Sie sich an.Sind Sie an Contour interessiert?

Nutzen Sie Web-Scraping-Technologien?

  • Ja

  • Nein

8 Nutzer haben abgestimmt. 1 Nutzer hat sich enthalten.

Quelle: habr.com

Erwerben Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster