Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen

Den Auteur vum Artikel, d'Iwwersetzung vun deem mir haut verëffentlechen, seet datt säin Zil ass iwwer d'Entwécklung vun engem Web Scraper am Python mat Selenium ze schwätzen, deen no Fluchbilljee Präisser sicht. Bei der Sich no Tickete gi flexibel Datume benotzt (+- 3 Deeg par rapport zu den spezifizéierten Datumen). De Scraper späichert d'Sichresultater an enger Excel-Datei a schéckt d'Persoun, déi d'Sich gemaach huet, eng E-Mail mat engem Resumé vun deem wat se fonnt hunn. D'Zil vun dësem Projet ass Reesender ze hëllefen déi bescht Offeren ze fannen.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen

Wann Dir d'Material versteet, fillt Dir Iech verluer, kuckt op dat Artikel.

Wat wäerte mir sichen?

Dir sidd fräi de System hei beschriwwen ze benotzen wéi Dir wëllt. Zum Beispill hunn ech et benotzt fir Weekend Touren an Ticketen fir meng Heemechtsstad ze sichen. Wann Dir sérieux sidd fir profitabel Ticketen ze fannen, kënnt Dir de Skript um Server lafen (einfach Server, fir 130 Rubelen pro Mount, ass ganz gëeegent fir dëst) a sécherstellen, datt et eemol oder zweemol am Dag leeft. Sichresultater ginn Iech per E-Mail geschéckt. Ausserdeem empfeelen ech alles opzestellen, sou datt de Skript eng Excel-Datei mat Sichresultater an engem Dropbox-Ordner späichert, deen Iech erlaabt esou Dateien iwwerall an zu all Moment ze gesinn.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Ech hunn nach keng Tariffer mat Feeler fonnt, awer ech mengen et ass méiglech

Wann Dir sicht, wéi scho gesot, gëtt e "flexibelen Datum" benotzt; de Skript fënnt Offeren déi bannent dräi Deeg vun den uginnen Datumen sinn. Och wann Dir de Skript leeft, sicht et no Offeren an nëmmen eng Richtung, et ass einfach ze änneren, sou datt et Daten iwwer verschidde Fluchrichtungen sammelt. Mat senger Hëllef kënnt Dir souguer no falschen Tariffer kucken, sou Entdeckunge kënne ganz interessant sinn.

Firwat braucht Dir eng aner Web Scraper?

Wéi ech fir d'éischt ugefaang hunn Web-Schrauwen, war ech éierlech gesot net besonnesch drun interesséiert. Ech wollt méi Projeten am Beräich vun der prévisiver Modelléierung, der Finanzanalyse, an eventuell och am Beräich vun der Analyse vun der emotionaler Faarf vun Texter maachen. Awer et huet sech erausgestallt datt et ganz interessant war erauszefannen wéi een e Programm erstellt deen Daten vu Websäiten sammelt. Wéi ech an dësem Thema verdéift hunn, hunn ech gemierkt datt d'Webschrauwen den "Motor" vum Internet ass.

Dir mengt vläicht datt dëst eng ze fett Ausso ass. Awer betruecht datt Google ugefaang huet mat engem Web Scraper deen de Larry Page mat Java a Python erstallt huet. Google Roboter hunn den Internet exploréiert a probéiert seng Benotzer déi bescht Äntwerten op hir Froen ze ginn. Web Scraping huet endlos Uwendungen, an och wann Dir un eppes anescht an Data Science interesséiert sidd, braucht Dir e puer Schrauwen Fäegkeeten fir d'Donnéeën ze kréien déi Dir braucht fir ze analyséieren.

Ech hunn e puer vun den Techniken hei benotzt an engem wonnerbar fonnt d'Buch iwwer Web Scraping, déi ech viru kuerzem kaaft hunn. Et enthält vill einfach Beispiller an Iddie fir praktesch Uwendung vun deem wat Dir geléiert hutt. Zousätzlech gëtt et e ganz interessant Kapitel iwwer de Contournement vun reCaptcha Schecken. Dëst koum als Neiegkeet fir mech, well ech net emol wousst datt et speziell Tools a souguer ganz Servicer fir sou Probleemer ze léisen.

Hues du gär reesen?!

Op déi einfach an zimlech harmlos Fro, déi am Titel vun dëser Rubrik gestallt gëtt, kënnt Dir dacks eng positiv Äntwert héieren, begleet vun e puer Geschichten aus de Reesen vun der Persoun, un déi et gefrot gouf. Déi meescht vun eis wäerten d'accord sinn datt Reesen e super Wee ass fir Iech an nei kulturell Ëmfeld z'ënnerhalen an Ären Horizont ze erweideren. Wann Dir awer een freet ob se gären no Fluchbilljeeën sichen, sinn ech sécher datt d'Äntwert net sou positiv wäert sinn. Tatsächlech kënnt Python eis hei zur Hëllef.

Déi éischt Aufgab, déi mir musse léisen op de Wee fir e System ze kreéieren fir Informatioun iwwer Fluchbilljeeën ze sichen, wäert eng passend Plattform auswielen, aus där mir Informatioun huelen. Dëse Problem ze léisen war net einfach fir mech, awer um Enn hunn ech de Kayak Service gewielt. Ech hunn d'Servicer vu Momondo, Skyscanner, Expedia, an e puer anerer probéiert, awer d'Roboterschutzmechanismen op dës Ressourcen waren onduerchsiichtlech. No e puer Versich, während deenen ech mat Luuchten, Foussgängersträifen a Vëloen ze dinn hunn, d'Systemer ze iwwerzeegen, datt ech Mënsch wier, hunn ech decidéiert datt de Kajak am Beschten fir mech passt, obwuel och wann Ze vill Säite gelueden sinn. an enger kuerzer Zäit, a Schecken fänken och. Ech hunn et fäerdeg bruecht de Bot Ufroen op de Site mat Intervalle vu 4 bis 6 Stonnen ze schécken, an alles huet gutt geschafft. Vun Zäit zu Zäit entstinn Schwieregkeeten wann Dir mam Kayak schafft, awer wa se ufänken Iech mat Schecken ze pesteren, da musst Dir entweder manuell mat hinnen handelen an dann de Bot starten, oder e puer Stonnen waarden an d'Schecken sollen ophalen. Wann néideg, kënnt Dir de Code einfach fir eng aner Plattform adaptéieren, a wann Dir dat maacht, kënnt Dir et an de Kommentarer mellen.

Wann Dir just mat Web Scraping ufänkt a wësst net firwat verschidde Websäite mat deem kämpfen, dann ier Dir Ären éischte Projet an dësem Beräich ufänkt, maacht Iech selwer eng Faveur a maacht eng Google Sich no de Wierder "Web Scraping Etiquette" . Är Experimenter kënne méi fréi ophalen wéi Dir denkt, wann Dir Webschrauwen onverstänneg mécht.

Schrëtt;

Hei ass en allgemengen Iwwerbléck iwwer wat an eisem Web Scraper Code geschitt:

  • Import déi néideg Bibliothéiken.
  • Eng Google Chrome Tab opmaachen.
  • Rufft eng Funktioun un, déi de Bot ufänkt, laanscht d'Stied an d'Datumer déi benotzt gi wann Dir no Ticketen sicht.
  • Dës Funktioun hëlt déi éischt Sichresultater, sortéiert no Best, a klickt op e Knäppchen fir méi Resultater ze lueden.
  • Eng aner Funktioun sammelt Daten vun der ganzer Säit a bréngt en Dateframe zréck.
  • Déi zwee virdru Schrëtt gi mat Sortéierungstypen no Ticketpräis (bëlleg) an duerch Fluchgeschwindegkeet (schnellste) duerchgefouert.
  • De Benotzer vum Skript gëtt eng E-Mail geschéckt mat engem Zesummefaassung vun den Ticketpräisser (bëllegst Ticketen an duerchschnëttlech Präis), an en Dateframe mat Informatioun, déi no den dräi uewe genannten Indikatoren zortéiert gëtt, gëtt als Excel-Datei gespäichert.
  • All déi uewe genannte Aktiounen ginn an engem Zyklus no enger spezifizéierter Zäit gemaach.

Et sollt bemierkt datt all Selenium Projet mat engem Web Chauffer ufänkt. ech benotzen Chromedriver, Ech schaffen mat Google Chrome, awer et ginn aner Optiounen. PhantomJS a Firefox sinn och populär. Nodeems Dir de Chauffer erofgelueden hutt, musst Dir en an de passenden Dossier placéieren, an dëst fäerdeg d'Virbereedung fir säi Gebrauch. Déi éischt Zeilen vun eisem Skript öffnen eng nei Chrome Tab.

Denkt drun datt ech a menger Geschicht net probéieren neien Horizont opzemaachen fir super Deals op Fluchbilljeeën ze fannen. Et gi vill méi fortgeschratt Methoden fir no sou Offeren ze sichen. Ech wëll just de Lieser vun dësem Material en einfachen awer praktesche Wee bidden fir dëse Problem ze léisen.

Hei ass de Code iwwer dee mir hei uewen geschwat hunn.

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

# Используйте тут ваш путь к chromedriver!
chromedriver_path = 'C:/{YOUR PATH HERE}/chromedriver_win32/chromedriver.exe'

driver = webdriver.Chrome(executable_path=chromedriver_path) # Этой командой открывается окно Chrome
sleep(2)

Um Ufank vum Code kënnt Dir d'Paketimportbefehle gesinn, déi während eisem Projet benotzt ginn. Also, randint benotzt fir de Bot fir eng zoufälleg Zuel vu Sekonnen ze "schlofen" ze maachen ier Dir eng nei Sichoperatioun ufänkt. Normalerweis kann keen eenzege Bot ouni dëst maachen. Wann Dir den uewe genannte Code leeft, gëtt eng Chrome Fënster op, déi de Bot benotzt fir mat Siten ze schaffen.

Loosst eis e klengen Experiment maachen an d'kayak.com Websäit an enger separater Fënster opmaachen. Mir wäerten d'Stad auswielen, aus där mir fléien, an d'Stad op déi mir wëllen kommen, souwéi d'Flugdatum. Wann Dir Datume wielt, gitt sécher datt d'Gamme vu +-3 Deeg benotzt gëtt. Ech hunn de Code geschriwwen a berücksichtegt wat de Site als Äntwert op esou Ufroe produzéiert. Wann Dir zum Beispill nëmmen Tickete fir spezifizéiert Datume sichen musst, da gëtt et eng grouss Wahrscheinlechkeet datt Dir de Botcode muss änneren. Wann ech iwwer de Code schwätzen, ginn ech entspriechend Erklärungen, awer wann Dir Iech duercherneen fillt, loosst mech wëssen.

Elo klickt op de Sich Knäppchen a kuckt de Link an der Adressbar. Et sollt ähnlech sinn wéi de Link deen ech am Beispill hei ënnen benotzen wou d'Variabel deklaréiert ass kayak, déi d'URL späichert, an d'Method gëtt benotzt get Web Chauffer. Nodeems Dir op de Sichknäppchen geklickt hutt, sollten d'Resultater op der Säit erschéngen.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Wann ech de Kommando benotzt get méi wéi zwee oder dräi Mol bannent e puer Minutten, Ech gouf gefrot fir d'Verifizéierung mat reCaptcha ofzeschléissen. Dir kënnt dës Scheck manuell passéieren a weider experimentéieren bis de System decidéiert en neie Scheck auszeféieren. Wann ech de Skript getest hunn, schéngt et wéi wann déi éischt Sich Sessioun ëmmer glat gaang ass, also wann Dir mam Code experimentéiere wëllt, musst Dir nëmmen periodesch manuell kontrolléieren an de Code lafen loossen, mat laangen Intervalle tëscht Sich Sessiounen. A wann Dir driwwer denkt, ass et onwahrscheinlech datt eng Persoun Informatioun iwwer Ticketpräisser brauch, déi mat 10-Minuten Intervalle tëscht Sichoperatioune kritt gëtt.

Schafft mat enger Säit mat XPath

Also hu mir eng Fënster opgemaach an de Site gelueden. Fir Präisser an aner Informatioun ze kréien, musse mir XPath Technologie oder CSS Selektor benotzen. Ech hu beschloss mat XPath ze halen an hunn net de Besoin gefillt CSS Selektoren ze benotzen, awer et ass ganz méiglech esou ze schaffen. Navigéiere ronderëm eng Säit mat XPath kann komplizéiert sinn, an och wann Dir d'Techniken benotzt, déi ech beschriwwen hunn dat Artikel, deen d'Kopie vun den entspriechende Identifizéierer aus dem Säitcode involvéiert huet, hunn ech gemierkt datt dëst tatsächlech net den optimale Wee ass fir op déi néideg Elementer ze kommen. Iwwregens, an dat D'Buch bitt eng exzellent Beschreiwung vun de Grondlagen fir mat Säiten ze schaffen déi XPath an CSS Selektor benotzen. Dëst ass wéi déi entspriechend Web Chauffer Method ausgesäit.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Also, loosst eis weider un de Bot schaffen. Loosst eis d'Fäegkeeten vum Programm benotze fir déi bëllegst Ticketen ze wielen. Am folgende Bild gëtt den XPath Selektorcode a rout markéiert. Fir de Code ze gesinn, musst Dir op d'Säitelement klickt, an deem Dir interesséiert sidd, a wielt de Kommando Inspect aus dem Menü deen erschéngt. Dëse Kommando kann fir verschidde Säitelementer genannt ginn, de Code vun deem gëtt am Code Viewer ugewisen a markéiert.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
View Säit Code

Fir d'Bestätegung vu menger Begrënnung iwwer d'Nodeeler vun der Kopie vun der Selektor aus dem Code ze fannen, oppassen op déi folgend Funktiounen.

Dëst ass wat Dir kritt wann Dir de Code kopéiert:

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

Fir sou eppes ze kopéieren, musst Dir op d'Sektioun vum Code klickt, an deem Dir interesséiert sidd, a wielt de Kommando Kopie > Kopie XPath aus dem Menü deen erschéngt.

Hei ass wat ech benotzt hunn fir de Bëllegst Knäppchen ze definéieren:

cheap_results = ‘//a[@data-code = "price"]’

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Kommando kopéieren> XPath kopéieren

Et ass ganz offensichtlech datt déi zweet Optioun vill méi einfach ausgesäit. Wann se benotzt, sicht et no engem Element a dat den Attribut huet data-codegläich op price. Wann Dir déi éischt Optioun benotzt, gëtt d'Element gesicht id déi gläich ass wtKI-price_aTab, an den XPath Wee zum Element gesäit aus /div[1]/div/div/div[1]/div/span/span. Eng XPath Ufro wéi dës op eng Säit wäert den Trick maachen, awer nëmmen eemol. Ech kann dat elo soen id wäert déi nächst Kéier d'Säit gelueden änneren. Charakter Sequenz wtKI ännert sech dynamesch all Kéier wann d'Säit gelueden ass, sou datt de Code deen se benotzt wäert nëtzlos sinn no der nächster Säit nei lued. Also huelt e bëssen Zäit fir XPath ze verstoen. Dëst Wëssen wäert Iech gutt déngen.

Wéi och ëmmer, et sollt bemierkt datt d'Kopie vun XPath Selektoren nëtzlech ka sinn wann Dir mat zimlech einfache Siten schafft, a wann Dir bequem sidd mat dësem, ass et näischt falsch.

Loosst eis elo iwwerdenken wat Dir maache musst wann Dir all d'Sichresultater an e puer Zeilen an enger Lëscht kritt. Ganz einfach. All Resultat ass an engem Objet mat enger Klass resultWrapper. Luede all d'Resultater kann an enger Loop gemaach ginn ähnlech wéi déi hei ënnendrënner.

Et sollt bemierkt datt wann Dir déi uewe versteet, da sollt Dir de gréissten Deel vum Code einfach verstoen, dee mir analyséieren. Wéi dëse Code leeft, kréien mir Zougang zu deem wat mir brauchen (tatsächlech d'Element an deem d'Resultat gewéckelt ass) mat enger Aart vu Weespezifizéierende Mechanismus (XPath). Dëst gëtt gemaach fir den Text vum Element ze kréien an en an en Objet ze placéieren aus deem d'Donnéeë gelies kënne ginn (fir d'éischt benotzt flight_containers, dann - flights_list).

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Déi éischt dräi Zeilen ginn ugewisen a mir kënne kloer alles gesinn wat mir brauchen. Wéi och ëmmer, mir hu méi interessant Weeër fir Informatioun ze kréien. Mir mussen Daten vun all Element separat huelen.

Gitt op d'Aarbecht!

Deen einfachste Wee fir eng Funktioun ze schreiwen ass zousätzlech Resultater ze lueden, sou datt mir ufänken. Ech wéilt d'Zuel vun de Flich maximéieren, iwwer déi de Programm Informatioun kritt, ouni Verdacht am Service z'erhéijen, deen zu enger Inspektioun féiert, also klickt ech op de Lued méi Resultater Knäppchen eemol all Kéier wann d'Säit ugewise gëtt. An dësem Code sollt Dir op de Block oppassen try, déi ech derbäigesat hunn, well heiansdo de Knäppchen net richteg lued. Wann Dir dëst och begéint, kommentéiert Uruff un dës Funktioun am Funktiounscode start_kayak, déi mir hei ënnen kucken.

# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
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

Elo, no enger laanger Analyse vun dëser Funktioun (heiansdo kann ech mech matdroen), si mir bereet eng Funktioun ze deklaréieren déi d'Säit schrauwen.

Ech hu scho meeschtens gesammelt wat gebraucht gëtt an der folgender Funktioun genannt page_scrape. Heiansdo ginn déi zréckginn Weedaten kombinéiert, also benotzen ech eng einfach Method fir se ze trennen. Zum Beispill, wann ech Verännerlechen fir d'éischte Kéier benotzen section_a_list и section_b_list. Eis Funktioun gëtt en Dateframe zréck flights_df, Dëst erlaabt eis d'Resultater ze trennen aus verschiddenen Datesortéierungsmethoden a spéider kombinéieren.

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

Ech hu probéiert d'Variabelen ze nennen sou datt de Code verständlech wier. Erënneren, datt Verännerlechen ugefaange mat a gehéieren zu der éischter Etapp vum Wee, an b - op déi zweet. Loosst eis op déi nächst Funktioun goen.

Ënnerstëtzung Mechanismen

Mir hunn elo eng Funktioun déi eis erlaabt zousätzlech Sichresultater ze lueden an eng Funktioun fir dës Resultater ze veraarbecht. Dësen Artikel kéint hei eriwwer sinn, well dës zwou Funktiounen alles ubidden wat Dir braucht fir Säiten ze schrauwen déi Dir selwer opmaache kënnt. Awer mir hunn nach net e puer vun den uewe diskutéierte Hëllefsmechanismen berücksichtegt. Zum Beispill ass dëst de Code fir E-Mailen an e puer aner Saachen ze schécken. All dëst kann an der Funktioun fonnt ginn start_kayak, déi mir elo betruechten.

Fir dës Funktioun ze schaffen, braucht Dir Informatiounen iwwer Stied an Datumen. Mat Hëllef vun dëser Informatioun bilden se e Link an enger Variabel kayak, déi benotzt gëtt fir Iech op eng Säit ze huelen déi Sichresultater enthält, déi no hirem beschte Match mat der Ufro zortéiert sinn. No der éischter Scraping Sessioun wäerte mir mat de Präisser an der Tabell uewen op der Säit schaffen. Mir fanne nämlech de Minimum Ticketpräis an den Duerchschnëttspräis. All dëst, zesumme mat der Prognose vum Site erausginn, gëtt per E-Mail geschéckt. Op der Säit soll déi entspriechend Tabell an der ieweschter lénkser Ecke sinn. Mat dëser Tabell ze schaffen, iwwregens, kann e Feeler bei der Sich mat exakten Datume verursaachen, well an dësem Fall ass den Dësch net op der Säit ugewisen.

def start_kayak(city_from, city_to, date_start, date_end):
    """City codes - it's the IATA codes!
    Date format -  YYYY-MM-DD"""
    
    kayak = ('https://www.kayak.com/flights/' + city_from + '-' + city_to +
             '/' + date_start + '-flexible/' + date_end + '-flexible?sort=bestflight_a')
    driver.get(kayak)
    sleep(randint(8,10))
    
    # иногда появляется всплывающее окно, для проверки на это и его закрытия можно воспользоваться блоком try
    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('loading more.....')
    
#     load_more()
    
    print('starting first scrape.....')
    df_flights_best = page_scrape()
    df_flights_best['sort'] = 'best'
    sleep(randint(60,80))
    
    # Возьмём самую низкую цену из таблицы, расположенной в верхней части страницы
    matrix = driver.find_elements_by_xpath('//*[contains(@id,"FlexMatrixCell")]')
    matrix_prices = [price.text.replace('$','') for price in matrix]
    matrix_prices = list(map(int, matrix_prices))
    matrix_min = min(matrix_prices)
    matrix_avg = sum(matrix_prices)/len(matrix_prices)
    
    print('switching to cheapest results.....')
    cheap_results = '//a[@data-code = "price"]'
    driver.find_element_by_xpath(cheap_results).click()
    sleep(randint(60,90))
    print('loading more.....')
    
#     load_more()
    
    print('starting second scrape.....')
    df_flights_cheap = page_scrape()
    df_flights_cheap['sort'] = 'cheap'
    sleep(randint(60,80))
    
    print('switching to quickest results.....')
    quick_results = '//a[@data-code = "duration"]'
    driver.find_element_by_xpath(quick_results).click()  
    sleep(randint(60,90))
    print('loading more.....')
    
#     load_more()
    
    print('starting third scrape.....')
    df_flights_fast = page_scrape()
    df_flights_fast['sort'] = 'fast'
    sleep(randint(60,80))
    
    # Сохранение нового фрейма в Excel-файл, имя которого отражает города и даты
    final_df = df_flights_cheap.append(df_flights_best).append(df_flights_fast)
    final_df.to_excel('search_backups//{}_flights_{}-{}_from_{}_to_{}.xlsx'.format(strftime("%Y%m%d-%H%M"),
                                                                                   city_from, city_to, 
                                                                                   date_start, date_end), index=False)
    print('saved df.....')
    
    # Можно следить за тем, как прогноз, выдаваемый сайтом, соотносится с реальностью
    xp_loading = '//div[contains(@id,"advice")]'
    loading = driver.find_element_by_xpath(xp_loading).text
    xp_prediction = '//span[@class="info-text"]'
    prediction = driver.find_element_by_xpath(xp_prediction).text
    print(loading+'n'+prediction)
    
    # иногда в переменной loading оказывается эта строка, которая, позже, вызывает проблемы с отправкой письма
    # если это прозошло - меняем её на "Not Sure"
    weird = '¯_(ツ)_/¯'
    if loading == weird:
        loading = 'Not sure'
    
    username = '[email protected]'
    password = 'YOUR PASSWORD'

    server = smtplib.SMTP('smtp.outlook.com', 587)
    server.ehlo()
    server.starttls()
    server.login(username, password)
    msg = ('Subject: Flight Scrapernn
Cheapest Flight: {}nAverage Price: {}nnRecommendation: {}nnEnd of message'.format(matrix_min, matrix_avg, (loading+'n'+prediction)))
    message = MIMEMultipart()
    message['From'] = '[email protected]'
    message['to'] = '[email protected]'
    server.sendmail('[email protected]', '[email protected]', msg)
    print('sent email.....')

Ech hunn dëse Skript getest mat engem Outlook Kont (hotmail.com). Ech hunn et net getest fir richteg mat engem Gmail Kont ze schaffen, dësen E-Mail System ass zimlech populär, awer et gi vill méiglech Optiounen. Wann Dir e Hotmail Kont benotzt, fir datt alles funktionnéiert, musst Dir just Är Donnéeën an de Code aginn.

Wann Dir wëllt verstoen wat genee a spezifesche Sektioune vum Code fir dës Funktioun gemaach gëtt, kënnt Dir se kopéieren an experimentéieren mat hinnen. Experimentéiere mam Code ass deen eenzege Wee fir et wierklech ze verstoen.

Prett System

Elo datt mir alles gemaach hunn, iwwer wat mir geschwat hunn, kënne mir eng einfach Loop erstellen déi eis Funktiounen nennt. De Skript freet Daten vum Benotzer iwwer Stied an Datumen. Wann Dir mat konstante Restart vum Skript testt, ass et onwahrscheinlech datt Dir dës Donnéeën all Kéier manuell wëllt aginn, sou datt déi entspriechend Zeilen, fir d'Zäit vum Test, kommentéiert kënne ginn andeems Dir déi ënnert hinnen unkommentéiert, an deenen d'Donnéeën néideg sinn vum Skript ass hardcoded.

city_from = input('From which city? ')
city_to = input('Where to? ')
date_start = input('Search around which departure date? Please use YYYY-MM-DD format only ')
date_end = input('Return when? Please use YYYY-MM-DD format only ')

# 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 {} was complete @ {}'.format(n, strftime("%Y%m%d-%H%M")))
    
    # Ждём 4 часа
    sleep(60*60*4)
    print('sleep finished.....')

Dëst ass wéi en Testrun vum Skript ausgesäit.
Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen
Test Laf vum Skript

Resultater

Wann Dir et esou wäit gemaach hutt, Gratulatioun! Dir hutt elo e funktionnéierende Webscraper, obwuel ech scho vill Weeër gesinn fir et ze verbesseren. Zum Beispill kann et mat Twilio integréiert ginn, sou datt et SMSen anstatt E-Mailen schéckt. Dir kënnt e VPN oder soss eppes benotze fir gläichzäiteg Resultater vu verschiddene Serveren ze kréien. Et gëtt och e periodesch entstinn Problem mat der Iwwerpréiwung vum Site Benotzer fir ze kucken ob hien eng Persoun ass, awer dëse Problem kann och geléist ginn. Op alle Fall, elo hutt Dir eng Basis déi Dir ausbaue kënnt wann Dir wëllt. Zum Beispill, gitt sécher datt eng Excel-Datei un de Benotzer als Uschloss un eng E-Mail geschéckt gëtt.

Python - en Assistent fir bëlleg Flugbilljeeën ze fannen fir déi, déi gär reesen

Nëmme registréiert Benotzer kënnen un der Ëmfro deelhuelen. Umellen, wann ech glift.

Benotzt Dir Web Scraping Technologien?

  • datt

  • Nee

8 Benotzer hunn gestëmmt. 1 Benotzer huet sech enthalen.

Source: will.com

Setzt e Commentaire