Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo

Avtor članka, katerega prevod objavljamo danes, pravi, da je njegov cilj govoriti o razvoju spletnega strgala v Pythonu z uporabo Seleniuma, ki išče cene letalskih kart. Pri iskanju vstopnic se uporabljajo fleksibilni datumi (+- 3 dni glede na navedene datume). Strgalo shrani rezultate iskanja v Excelovo datoteko in osebi, ki je iskala, pošlje e-pošto s povzetkom tega, kar je našla. Cilj tega projekta je pomagati popotnikom najti najboljše ponudbe.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo

Če se ob razumevanju snovi počutite izgubljeni, si oglejte to Članek.

Kaj bomo iskali?

Tukaj opisani sistem lahko uporabljate po želji. Na primer, uporabil sem ga za iskanje vikend izletov in vozovnic za moj domači kraj. Če ste resni pri iskanju donosnih vstopnic, lahko zaženete skript na strežniku (preprosto strežnik, za 130 rubljev na mesec, je povsem primeren za to) in poskrbite, da deluje enkrat ali dvakrat na dan. Rezultati iskanja vam bodo poslani po e-pošti. Poleg tega priporočam, da vse nastavite tako, da skript shrani datoteko Excel z rezultati iskanja v mapo Dropbox, kar vam bo omogočilo ogled takšnih datotek od kjerkoli in kadarkoli.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Nisem še našel tarif z napakami, vendar mislim, da je možno

Pri iskanju se, kot že omenjeno, uporablja “prilagodljiv datum”, skripta najde ponudbe, ki so znotraj treh dni od danih datumov. Čeprav pri izvajanju skripta išče ponudbe samo v eni smeri, jo je enostavno spremeniti tako, da lahko zbira podatke o več smereh letenja. Z njegovo pomočjo lahko celo iščete napačne tarife, takšne najdbe so lahko zelo zanimive.

Zakaj potrebujete drugo spletno strgalo?

Ko sem prvič začel s spletnim strganjem, me to iskreno ni posebej zanimalo. Želel sem delati več projektov na področju prediktivnega modeliranja, finančne analize in po možnosti na področju analize čustvene obarvanosti besedil. Izkazalo pa se je, da je zelo zanimivo ugotavljati, kako ustvariti program, ki zbira podatke s spletnih strani. Ko sem se poglobil v to temo, sem ugotovil, da je spletno strganje »motor« interneta.

Morda mislite, da je to preveč drzna izjava. Toda upoštevajte, da je Google začel s spletnim strgalom, ki ga je Larry Page ustvaril z uporabo Jave in Pythona. Googlovi roboti raziskujejo internet in skušajo uporabnikom ponuditi najboljše odgovore na njihova vprašanja. Spletno strganje ima neskončne možnosti uporabe in tudi če vas zanima kaj drugega v Data Science, boste potrebovali nekaj spretnosti strganja, da dobite podatke, ki jih potrebujete za analizo.

Nekaj ​​tehnik, ki se tukaj uporabljajo, se mi je zdelo čudovitih knjigo o spletnem strganju, ki sem ga pred kratkim pridobil. Vsebuje veliko preprostih primerov in idej za praktično uporabo naučenega. Poleg tega obstaja zelo zanimivo poglavje o izogibanju preverjanju reCaptcha. To je zame bila novica, saj sploh nisem vedel, da obstajajo posebna orodja in celo cele storitve za reševanje tovrstnih težav.

Ali rad potuješ?!

Na preprosto in dokaj neškodljivo vprašanje, zastavljeno v naslovu te rubrike, lahko pogosto slišite pozitiven odgovor, ki ga spremlja nekaj zgodb s potovanj osebe, ki ji je bilo postavljeno. Večina od nas bi se strinjala, da je potovanje odličen način, da se potopite v nova kulturna okolja in razširite svoja obzorja. Če pa koga vprašate, ali rad išče letalske karte, sem prepričan, da odgovor ne bo tako pozitiven. Pravzaprav nam Python tukaj priskoči na pomoč.

Prva naloga, ki jo moramo rešiti na poti do izdelave sistema za iskanje informacij o letalskih vozovnicah, bo izbira primerne platforme, iz katere bomo črpali informacije. Reševanje te težave mi ni bilo lahko, a sem se na koncu odločila za Kajak servis. Preizkusil sem storitve Momondo, Skyscanner, Expedia in nekaj drugih, vendar so bili robotski zaščitni mehanizmi na teh virih neprebojni. Po več poskusih, med katerimi sem se moral ukvarjati s semaforji, prehodi za pešce in kolesi, ko sem poskušal sisteme prepričati, da sem človek, sem se odločil, da je Kayak najbolj primeren zame, kljub dejstvu, da tudi če je naloženih preveč strani v kratkem pa se začnejo tudi kontrole. Uspelo mi je doseči, da je bot pošiljal zahteve na stran v intervalih od 4 do 6 ur in vse je delovalo v redu. Občasno se pri delu s Kajakom pojavijo težave, a če vas začnejo nadlegovati s preverjanji, jih morate bodisi obravnavati ročno in nato zagnati bota ali pa počakati nekaj ur in preverjanja naj prenehajo. Po potrebi lahko kodo preprosto prilagodite za drugo platformo in če to storite, lahko to prijavite v komentarjih.

Če ste šele začeli s spletnim strganjem in ne veste, zakaj se nekatera spletna mesta s tem spopadajo, potem preden začnete s svojim prvim projektom na tem področju, si naredite uslugo in v Googlu poiščite besedo "web scraping bonton" . Vaši poskusi se lahko končajo prej, kot si mislite, če spletno strganje izvajate nespametno.

Začetek

Tukaj je splošen pregled tega, kaj se bo zgodilo v naši kodi spletnega strgala:

  • Uvozite zahtevane knjižnice.
  • Odpiranje zavihka Google Chrome.
  • Pokličite funkcijo, ki zažene bota in mu posreduje mesta in datume, ki bodo uporabljeni pri iskanju vstopnic.
  • Ta funkcija vzame prve rezultate iskanja, razvrščene po najboljših, in klikne gumb za nalaganje več rezultatov.
  • Druga funkcija zbira podatke s celotne strani in vrne podatkovni okvir.
  • Prejšnja dva koraka se izvajata z uporabo tipov razvrščanja po ceni vozovnice (poceni) in po hitrosti leta (najhitrejši).
  • Uporabniku skripte se pošlje elektronsko sporočilo s povzetkom cen vozovnic (najcenejše karte in povprečna cena), podatkovni okvir z informacijami, razvrščenimi po treh zgoraj omenjenih indikatorjih, pa se shrani kot Excelova datoteka.
  • Vsa zgoraj navedena dejanja se izvajajo v ciklu po določenem časovnem obdobju.

Opozoriti je treba, da se vsak projekt Selenium začne s spletnim gonilnikom. jaz uporabljam Chromedriver, delam z Google Chromom, vendar obstajajo druge možnosti. Priljubljena sta tudi PhantomJS in Firefox. Po prenosu gonilnika ga morate postaviti v ustrezno mapo in s tem je priprava za njegovo uporabo končana. Prve vrstice našega skripta odprejo nov zavihek Chrome.

Ne pozabite, da v svoji zgodbi ne poskušam odpreti novih obzorij za iskanje odličnih ponudb letalskih vozovnic. Obstajajo veliko bolj napredne metode iskanja tovrstnih ponudb. Bralcem tega gradiva želim samo ponuditi preprost, a praktičen način za rešitev te težave.

Tukaj je koda, o kateri smo govorili zgoraj.

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)

Na začetku kode lahko vidite ukaze za uvoz paketov, ki se uporabljajo v našem projektu. Torej, randint uporablja se za to, da bot "zaspi" za naključno število sekund, preden začne novo operacijo iskanja. Ponavadi noben bot ne more brez tega. Če zaženete zgornjo kodo, se odpre Chromovo okno, ki ga bo bot uporabil za delo s spletnimi mesti.

Naredimo majhen poskus in odprimo spletno stran kayak.com v ločenem oknu. Izbrali bomo mesto, iz katerega bomo leteli, in mesto, kamor želimo priti, ter datume poleta. Pri izbiri datumov bodite pozorni na obseg +-3 dni. Kodo sem napisal ob upoštevanju tega, kar spletno mesto ustvari kot odgovor na takšne zahteve. Če morate na primer iskati vstopnice samo za določene datume, potem obstaja velika verjetnost, da boste morali spremeniti kodo bota. Ko govorim o kodi, podam ustrezna pojasnila, če pa ste zmedeni, mi sporočite.

Zdaj kliknite gumb za iskanje in poglejte povezavo v naslovni vrstici. Morala bi biti podobna povezavi, ki jo uporabljam v spodnjem primeru, kjer je deklarirana spremenljivka kayak, ki shrani URL, in uporabljena metoda get spletni gonilnik. Po kliku na gumb za iskanje bi se morali rezultati prikazati na strani.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Ko sem uporabil ukaz get Več kot dvakrat ali trikrat v nekaj minutah sem bil pozvan, da dokončam preverjanje z uporabo reCaptcha. To preverjanje lahko opravite ročno in nadaljujete z eksperimentiranjem, dokler se sistem ne odloči izvesti novega preverjanja. Ko sem preizkusil skript, se je zdelo, da je prva iskalna seja vedno potekala gladko, tako da bi morali, če bi želeli eksperimentirati s kodo, le občasno ročno preveriti in pustiti, da se koda izvaja, z uporabo dolgih intervalov med iskalnimi sejami. In če dobro pomislite, oseba verjetno ne bo potrebovala informacij o cenah vozovnic, prejetih v 10-minutnih intervalih med iskalnimi operacijami.

Delo s stranjo z uporabo XPath

Odprli smo okno in naložili stran. Za pridobitev cen in drugih informacij moramo uporabiti tehnologijo XPath ali izbirnike CSS. Odločil sem se, da bom ostal pri XPathu in nisem čutil potrebe po uporabi izbirnikov CSS, vendar je povsem mogoče delati na ta način. Krmarjenje po strani z uporabo XPath je lahko težavno in tudi če uporabljate tehnike, ki sem jih opisal v to članka, ki je vključeval kopiranje ustreznih identifikatorjev iz kode strani, sem ugotovil, da to dejansko ni optimalen način za dostop do potrebnih elementov. Mimogrede, v to V knjigi so odlično opisane osnove dela s stranmi z uporabo XPath in CSS izbirnikov. Takole izgleda ustrezna metoda spletnega gonilnika.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Torej, nadaljujmo z delom na botu. Izkoristimo zmožnosti programa za izbor najcenejših vstopnic. Na naslednji sliki je izbirna koda XPath označena z rdečo. Za ogled kode morate z desno miškino tipko klikniti element strani, ki vas zanima, in v meniju, ki se prikaže, izbrati ukaz Pregled. Ta ukaz je mogoče poklicati za različne elemente strani, katerih koda bo prikazana in označena v pregledovalniku kode.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Ogled kode strani

Da bi našli potrditev mojega razmišljanja o pomanjkljivostih kopiranja izbirnikov iz kode, bodite pozorni na naslednje lastnosti.

To je tisto, kar dobite, ko kopirate kodo:

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

Če želite kopirati nekaj takega, morate z desno tipko miške klikniti del kode, ki vas zanima, in v meniju, ki se pojavi, izbrati ukaz Kopiraj > Kopiraj XPath.

Za definiranje gumba Najcenejši sem uporabil naslednje:

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

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Kopiraj ukaz > Kopiraj XPath

Povsem očitno je, da je druga možnost videti veliko preprostejša. Ko je uporabljen, išče element a, ki ima atribut data-code, enako price. Pri uporabi prve možnosti se element išče id kar je enako wtKI-price_aTab, pot XPath do elementa pa izgleda takole /div[1]/div/div/div[1]/div/span/span. Poizvedba XPath, kot je ta, do strani bo pomagala, vendar samo enkrat. Takoj lahko rečem id se spremeni ob naslednjem nalaganju strani. Zaporedje znakov wtKI spreminja dinamično vsakič, ko se stran naloži, zato bo koda, ki jo uporablja, neuporabna po naslednjem ponovnem nalaganju strani. Zato si vzemite nekaj časa, da razumete XPath. To znanje vam bo dobro služilo.

Vendar je treba opozoriti, da je kopiranje izbirnikov XPath lahko uporabno pri delu s precej preprostimi mesti, in če vam to ustreza, ni s tem nič narobe.

Zdaj pa razmislimo, kaj storiti, če morate dobiti vse rezultate iskanja v več vrsticah znotraj seznama. Zelo preprosto. Vsak rezultat je znotraj predmeta z razredom resultWrapper. Nalaganje vseh rezultatov je mogoče izvesti v zanki, podobni spodnji.

Upoštevati je treba, da če razumete zgoraj navedeno, bi morali zlahka razumeti večino kode, ki jo bomo analizirali. Ko se ta koda izvaja, dostopamo do tistega, kar potrebujemo (pravzaprav do elementa, v katerega je zavit rezultat), z uporabo neke vrste mehanizma za določanje poti (XPath). To naredimo zato, da dobimo besedilo elementa in ga postavimo v predmet, iz katerega je mogoče brati podatke (prvo uporabljen flight_containers, potem - flights_list).

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Prve tri vrstice so prikazane in jasno vidimo vse, kar potrebujemo. Vendar pa imamo bolj zanimive načine pridobivanja informacij. Podatke moramo vzeti iz vsakega elementa posebej.

Pojdi v službo!

Funkcijo najlažje napišemo tako, da naložimo dodatne rezultate, tako da bomo s tem začeli. Rad bi maksimiziral število letov, o katerih program prejme podatke, ne da bi pri servisu vzbudil sume, ki vodijo do pregleda, zato ob vsakem prikazu strani enkrat kliknem gumb Naloži več rezultatov. V tej kodi bodite pozorni na blok try, ki sem ga dodal, ker se včasih gumb ne naloži pravilno. Če tudi vi naletite na to, komentirajte klice te funkcije v kodi funkcije start_kayak, ki si jih bomo ogledali v nadaljevanju.

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

Zdaj, po dolgi analizi te funkcije (včasih me lahko zanese), smo pripravljeni deklarirati funkcijo, ki bo strgala stran.

Večino potrebnega sem že zbral v naslednji funkciji, imenovani page_scrape. Včasih so vrnjeni podatki o poti združeni, zato jih ločim s preprosto metodo. Na primer, ko spremenljivke uporabim prvič section_a_list и section_b_list. Naša funkcija vrne podatkovni okvir flights_df, nam to omogoča, da ločimo rezultate, pridobljene z različnimi metodami razvrščanja podatkov, in jih kasneje združimo.

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

Poskušal sem poimenovati spremenljivke tako, da bo koda razumljiva. Ne pozabite, da spremenljivke, ki se začnejo z a pripadajo prvi stopnji poti in b - do drugega. Pojdimo na naslednjo funkcijo.

Podporni mehanizmi

Zdaj imamo funkcijo, ki nam omogoča nalaganje dodatnih rezultatov iskanja, in funkcijo za obdelavo teh rezultatov. Ta članek bi se lahko končal tukaj, saj ti dve funkciji ponujata vse, kar potrebujete za strganje strani, ki jih lahko odprete sami. Vendar še nismo upoštevali nekaterih pomožnih mehanizmov, o katerih smo govorili zgoraj. To je na primer koda za pošiljanje e-pošte in nekatere druge stvari. Vse to lahko najdete v funkciji start_kayak, ki ga bomo zdaj obravnavali.

Ta funkcija zahteva informacije o mestih in datumih. Z uporabo teh informacij oblikuje povezavo v spremenljivki kayak, ki se uporablja za preusmeritev na stran, ki bo vsebovala rezultate iskanja, razvrščene po njihovem najboljšem ujemanju s poizvedbo. Po prvem strganju bomo delali s cenami v tabeli na vrhu strani. Našli bomo namreč najnižjo ceno vozovnice in povprečno ceno. Vse to, skupaj z napovedjo, ki jo izda spletno mesto, bo poslano po e-pošti. Na strani naj bo ustrezna tabela v zgornjem levem kotu. Mimogrede, delo s to tabelo lahko povzroči napako pri iskanju z natančnimi datumi, saj v tem primeru tabela ni prikazana na strani.

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.....')

Ta skript sem preizkusil z računom Outlook (hotmail.com). Nisem preizkusil njegovega pravilnega delovanja z računom Gmail, ta e-poštni sistem je precej priljubljen, vendar obstaja veliko možnih možnosti. Če uporabljate račun Hotmail, morate le vnesti svoje podatke v kodo, da bo vse delovalo.

Če želite razumeti, kaj točno se dela v določenih delih kode za to funkcijo, jih lahko kopirate in eksperimentirate z njimi. Eksperimentiranje s kodo je edini način, da jo resnično razumemo.

Pripravljen sistem

Zdaj, ko smo naredili vse, o čemer smo govorili, lahko ustvarimo preprosto zanko, ki kliče naše funkcije. Skript od uporabnika zahteva podatke o mestih in datumih. Pri testiranju s stalnim ponovnim zagonom skripta verjetno ne boste želeli vsakič ročno vnesti teh podatkov, zato lahko ustrezne vrstice za čas testiranja komentirate tako, da odkomentirate tiste pod njimi, v katerih so podatki, ki jih potrebuje skript je trdo kodiran.

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.....')

Takole izgleda testni zagon skripte.
Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo
Testni zagon skripte

Rezultati

Če vam je uspelo tako daleč, čestitamo! Zdaj imate delujoče spletno strgalo, čeprav že vidim veliko načinov za njegovo izboljšavo. Na primer, lahko se integrira s Twiliom, tako da pošilja besedilna sporočila namesto e-pošte. Za hkratno prejemanje rezultatov iz več strežnikov lahko uporabite VPN ali kaj drugega. Občasno se pojavlja tudi težava s preverjanjem uporabnika spletnega mesta, ali je oseba, vendar je tudi to težavo mogoče rešiti. V vsakem primeru imate zdaj bazo, ki jo lahko po želji razširite. Prepričajte se na primer, da je datoteka Excel poslana uporabniku kot priloga k e-poštnemu sporočilu.

Python - pomočnik pri iskanju poceni letalskih kart za tiste, ki radi potujejo

V anketi lahko sodelujejo samo registrirani uporabniki. Prijaviti se, prosim.

Ali uporabljate tehnologije spletnega strganja?

  • Da

  • Št

Glasovalo je 8 uporabnikov. 1 uporabnik se je vzdržal.

Vir: www.habr.com

Dodaj komentar