Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati

Autor članka, čiji prijevod danas objavljujemo, kaže da je njegov cilj govoriti o razvoju web scrapera u Pythonu pomoću Seleniuma, koji pretražuje cijene avio karata. Prilikom traženja ulaznica koriste se fleksibilni datumi (+- 3 dana u odnosu na navedene datume). Strugač sprema rezultate pretraživanja u Excel datoteku i osobi koja je pokrenula pretragu šalje e-poruku sa sažetkom onoga što je pronašla. Cilj ovog projekta je pomoći putnicima da pronađu najbolje ponude.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati

Ako se pri razumijevanju gradiva osjećate izgubljeno, pogledajte ovo članak.

Što ćemo tražiti?

Ovdje opisani sustav slobodni ste koristiti kako želite. Na primjer, koristio sam ga za traženje vikend tura i karata za svoj rodni grad. Ako ste ozbiljni u pronalaženju isplativih ulaznica, možete pokrenuti skriptu na poslužitelju (jednostavno server, za 130 rubalja mjesečno, sasvim je prikladan za to) i pobrinite se da radi jednom ili dva puta dnevno. Rezultati pretraživanja bit će vam poslani e-poštom. Osim toga, preporučam sve postaviti tako da skripta sprema Excel datoteku s rezultatima pretraživanja u mapu Dropbox, što će vam omogućiti pregled takvih datoteka s bilo kojeg mjesta i u bilo koje vrijeme.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Još nisam našao tarife s greškom, ali mislim da je moguće

Prilikom pretraživanja, kao što je već spomenuto, koristi se “fleksibilni datum”; skripta pronalazi ponude unutar tri dana od zadanih datuma. Iako prilikom pokretanja skripta traži ponude samo u jednom smjeru, lako ju je modificirati tako da može prikupljati podatke o više smjerova leta. Uz njegovu pomoć možete čak tražiti pogrešne tarife; takvi nalazi mogu biti vrlo zanimljivi.

Zašto vam treba još jedan web scraper?

Kad sam tek počeo s web scrapingom, iskreno nisam bio za to posebno zainteresiran. Želio sam raditi više projekata na području prediktivnog modeliranja, financijske analize, a možda i na području analize emocionalne obojenosti tekstova. No pokazalo se da je bilo vrlo zanimljivo smišljati kako napraviti program koji prikuplja podatke s web stranica. Dok sam ulazio u ovu temu, shvatio sam da je web scraping "motor" Interneta.

Možda mislite da je ovo previše hrabra izjava. Ali uzmite u obzir da je Google započeo s web scraperom koji je Larry Page napravio pomoću Jave i Pythona. Googleovi roboti istražuju internet nastojeći svojim korisnicima pružiti najbolje odgovore na njihova pitanja. Web scraping ima beskonačnu upotrebu, pa čak i ako ste zainteresirani za nešto drugo u znanosti o podacima, trebat će vam neke vještine scrapinga da dobijete podatke koje trebate analizirati.

Otkrio sam da su neke od ovdje korištenih tehnika prekrasne knjiga o web scrapingu, koji sam nedavno nabavio. Sadrži mnogo jednostavnih primjera i ideja za praktičnu primjenu onoga što ste naučili. Osim toga, postoji vrlo zanimljivo poglavlje o zaobilaženju reCaptcha provjera. Ovo mi je bila novost, budući da nisam ni znao da postoje posebni alati, pa čak i cijeli servisi za rješavanje takvih problema.

Voliš li putovati?!

Na jednostavno i prilično bezazleno pitanje postavljeno u naslovu ove rubrike često se može čuti potvrdan odgovor, popraćen par pričama s putovanja osobe kojoj je postavljeno. Većina nas bi se složila da je putovanje izvrstan način da uronite u nova kulturna okruženja i proširite svoje horizonte. No, ako nekoga pitate voli li tražiti avio karte, siguran sam da odgovor neće biti tako pozitivan. Zapravo, Python nam tu priskače u pomoć.

Prvi zadatak koji trebamo riješiti na putu stvaranja sustava za pretraživanje informacija o avio kartama bit će odabir odgovarajuće platforme s koje ćemo preuzimati informacije. Rješavanje ovog problema mi nije bilo lako, ali sam na kraju odabrao Kayak servis. Isprobao sam usluge Momonda, Skyscannera, Expedije i nekoliko drugih, ali zaštitni mehanizmi robota na tim resursima bili su neprobojni. Nakon nekoliko pokušaja, tijekom kojih sam se morao nositi sa semaforima, pješačkim prijelazima i biciklima, pokušavajući uvjeriti sustave da sam čovjek, odlučio sam da je Kayak najprikladniji za mene, unatoč činjenici da čak i ako je učitano previše stranica u kratkom vremenu, a počinju i provjere. Uspio sam natjerati bota da šalje zahtjeve stranici u intervalima od 4 do 6 sati i sve je radilo u redu. S vremena na vrijeme pojavljuju se poteškoće pri radu s Kayakom, ali ako vas počnu gnjaviti s provjerama, tada ih trebate riješiti ručno i zatim pokrenuti bot ili pričekati nekoliko sati i provjere bi trebale prestati. Ako je potrebno, možete jednostavno prilagoditi kod za drugu platformu, a ako to učinite, možete to prijaviti u komentarima.

Ako ste tek počeli s web scrapingom i ne znate zašto se neke web stranice muče s tim, onda prije nego što započnete svoj prvi projekt u ovom području, učinite si uslugu i pretražite na Googleu riječi "web scraping bonton" . Vaši bi eksperimenti mogli završiti prije nego što mislite ako nepažljivo radite scraping weba.

Početak

Evo općeg pregleda onoga što će se dogoditi u našem kodu web skrapera:

  • Uvezite potrebne biblioteke.
  • Otvaranje kartice Google Chrome.
  • Pozovite funkciju koja pokreće bota, prosljeđujući mu gradove i datume koji će se koristiti prilikom traženja karata.
  • Ova funkcija uzima prve rezultate pretraživanja, sortirane prema najboljem, i klikne gumb za učitavanje više rezultata.
  • Druga funkcija prikuplja podatke s cijele stranice i vraća podatkovni okvir.
  • Dva prethodna koraka izvode se korištenjem tipova sortiranja prema cijeni karte (jeftino) i prema brzini leta (najbrže).
  • Korisniku skripte šalje se e-mail koji sadrži sažetak cijena karata (najjeftinije karte i prosječna cijena), a podatkovni okvir s informacijama sortiranim prema tri gore navedena indikatora sprema se kao Excel datoteka.
  • Sve gore navedene radnje izvode se u ciklusu nakon određenog vremenskog razdoblja.

Treba napomenuti da svaki Selenium projekt počinje s web driverom. koristim Chromedriver, radim s Google Chromeom, ali postoje i druge opcije. PhantomJS i Firefox su također popularni. Nakon preuzimanja drajvera potrebno ga je smjestiti u odgovarajuću mapu i time je završena priprema za njegovo korištenje. Prvi redovi naše skripte otvaraju novu karticu Chrome.

Imajte na umu da u svojoj priči ne pokušavam otvoriti nove horizonte za pronalaženje sjajnih ponuda za zrakoplovne karte. Postoje puno naprednije metode traženja takvih ponuda. Samo želim čitateljima ovog materijala ponuditi jednostavan, ali praktičan način rješavanja ovog problema.

Evo koda o kojem smo govorili gore.

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 početku koda možete vidjeti naredbe za uvoz paketa koje se koriste u cijelom našem projektu. Tako, randint koristi se kako bi bot "zaspao" na slučajni broj sekundi prije pokretanja nove operacije pretraživanja. Obično niti jedan bot ne može bez ovoga. Ako pokrenete gornji kod, otvorit će se prozor preglednika Chrome, koji će bot koristiti za rad sa stranicama.

Napravimo mali eksperiment i otvorimo web stranicu kayak.com u zasebnom prozoru. Odabrat ćemo grad iz kojeg ćemo letjeti, grad u koji želimo stići, kao i datume leta. Prilikom odabira datuma vodite računa da se koristi raspon od +-3 dana. Napisao sam kôd uzimajući u obzir ono što stranica proizvodi kao odgovor na takve zahtjeve. Ako, na primjer, trebate tražiti karte samo za određene datume, postoji velika vjerojatnost da ćete morati izmijeniti kod bota. Kada govorim o kodu, dajem odgovarajuća objašnjenja, ali ako se osjećate zbunjeno, javite mi.

Sada kliknite gumb za pretraživanje i pogledajte vezu u adresnoj traci. Trebao bi biti sličan poveznici koju koristim u donjem primjeru gdje je varijabla deklarirana kayak, koji pohranjuje URL, a metoda se koristi get web vozač. Nakon klika na gumb za pretraživanje, rezultati bi se trebali pojaviti na stranici.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Kad sam upotrijebio naredbu get više od dva ili tri puta u nekoliko minuta, zatraženo je da dovršim provjeru pomoću reCaptcha. Ovu provjeru možete proći ručno i nastaviti eksperimentirati dok sustav ne odluči pokrenuti novu provjeru. Kad sam testirao skriptu, činilo se da je prva sesija pretraživanja uvijek prošla glatko, pa ako želite eksperimentirati s kodom, morali biste samo povremeno ručno provjeravati i pustiti da se kod izvodi, koristeći duge intervale između sesija pretraživanja. I, ako razmislite o tome, osoba vjerojatno neće trebati informacije o cijenama karata primljene u intervalima od 10 minuta između operacija pretraživanja.

Rad sa stranicom koristeći XPath

Dakle, otvorili smo prozor i učitali stranicu. Da bismo dobili cijene i druge informacije, moramo koristiti XPath tehnologiju ili CSS selektore. Odlučio sam se držati XPatha i nisam osjećao potrebu za korištenjem CSS selektora, ali sasvim je moguće raditi na taj način. Kretanje po stranici pomoću XPatha može biti teško, čak i ako koristite tehnike koje sam opisao u ovo članak koji je uključivao kopiranje odgovarajućih identifikatora iz koda stranice, shvatio sam da to zapravo nije optimalan način pristupa potrebnim elementima. Usput, u ovo Knjiga pruža odličan opis osnova rada sa stranicama pomoću XPath i CSS selektora. Ovako izgleda odgovarajuća metoda upravljačkog programa za web.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Dakle, nastavimo raditi na botu. Iskoristimo mogućnosti programa za odabir najjeftinijih ulaznica. Na sljedećoj slici XPath selektorski kod je označen crvenom bojom. Za pregled koda potrebno je desnom tipkom miša kliknuti na element stranice koji vas zanima i iz izbornika koji se pojavi odabrati naredbu Inspect. Ova se naredba može pozvati za različite elemente stranice, čiji će kod biti prikazan i istaknut u pregledniku koda.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Pogledajte kod stranice

Kako bih pronašao potvrdu svog razmišljanja o nedostacima kopiranja selektora iz koda, obratite pozornost na sljedeće značajke.

Ovo dobivate kada kopirate kod:

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

Da biste kopirali ovako nešto, potrebno je desnom tipkom miša kliknuti na dio koda koji vas zanima i iz izbornika koji se pojavi odabrati naredbu Kopiraj > Kopiraj XPath.

Evo što sam upotrijebio za definiranje gumba Najjeftinije:

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

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Kopiraj naredbu > Kopiraj XPath

Sasvim je očito da druga opcija izgleda mnogo jednostavnija. Kada se koristi, traži element a koji ima atribut data-codejednak price. Kada koristite prvu opciju, element se pretražuje id koji je jednak wtKI-price_aTab, a XPath put do elementa izgleda ovako /div[1]/div/div/div[1]/div/span/span. Ovakav XPath upit prema stranici poslužit će, ali samo jednom. To mogu odmah reći id promijenit će se sljedeći put kada se stranica učita. Redoslijed znakova wtKI mijenja se dinamički svaki put kada se stranica učita, tako da će kôd koji ga koristi biti beskoristan nakon sljedećeg ponovnog učitavanja stranice. Stoga odvojite malo vremena da razumijete XPath. Ovo znanje će vam dobro poslužiti.

Međutim, treba imati na umu da kopiranje XPath selektora može biti korisno kada radite s prilično jednostavnim stranicama, a ako vam to odgovara, nema ništa loše u tome.

Razmislimo sada o tome što učiniti ako trebate dobiti sve rezultate pretraživanja u nekoliko redaka, unutar popisa. Jako jednostavno. Svaki rezultat je unutar objekta s klasom resultWrapper. Učitavanje svih rezultata može se izvršiti u petlji sličnoj dolje prikazanoj.

Treba napomenuti da ako razumijete gore navedeno, trebali biste lako razumjeti većinu koda koji ćemo analizirati. Dok se ovaj kod izvodi, pristupamo onome što trebamo (zapravo, elementu u koji je umotan rezultat) pomoću neke vrste mehanizma za određivanje putanje (XPath). Ovo se radi kako bi se dobio tekst elementa i smjestio u objekt iz kojeg se podaci mogu čitati (prvi put korišten flight_containers, onda - flights_list).

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Prikazana su prva tri retka i jasno vidimo sve što nam treba. No, imamo zanimljivije načine dobivanja informacija. Moramo uzeti podatke iz svakog elementa posebno.

Baci se na posao!

Najlakši način za pisanje funkcije je učitavanje dodatnih rezultata, pa ćemo odatle početi. Želio bih maksimizirati broj letova o kojima program prima informacije, a da ne posumnjam u službu koja vodi inspekciju, pa pri svakom prikazu stranice jednom kliknem gumb Učitaj više rezultata. U ovom kodu trebate obratiti pozornost na blok try, koji sam dodao jer se gumb ponekad ne učitava kako treba. Ako i vi naiđete na ovo, komentirajte pozive ove funkcije u kodu funkcije start_kayak, što ćemo pogledati u nastavku.

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

Sada, nakon duge analize ove funkcije (ponekad se mogu zanijeti), spremni smo deklarirati funkciju koja će strugati stranicu.

Već sam prikupio većinu onoga što je potrebno u sljedećoj funkciji pod nazivom page_scrape. Ponekad se vraćeni podaci putanje kombiniraju, pa koristim jednostavnu metodu za njihovo odvajanje. Na primjer, kada prvi put koristim varijable section_a_list и section_b_list. Naša funkcija vraća okvir podataka flights_df, to nam omogućuje da odvojimo rezultate dobivene različitim metodama sortiranja podataka i kasnije ih kombiniramo.

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

Pokušao sam imenovati varijable tako da kod bude razumljiv. Zapamtite da varijable koje počinju s a pripadaju prvoj fazi puta, i b - na drugu. Prijeđimo na sljedeću funkciju.

Mehanizmi podrške

Sada imamo funkciju koja nam omogućuje učitavanje dodatnih rezultata pretraživanja i funkciju za obradu tih rezultata. Ovaj je članak mogao završiti ovdje, budući da ove dvije funkcije pružaju sve što vam je potrebno za struganje stranica koje možete otvoriti sami. Ali još nismo razmotrili neke od pomoćnih mehanizama o kojima smo gore govorili. Na primjer, ovo je šifra za slanje e-pošte i još neke stvari. Sve se to može pronaći u funkciji start_kayak, što ćemo sada razmotriti.

Da bi ova funkcija radila, potrebne su vam informacije o gradovima i datumima. Koristeći te informacije, formira vezu u varijabli kayak, koji se koristi da vas odvede na stranicu koja će sadržavati rezultate pretraživanja poredane prema njihovom najboljem podudaranju s upitom. Nakon prvog scrapinga radit ćemo s cijenama u tablici na vrhu stranice. Naime, pronaći ćemo minimalnu cijenu karte i prosječnu cijenu. Sve ovo, zajedno s predviđanjem koje izdaje stranica, bit će poslano e-poštom. Na stranici odgovarajuća tablica treba biti u gornjem lijevom kutu. Uzgred, rad s ovom tablicom može uzrokovati pogrešku prilikom pretraživanja pomoću točnih datuma, jer u ovom slučaju tablica nije prikazana na stranici.

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

Testirao sam ovu skriptu koristeći Outlook račun (hotmail.com). Nisam testirao da ispravno radi s Gmail računom, ovaj je sustav e-pošte prilično popularan, ali postoji mnogo mogućih opcija. Ako koristite Hotmail račun, onda da bi sve radilo, samo trebate unijeti svoje podatke u kod.

Ako želite razumjeti što se točno radi u određenim dijelovima koda za ovu funkciju, možete ih kopirati i eksperimentirati s njima. Eksperimentiranje s kodom je jedini način da ga istinski razumijete.

Spremni sustav

Sada kada smo učinili sve o čemu smo pričali, možemo stvoriti jednostavnu petlju koja poziva naše funkcije. Skripta od korisnika traži podatke o gradovima i datumima. Kod testiranja sa stalnim ponovnim pokretanjem skripte, te podatke vjerojatno nećete htjeti svaki put unositi ručno, tako da odgovarajuće retke, za vrijeme testiranja, možete komentirati odkomentiranjem onih ispod njih, u kojima se unose podaci potrebni skripta je tvrdo kodirana.

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

Ovako izgleda probno pokretanje skripte.
Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati
Probno pokretanje skripte

Rezultati

Ako ste uspjeli do sada, čestitamo! Sada imate web strugač koji radi, iako već vidim mnogo načina za njegovo poboljšanje. Na primjer, može se integrirati s Twiliom tako da šalje tekstualne poruke umjesto e-pošte. Možete koristiti VPN ili nešto drugo za istovremeno primanje rezultata s nekoliko poslužitelja. Također se povremeno pojavljuje problem s provjerom korisnika stranice da li je osoba, ali i taj problem se može riješiti. U svakom slučaju, sada imate bazu koju po želji možete proširiti. Na primjer, provjerite šalje li se Excel datoteka korisniku kao privitak e-poruke.

Python - pomoćnik u pronalaženju jeftinih zrakoplovnih karata za one koji vole putovati

U anketi mogu sudjelovati samo registrirani korisnici. Prijaviti se, molim.

Koristite li tehnologije struganja weba?

  • Da

  • Ne

Glasovalo je 8 korisnika. 1 korisnik je bio suzdržan.

Izvor: www.habr.com

Dodajte komentar