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

Autor članka, čiji prijevod danas objavljujemo, kaže da je njegov cilj da govori o razvoju web scrapera u Pythonu koristeći Selenium, koji traži cijene avio karata. Prilikom traženja karata koriste se fleksibilni datumi (+- 3 dana u odnosu na navedene datume). Scraper sprema rezultate pretrage u Excel datoteku i šalje osobi koja je pokrenula pretragu 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 avio karata za one koji vole putovati

Ako se tokom razumijevanja gradiva osjećate izgubljeno, pogledajte ovo članak.

Šta ćemo tražiti?

Ovdje opisani sistem možete slobodno 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 unosnih ulaznica, možete pokrenuti skriptu na serveru (jednostavno server, za 130 rubalja mjesečno, sasvim je prikladno za ovo) i pobrinite se da radi jednom ili dva puta dnevno. Rezultati pretrage će vam biti poslani e-poštom. Osim toga, preporučujem da sve postavite tako da skripta spremi Excel datoteku s rezultatima pretraživanja u Dropbox folder, što će vam omogućiti da pregledate takve datoteke s bilo kojeg mjesta i u bilo koje vrijeme.

Python - pomoćnik u pronalaženju jeftinih avio karata za one koji vole putovati
Tarife sa greškama još nisam našao, ali mislim da je moguće

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

Zašto vam treba još jedan web strugač?

Kada sam prvi put počeo da skidam web, to me, iskreno, nije posebno zanimalo. Želeo sam da radim više projekata u oblasti prediktivnog modeliranja, finansijske analize i, eventualno, u oblasti analize emocionalne obojenosti tekstova. Ali pokazalo se da je bilo vrlo zanimljivo smisliti kako napraviti program koji prikuplja podatke sa 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 kreirao koristeći Javu i Python. Google roboti istražuju internet, pokušavajući korisnicima pružiti najbolje odgovore na njihova pitanja. Web scraping ima beskrajnu upotrebu, pa čak i ako vas zanima nešto drugo u nauci o podacima, trebat će vam neke vještine scrapinga da biste dobili podatke koje trebate analizirati.

Našla sam neke od tehnika koje se ovdje koriste u divnom 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. To mi je došla kao vijest, jer nisam ni znao da postoje posebni alati, pa čak i čitavi 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 pozitivan odgovor, popraćen par priča sa putovanja osobe kojoj je postavljeno. Većina nas bi se složila da su putovanja odličan način da se uronite u nova kulturna okruženja i proširite svoje vidike. Međutim, ako nekoga pitate da li voli da traži avionske karte, siguran sam da odgovor neće biti tako pozitivan. U stvari, Python nam ovdje dolazi u pomoć.

Prvi zadatak koji trebamo riješiti na putu stvaranja sistema za pretraživanje informacija o avio kartama biće odabir odgovarajuće platforme sa koje ćemo preuzimati informacije. Rešavanje ovog problema mi nije bilo lako, ali sam na kraju izabrao Kajak servis. Isprobao sam usluge Momonda, Skyscannera, Expedia i nekoliko drugih, ali mehanizmi zaštite robota na ovim resursima bili su neprobojni. Nakon nekoliko pokušaja, tokom kojih sam morao da se nosim sa semaforima, pešačkim prelazima i biciklima, pokušavajući da ubedim sisteme da sam čovek, odlučio sam da mi kajak najviše odgovara, uprkos činjenici da čak i ako je previše stranica učitano za kratko vrijeme, a počinju i provjere. Uspio sam natjerati bota da šalje zahtjeve na stranicu u intervalima od 4 do 6 sati i sve je funkcionisalo kako treba. S vremena na vrijeme nastaju poteškoće pri radu s Kajakom, ali ako vas počnu gnjaviti provjerama, onda se trebate ili pozabaviti njima 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 scraping-om i ne znate zašto se neke web stranice bore s tim, onda prije nego što započnete svoj prvi projekat u ovoj oblasti, učinite sebi uslugu i pretražite na Google-u riječi "web scraping etiquette" . Vaši eksperimenti se mogu završiti prije nego što mislite ako nepametno krenete po webu.

Prvi koraci

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

  • Uvezite potrebne biblioteke.
  • Otvaranje kartice Google Chrome.
  • Pozovite funkciju koja pokreće bot, prenoseći mu gradove i datume koji će se koristiti prilikom traženja karata.
  • Ova funkcija uzima prve rezultate pretraživanja, sortirane po najboljim, i klikne na dugme da učita više rezultata.
  • Druga funkcija prikuplja podatke sa cijele stranice i vraća okvir podataka.
  • Dva prethodna koraka se izvode koristeći sortiranje po cijeni karte (jeftina) i brzini leta (najbrže).
  • Korisniku skripte se šalje e-mail sa rezimeom cijena karata (najjeftinije karte i prosječne cijene), a okvir podataka sa informacijama sortiranim prema tri gore navedena indikatora se pohranjuje kao Excel fajl.
  • Sve gore navedene radnje se izvode u ciklusu nakon određenog vremenskog perioda.

Treba napomenuti da svaki Selenium projekat počinje sa web drajverom. ja koristim Chromedriver, radim sa 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 se završava priprema za njegovu upotrebu. Prvi redovi naše skripte otvaraju novu Chrome karticu.

Imajte na umu da u svojoj priči ne pokušavam otvoriti nove horizonte za pronalaženje sjajnih ponuda za avio karte. Postoje mnogo 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 pričali 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 komande za uvoz paketa koje se koriste u cijelom našem projektu. dakle, randint koristi se kako bi bot „zaspao“ na nasumični broj sekundi prije nego što započne novu operaciju pretraživanja. Obično ni jedan bot ne može bez ovoga. Ako pokrenete gornji kod, otvorit će se Chrome prozor koji će bot koristiti za rad sa web lokacijama.

Napravimo mali eksperiment i otvorimo web stranicu kayak.com u zasebnom prozoru. Odabrat ćemo grad iz kojeg ćemo letjeti, i grad u koji želimo stići, kao i datume letova. Prilikom odabira datuma vodite računa o tome da se koristi raspon od +-3 dana. Napisao sam kod 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, onda postoji velika vjerovatnoća 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 na dugme za pretragu i pogledajte vezu u adresnoj traci. Trebao bi biti sličan linku koji koristim u primjeru ispod gdje je varijabla deklarirana kayak, koji pohranjuje URL, a metoda se koristi get web drajver. Nakon što kliknete na dugme za pretragu, rezultati bi se trebali pojaviti na stranici.

Python - pomoćnik u pronalaženju jeftinih avio karata za one koji vole putovati
Kada sam koristio komandu get više od dva ili tri puta u roku od nekoliko minuta, od mene je zatraženo da završim verifikaciju koristeći reCaptcha. Ovu provjeru možete proći ručno i nastaviti eksperimentirati sve dok sistem ne odluči pokrenuti novu provjeru. Kada sam testirao skriptu, činilo se da je prva sesija pretraživanja uvijek išla glatko, pa ako želite eksperimentirati s kodom, morali biste samo povremeno ručno provjeravati i pustiti kod da se pokrene, koristeći duge intervale između sesija pretraživanja. I, ako razmislite o tome, malo je vjerovatno da će nekoj osobi trebati informacije o cijenama karata koje se primaju 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 XPath-a i nisam osjećao potrebu da koristim CSS selektore, ali je sasvim moguće raditi na taj način. Kretanje po stranici pomoću XPath-a može biti nezgodno, čak i ako koristite tehnike koje sam opisao u ovo članka, 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 koristeći XPath i CSS selektore. Ovako izgleda odgovarajuća metoda web drajvera.

Python - pomoćnik u pronalaženju jeftinih avio karata za one koji vole putovati
Dakle, nastavimo sa radom na botu. Iskoristimo mogućnosti programa da odaberemo najjeftinije karte. Na sljedećoj slici, XPath kod selektora je istaknut crvenom bojom. Da biste pogledali kod, potrebno je da kliknete desnim tasterom miša na element stranice koji vas zanima i izaberete komandu Inspect iz menija koji se pojavi. Ova naredba se 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 avio karata za one koji vole putovati
Pogledajte kod stranice

Da biste pronašli potvrdu mog razmišljanja o nedostacima kopiranja selektora iz koda, obratite pažnju na sljedeće karakteristike.

Evo šta dobijate kada kopirate kod:

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

Da biste kopirali nešto ovako, potrebno je da kliknete desnim tasterom miša na deo koda koji vas zanima i iz menija koji se pojavi izaberete komandu Kopiraj > Kopiraj XPath.

Evo šta sam koristio da definiram najjeftinije dugme:

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

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

Sasvim je očigledno da druga opcija izgleda mnogo jednostavnije. Kada se koristi, traži element a koji ima atribut data-codejednak price. Kada koristite prvu opciju, element se traži id što je jednako wtKI-price_aTab, a XPath putanja do elementa izgleda ovako /div[1]/div/div/div[1]/div/span/span. XPath upit stranici kao što je ovaj će učiniti trik, ali samo jednom. Odmah to mogu reći id će se promijeniti sljedeći put kada se stranica učita. Slijed karaktera wtKI mijenja se dinamički svaki put kada se stranica učita, tako da će kod koji ga koristi biti beskoristan nakon sljedećeg ponovnog učitavanja stranice. Zato odvojite malo vremena da shvatite XPath. Ovo znanje će vam dobro poslužiti.

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

Sada razmislimo šta učiniti ako trebate dobiti sve rezultate pretraživanja u nekoliko redova, unutar liste. Veoma jednostavno. Svaki rezultat je unutar objekta sa klasom resultWrapper. Učitavanje svih rezultata može se obaviti u petlji sličnoj dolje prikazanoj.

Treba napomenuti da ako razumijete gore navedeno, onda biste trebali lako razumjeti većinu koda koji ćemo analizirati. Dok se ovaj kod izvodi, pristupamo onome što nam je potrebno (u stvari, elementu u koji je rezultat umotan) koristeći neku vrstu mehanizma za specificiranje putanje (XPath). Ovo se radi kako bi se dobio tekst elementa i smjestio u objekat iz kojeg se mogu čitati podaci (prvo korišteni flight_containers, onda - flights_list).

Python - pomoćnik u pronalaženju jeftinih avio karata za one koji vole putovati
Prikazuju se prva tri reda i jasno vidimo sve što nam treba. Međutim, imamo zanimljivije načine za dobijanje informacija. Moramo uzeti podatke iz svakog elementa posebno.

Na posao!

Najlakši način za pisanje funkcije je učitavanje dodatnih rezultata, tako da ćemo od toga početi. Želio bih maksimizirati broj letova o kojima program prima informacije, a da ne izazivam sumnju u uslugu koja vodi do inspekcije, pa kliknem na dugme Učitaj još rezultata jednom svaki put kada se stranica prikaže. U ovom kodu treba obratiti pažnju na blok try, koji sam dodao jer se ponekad dugme ne učitava kako treba. Ako i vi naiđete na ovo, komentarišite pozive ovoj funkciji u kodu funkcije start_kayak, koje ć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 zanesti), spremni smo da deklariramo funkciju koja će ostrugati stranicu.

Već sam prikupio većinu onoga što je potrebno u sljedećoj funkciji koja se zove page_scrape. Ponekad se vraćeni podaci o putanji kombinuju, pa koristim jednostavnu metodu da ih odvojim. Na primjer, kada prvi put koristim varijable section_a_list и section_b_list. Naša funkcija vraća okvir podataka flights_df, ovo nam omogućava da odvojimo rezultate dobijene 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 da imenujem varijable tako da kod bude razumljiv. Zapamtite da varijable počinju sa a pripadaju prvoj fazi puta, i b - do drugog. Prijeđimo na sljedeću funkciju.

Mehanizmi podrške

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

Da bi ova funkcija radila, potrebne su vam informacije o gradovima i datumima. Koristeći ove informacije, formira vezu u varijabli kayak, koji se koristi da vas odvede na stranicu koja će sadržavati rezultate pretraživanja sortirane prema njihovom najboljem podudaranju s upitom. Nakon prve sesije scrapinga, radit ćemo s cijenama u tabeli na vrhu stranice. Naime, naći ćemo minimalnu cijenu karte i prosječnu cijenu. Sve ovo, zajedno sa predviđanjem koje izdaje sajt, biće poslato e-poštom. Na stranici, odgovarajuća tabela treba da se nalazi u gornjem levom uglu. Rad s ovom tablicom, inače, može uzrokovati grešku prilikom pretraživanja pomoću tačnih datuma, jer se u ovom slučaju tabela ne prikazuje 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 nalog (hotmail.com). Nisam testirao da radi ispravno sa Gmail nalogom, ovaj sistem e-pošte je prilično popularan, ali postoji mnogo mogućih opcija. Ako koristite Hotmail nalog, da bi sve funkcionisalo, potrebno je samo da unesete svoje podatke u kod.

Ako želite da shvatite šta se tačno radi u određenim delovima koda za ovu funkciju, možete ih kopirati i eksperimentisati s njima. Eksperimentisanje sa kodom je jedini način da ga istinski razumete.

Spreman sistem

Sada kada smo uradili sve o čemu smo pričali, možemo kreirati jednostavnu petlju koja poziva naše funkcije. Skripta od korisnika traži podatke o gradovima i datumima. Prilikom testiranja sa stalnim ponovnim pokretanjem skripte, malo je vjerovatno da ćete htjeti ručno unositi ove podatke svaki put, tako da se odgovarajući redovi, za vrijeme testiranja, mogu komentirati dekomentiranjem onih ispod njih, u kojima su podaci potrebni za 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 avio karata za one koji vole putovati
Probno pokretanje skripte

Ishodi

Ako ste dogurali dovde, čestitamo! Sada imate radni web strugač, iako već vidim mnogo načina da ga poboljšam. 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 da istovremeno primate rezultate s nekoliko servera. Povremeno se javlja i problem sa provjeravanjem korisnika stranice da li je osoba, ali se i ovaj problem može riješiti. U svakom slučaju, sada imate bazu koju možete proširiti ako želite. Na primjer, uvjerite se da je Excel datoteka poslana korisniku kao prilog e-poruci.

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

Samo registrovani korisnici mogu učestvovati u anketi. Prijavite semolim.

Da li koristite web scraping tehnologije?

  • Da

  • Nijedan

Glasalo je 8 korisnika. 1 korisnik je bio uzdržan.

izvor: www.habr.com

Dodajte komentar