Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú

Autor článku, ktorého preklad dnes uverejňujeme, hovorí, že jeho cieľom je rozprávať o vývoji webového škrabáka v Pythone pomocou Selenium, ktorý vyhľadáva ceny leteniek. Pri vyhľadávaní lístkov sa používajú flexibilné dátumy (+- 3 dni vzhľadom na uvedené dátumy). Škrabka uloží výsledky vyhľadávania do súboru programu Excel a pošle osobe, ktorá spustila vyhľadávanie, e-mail so zhrnutím toho, čo našla. Cieľom tohto projektu je pomôcť cestovateľom nájsť najlepšie ponuky.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú

Ak sa pri pochopení látky cítite stratení, pozrite sa na toto článok.

Čo budeme hľadať?

Tu popísaný systém môžete voľne používať podľa vlastného uváženia. Použil som ho napríklad na vyhľadávanie víkendových zájazdov a lístkov do môjho rodného mesta. Ak to s hľadaním ziskových lístkov myslíte vážne, môžete skript spustiť na serveri (jednoduché server, za 130 rubľov mesačne, je na to celkom vhodný) a uistite sa, že beží raz alebo dvakrát denne. Výsledky vyhľadávania vám budú zaslané e-mailom. Okrem toho odporúčam všetko nastaviť tak, aby skript ukladal excelovský súbor s výsledkami vyhľadávania do priečinka Dropbox, čo vám umožní prezerať si takéto súbory odkiaľkoľvek a kedykoľvek.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Zatiaľ som nenašiel tarify s chybami, ale myslím, že je to možné

Pri vyhľadávaní, ako už bolo spomenuté, sa používa „flexibilný dátum“, skript nájde ponuky, ktoré sú do troch dní od zadaných dátumov. Hoci pri spustení skriptu hľadá ponuky len jedným smerom, je jednoduché ho upraviť tak, aby dokázal zbierať údaje o viacerých smeroch letu. S jeho pomocou môžete dokonca hľadať chybné tarify, takéto nálezy môžu byť veľmi zaujímavé.

Prečo potrebujete ďalší webový škrabák?

Keď som prvýkrát začal so zoškrabovaním webu, úprimne ma to nijak zvlášť nezaujímalo. Chcel som robiť viac projektov v oblasti prediktívneho modelovania, finančnej analýzy, prípadne v oblasti analýzy emocionálneho zafarbenia textov. Ukázalo sa však, že je veľmi zaujímavé zistiť, ako vytvoriť program, ktorý zbiera údaje z webových stránok. Keď som sa ponoril do tejto témy, uvedomil som si, že zoškrabovanie webu je „motorom“ internetu.

Možno si myslíte, že je to príliš odvážne tvrdenie. Ale zvážte, že Google začal s webovým škrabákom, ktorý Larry Page vytvoril pomocou Java a Python. Roboty Google skúmajú internet a snažia sa svojim používateľom poskytnúť tie najlepšie odpovede na ich otázky. Web scraping má nekonečné možnosti využitia a aj keď vás v Data Science zaujíma niečo iné, na získanie údajov, ktoré potrebujete analyzovať, budete potrebovať určité zručnosti zoškrabovania.

Zistil som, že niektoré z techník, ktoré sa tu používajú, sú úžasné kniha o zoškrabovaní webu, ktorý som nedávno získal. Obsahuje veľa jednoduchých príkladov a nápadov na praktickú aplikáciu toho, čo ste sa naučili. Okrem toho je tu veľmi zaujímavá kapitola o obchádzaní reCaptcha kontrol. Prišlo mi to ako novinka, keďže som ani nevedel, že existujú špeciálne nástroje a dokonca celé služby na riešenie takýchto problémov.

Radi cestujete?!

Na jednoduchú a vcelku neškodnú otázku položenú v názve tejto časti si často vypočujete kladnú odpoveď doplnenú niekoľkými príbehmi z ciest toho, komu bola položená. Väčšina z nás by súhlasila s tým, že cestovanie je skvelý spôsob, ako sa ponoriť do nových kultúrnych prostredí a rozšíriť si obzory. Ak sa však niekoho opýtate, či má rád vyhľadávanie leteniek, som si istý, že odpoveď nebude taká pozitívna. V skutočnosti nám tu pomáha Python.

Prvou úlohou, ktorú musíme na ceste k vytvoreniu systému na vyhľadávanie informácií o letenkách vyriešiť, bude výber vhodnej platformy, z ktorej budeme informácie čerpať. Riešenie tohto problému pre mňa nebolo jednoduché, no nakoniec som si vybral službu Kajak. Vyskúšal som služby Momondo, Skyscanner, Expedia a niekoľko ďalších, ale mechanizmy ochrany robotov na týchto zdrojoch boli nepreniknuteľné. Po niekoľkých pokusoch, počas ktorých som sa musel popasovať so semaformi, prechodmi pre chodcov a bicyklami, snažiac sa presvedčiť systémy, že som človek, som sa rozhodol, že kajak je pre mňa najvhodnejší, napriek tomu, že aj keď sa načíta príliš veľa stránok v krátkom čase a začínajú aj kontroly. Podarilo sa mi prinútiť robota, aby odosielal požiadavky na stránku v intervaloch 4 až 6 hodín a všetko fungovalo dobre. Z času na čas sa pri práci s Kayakom vyskytnú ťažkosti, ale ak vás začnú otravovať kontrolami, musíte sa s nimi vysporiadať manuálne a potom spustiť robota, alebo počkať niekoľko hodín a kontroly by sa mali zastaviť. V prípade potreby môžete kód jednoducho prispôsobiť pre inú platformu a ak tak urobíte, môžete to nahlásiť v komentároch.

Ak s webovým zoškrabávaním ešte len začínate a neviete, prečo s tým niektoré weby zápasia, tak predtým, ako začnete svoj prvý projekt v tejto oblasti, urobte si láskavosť a vyhľadajte na Googli slová „etiquette zoškrabovania webu“ . Vaše experimenty sa môžu skončiť skôr, ako si myslíte, ak budete web zoškrabovať nerozumne.

Začíname

Tu je všeobecný prehľad toho, čo sa stane v našom webovom škrabacom kóde:

  • Importujte požadované knižnice.
  • Otvorenie karty Google Chrome.
  • Zavolajte funkciu, ktorá spustí robota a odovzdá mu mestá a dátumy, ktoré sa použijú pri hľadaní lístkov.
  • Táto funkcia vezme prvé výsledky vyhľadávania zoradené podľa najlepších a kliknutím na tlačidlo načítate ďalšie výsledky.
  • Ďalšia funkcia zbiera dáta z celej stránky a vracia dátový rámec.
  • Predchádzajúce dva kroky sa vykonávajú pomocou typov triedenia podľa ceny letenky (lacné) a podľa rýchlosti letu (najrýchlejšie).
  • Používateľovi skriptu sa odošle e-mail so sumárom cien lístkov (najlacnejšie lístky a priemerná cena) a dátový rámec s informáciami zoradenými podľa troch vyššie uvedených ukazovateľov sa uloží ako súbor Excel.
  • Všetky vyššie uvedené akcie sa vykonávajú v cykle po určenom časovom období.

Treba poznamenať, že každý projekt Selenium začína webovým ovládačom. používam Chromedriver, pracujem s prehliadačom Google Chrome, ale existujú aj iné možnosti. Populárne sú aj PhantomJS a Firefox. Po stiahnutí ovládača je potrebné ho umiestniť do príslušného priečinka a tým je príprava na jeho použitie hotová. Prvé riadky nášho skriptu otvárajú novú kartu Chrome.

Majte na pamäti, že v mojom príbehu sa nesnažím otvárať nové obzory pre hľadanie skvelých ponúk na letenky. Existujú oveľa pokročilejšie spôsoby vyhľadávania takýchto ponúk. Chcem len ponúknuť čitateľom tohto materiálu jednoduchý, ale praktický spôsob riešenia tohto problému.

Tu je kód, o ktorom sme hovorili vyššie.

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čiatku kódu môžete vidieť príkazy na import balíka, ktoré sa používajú v celom našom projekte. takže, randint používa sa na to, aby robot „zaspal“ na náhodný počet sekúnd pred spustením novej operácie vyhľadávania. Zvyčajne sa bez toho nezaobíde ani jeden robot. Ak spustíte vyššie uvedený kód, otvorí sa okno prehliadača Chrome, ktoré robot použije na prácu so stránkami.

Urobme malý experiment a otvoríme si webovú stránku kayak.com v samostatnom okne. Vyberieme si mesto, z ktorého poletíme, a mesto, do ktorého sa chceme dostať, ako aj termíny letov. Pri výbere termínov dbajte na to, aby bol použitý rozsah +-3 dni. Napísal som kód s ohľadom na to, čo stránka produkuje v reakcii na takéto požiadavky. Ak napríklad potrebujete hľadať vstupenky len na určené dátumy, potom je vysoká pravdepodobnosť, že budete musieť upraviť kód bota. Keď hovorím o kóde, poskytujem vhodné vysvetlenia, ale ak sa cítite zmätení, dajte mi vedieť.

Teraz kliknite na tlačidlo vyhľadávania a pozrite sa na odkaz v paneli s adresou. Mal by byť podobný odkazu, ktorý používam v príklade nižšie, kde je premenná deklarovaná kayak, ktorý ukladá URL, a používa sa metóda get webový ovládač. Po kliknutí na tlačidlo vyhľadávania by sa na stránke mali zobraziť výsledky.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Keď som použil príkaz get viac ako dvakrát alebo trikrát v priebehu niekoľkých minút som bol požiadaný o dokončenie overenia pomocou reCaptcha. Túto kontrolu môžete absolvovať manuálne a pokračovať v experimentovaní, kým sa systém nerozhodne spustiť novú kontrolu. Keď som testoval skript, zdalo sa, že prvá relácia vyhľadávania vždy prebehla hladko, takže ak by ste chceli experimentovať s kódom, museli by ste kód pravidelne ručne kontrolovať a nechať bežať, pričom medzi jednotlivými reláciami vyhľadávania by ste mali používať dlhé intervaly. A ak sa nad tým zamyslíte, je nepravdepodobné, že osoba bude potrebovať informácie o cenách lístkov, ktoré dostane v 10-minútových intervaloch medzi operáciami vyhľadávania.

Práca so stránkou pomocou XPath

Otvorili sme teda okno a načítali web. Na získanie cien a ďalších informácií musíme použiť technológiu XPath alebo selektory CSS. Rozhodol som sa zostať pri XPath a necítil som potrebu používať CSS selektory, ale je celkom možné, že to tak funguje. Navigácia po stránke pomocou XPath môže byť zložitá a aj keď použijete techniky, ktoré som opísal v toto článku, ktorý zahŕňal skopírovanie zodpovedajúcich identifikátorov z kódu stránky, som si uvedomil, že to v skutočnosti nie je optimálny spôsob prístupu k potrebným prvkom. Mimochodom, v toto Kniha poskytuje výborný popis základov práce so stránkami pomocou selektorov XPath a CSS. Takto vyzerá zodpovedajúca metóda webového ovládača.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Pokračujme teda v práci na robotovi. Využime možnosti programu na výber najlacnejších leteniek. Na nasledujúcom obrázku je kód selektora XPath zvýraznený červenou farbou. Ak chcete zobraziť kód, musíte kliknúť pravým tlačidlom myši na prvok stránky, ktorý vás zaujíma, a zo zobrazenej ponuky vybrať príkaz Skontrolovať. Tento príkaz možno volať pre rôzne prvky stránky, ktorých kód sa zobrazí a zvýrazní v prehliadači kódu.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Zobraziť kód stránky

Aby ste našli potvrdenie mojej úvahy o nevýhodách kopírovania selektorov z kódu, venujte pozornosť nasledujúcim funkciám.

Toto získate, keď skopírujete kód:

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

Ak chcete niečo také skopírovať, musíte kliknúť pravým tlačidlom myši na časť kódu, ktorá vás zaujíma, a v zobrazenej ponuke vybrať príkaz Kopírovať > Kopírovať XPath.

Tu je to, čo som použil na definovanie tlačidla Najlacnejšie:

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

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Kopírovať príkaz > Kopírovať cestu XPath

Je celkom zrejmé, že druhá možnosť vyzerá oveľa jednoduchšie. Pri použití hľadá prvok a, ktorý má atribút data-coderovná price. Pri použití prvej možnosti sa prvok vyhľadá id čo sa rovná wtKI-price_aTaba cesta XPath k prvku vyzerá takto /div[1]/div/div/div[1]/div/span/span. Dopyt XPath na stránku, ako je tento, bude stačiť, ale iba raz. To môžem povedať hneď id sa zmení pri ďalšom načítaní stránky. Postupnosť znakov wtKI sa dynamicky mení pri každom načítaní stránky, takže kód, ktorý ho používa, bude po ďalšom načítaní stránky zbytočný. Nájdite si teda čas na pochopenie XPath. Tieto znalosti vám dobre poslúžia.

Treba však poznamenať, že kopírovanie selektorov XPath môže byť užitočné pri práci s pomerne jednoduchými stránkami a ak vám to vyhovuje, nie je na tom nič zlé.

Teraz sa zamyslime nad tým, čo robiť, ak potrebujete získať všetky výsledky vyhľadávania v niekoľkých riadkoch v zozname. Veľmi jednoduché. Každý výsledok je vo vnútri objektu s triedou resultWrapper. Načítanie všetkých výsledkov sa môže uskutočniť v slučke podobnej tej, ktorá je uvedená nižšie.

Treba poznamenať, že ak rozumiete vyššie uvedenému, mali by ste ľahko pochopiť väčšinu kódu, ktorý budeme analyzovať. Keď tento kód beží, pristupujeme k tomu, čo potrebujeme (v skutočnosti k prvku, do ktorého je zabalený výsledok) pomocou nejakého mechanizmu špecifikujúceho cestu (XPath). Robí sa to s cieľom získať text prvku a umiestniť ho do objektu, z ktorého možno čítať údaje (prvé použitie flight_containers, potom - flights_list).

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Zobrazia sa prvé tri riadky a jasne vidíme všetko, čo potrebujeme. Máme však zaujímavejšie spôsoby získavania informácií. Musíme brať údaje z každého prvku samostatne.

Dostať sa do práce!

Najjednoduchší spôsob, ako napísať funkciu, je načítať ďalšie výsledky, takže začneme. Chcel by som maximalizovať počet letov, o ktorých program dostane informácie, bez toho, aby som vyvolal podozrenie v službe, ktorá vedie ku kontrole, preto pri každom zobrazení stránky kliknem na tlačidlo Načítať ďalšie výsledky. V tomto kóde by ste mali venovať pozornosť bloku try, ktorý som pridal, pretože sa občas tlačidlo nenačíta správne. Ak sa s tým stretnete aj vy, zakomentujte volania tejto funkcie v kóde funkcie start_kayak, na ktorý sa pozrieme nižšie.

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

Teraz, po dlhom rozbore tejto funkcie (občas sa nechám uniesť), sme pripravení deklarovať funkciu, ktorá zoškrabe stránku.

Väčšinu toho, čo je potrebné, som už zozbieral v nasledujúcej funkcii tzv page_scrape. Niekedy sa vrátené údaje o ceste kombinujú, takže na ich oddelenie používam jednoduchú metódu. Napríklad, keď prvýkrát použijem premenné section_a_list и section_b_list. Naša funkcia vracia dátový rámec flights_df, to nám umožňuje oddeliť výsledky získané z rôznych metód triedenia údajov a neskôr ich spojiť.

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

Snažil som sa pomenovať premenné tak, aby bol kód zrozumiteľný. Pamätajte, že premenné začínajúce na a patrí do prvej etapy cesty, a b - do druhého. Prejdime k ďalšej funkcii.

Podporné mechanizmy

Teraz máme funkciu, ktorá nám umožňuje načítať ďalšie výsledky vyhľadávania a funkciu na spracovanie týchto výsledkov. Tento článok mohol skončiť tu, pretože tieto dve funkcie poskytujú všetko, čo potrebujete na zoškrabanie stránok, ktoré si môžete sami otvoriť. Zatiaľ sme však neuvažovali o niektorých pomocných mechanizmoch diskutovaných vyššie. Toto je napríklad kód na odosielanie e-mailov a niektoré ďalšie veci. To všetko nájdete vo funkcii start_kayak, ktorý teraz zvážime.

Aby táto funkcia fungovala, potrebujete informácie o mestách a dátumoch. Pomocou týchto informácií vytvorí prepojenie v premennej kayak, ktorý slúži na prechod na stránku, ktorá bude obsahovať výsledky vyhľadávania zoradené podľa ich najlepšej zhody s dopytom. Po prvom zoškrabovaní budeme pracovať s cenami v tabuľke v hornej časti stránky. Totiž nájdeme minimálnu cenu letenky a priemernú cenu. To všetko spolu s predpoveďou vydanou stránkou bude zaslané e-mailom. Na stránke by mala byť zodpovedajúca tabuľka v ľavom hornom rohu. Práca s touto tabuľkou môže mimochodom spôsobiť chybu pri vyhľadávaní pomocou presných dátumov, pretože v tomto prípade sa tabuľka na stránke nezobrazuje.

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

Testoval som tento skript pomocou účtu Outlook (hotmail.com). Netestoval som, aby fungoval správne s účtom Gmail, tento e-mailový systém je pomerne populárny, ale existuje veľa možných možností. Ak používate účet Hotmail, potom aby všetko fungovalo, stačí zadať svoje údaje do kódu.

Ak chcete pochopiť, čo presne sa robí v konkrétnych častiach kódu pre túto funkciu, môžete ich skopírovať a experimentovať s nimi. Experimentovanie s kódom je jediný spôsob, ako ho skutočne pochopiť.

Pripravený systém

Teraz, keď sme urobili všetko, o čom sme hovorili, môžeme vytvoriť jednoduchú slučku, ktorá volá naše funkcie. Skript vyžaduje od používateľa údaje o mestách a dátumoch. Pri testovaní s neustálym reštartovaním skriptu je nepravdepodobné, že budete chcieť tieto údaje zakaždým zadávať ručne, takže príslušné riadky počas trvania testovania môžete zakomentovať odkomentovaním tých pod nimi, v ktorých sú údaje potrebné pre skript je pevne zakódovaný.

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

Takto vyzerá testovacia prevádzka skriptu.
Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú
Testovacia prevádzka skriptu

Výsledky

Ak ste sa dostali až sem, gratulujeme! Teraz máte funkčný webový škrabák, aj keď už vidím veľa spôsobov, ako ho vylepšiť. Napríklad môže byť integrovaný s Twilio, takže namiesto e-mailov odosiela textové správy. Na súčasné prijímanie výsledkov z niekoľkých serverov môžete použiť sieť VPN alebo niečo iné. Pravidelne sa vyskytuje aj problém s kontrolou používateľa stránky, či ide o osobu, ale aj tento problém sa dá vyriešiť. V každom prípade, teraz máte základňu, ktorú môžete rozšíriť, ak chcete. Uistite sa napríklad, že súbor programu Excel sa používateľovi odošle ako príloha e-mailu.

Python - pomocník pri hľadaní lacných leteniek pre tých, ktorí radi cestujú

Do prieskumu sa môžu zapojiť iba registrovaní užívatelia. Prihlásiť saProsím.

Používate technológie zoškrabovania webu?

  • Да

  • Nie

Hlasovalo 8 užívateľov. 1 používateľ sa zdržal hlasovania.

Zdroj: hab.com

Pridať komentár