Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà

L'autore di l'articulu, a traduzzione di quale avemu publicatu oghje, dice chì u so scopu hè di parlà di u sviluppu di un scraper web in Python cù Selenium, chì cerca i prezzi di i biglietti d'aereo. Quandu cercate i biglietti, sò aduprate date flessibili (+- 3 ghjorni relative à e date specificate). U scraper salva i risultati di ricerca in un schedariu Excel è manda à a persona chì curria a ricerca un email cun un riassuntu di ciò chì anu truvatu. U scopu di stu prughjettu hè di aiutà i viaghjatori à truvà e migliori offerte.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà

Se, mentre capisce u materiale, vi sentite persu, fate un ochju questu articulu.

Chì andemu à circà ?

Sò liberi di utilizà u sistema descrittu quì cumu vulete. Per esempiu, l'aghju utilizatu per circà i tour di u weekend è i biglietti per a mo cità nativa. Sè vo site seriu per truvà biglietti prufittuali, pudete eseguisce u script in u servitore (semplice servitore, per 130 rubles à u mese, hè abbastanza adattatu per questu) è assicuratevi chì corre una o duie volte à ghjornu. I risultati di a ricerca vi saranu mandati per email. Inoltre, ricumandemu di stabilisce tuttu ciò chì u script salva un schedariu Excel cù risultati di ricerca in un cartulare Dropbox, chì vi permetterà di vede tali schedari da ogni locu è in ogni mumentu.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Ùn aghju micca trovu tariffi cù errori, ma pensu chì hè pussibule

Quandu a ricerca, cum'è digià citatu, hè aduprata una "data flessibile"; u script trova offerte chì sò in trè ghjorni da e date date. Ancu s'ellu si eseguisce u script, cerca l'offerte in una sola direzzione, hè faciule fà mudificà per pudè raccoglie dati nantu à parechje direzzione di volu. Cù u so aiutu, pudete ancu cercà tariffi erronei; tali scuperte ponu esse assai interessanti.

Perchè avete bisognu di un altru web scraper?

Quandu aghju principiatu u web scraping, onestamente ùn era micca particularmente interessatu in questu. Vuliu fà più prughjetti in u campu di a modellazione predittiva, l'analisi finanziaria, è, possibbilmente, in u campu di l'analisi di u culore emutivu di i testi. Ma resultò chì era assai interessante per capisce cumu per creà un prugramma chì recullà dati da i siti web. Cume aghju sfondatu in questu tema, aghju realizatu chì u web scraping hè u "motore" di l'Internet.

Pudete pensà chì questu hè una dichjarazione troppu audace. Ma cunzidira chì Google hà cuminciatu cù un scraper web chì Larry Page hà creatu cù Java è Python. I robots di Google anu esploratu l'Internet, pruvatu à furnisce i so utilizatori cù e migliori risposte à e so dumande. U scraping Web hà usi infiniti, è ancu s'è vo site interessatu in qualcosa d'altru in Data Science, avete bisognu di qualchi capacità di scraping per uttene e dati chì avete bisognu di analizà.

Aghju trovu alcune di e tecniche aduprate quì in un maravigliu u libru nantu à u web scraping, chì aghju acquistatu recentemente. Contene assai esempi simplici è idee per l'applicazione pratica di ciò chì avete amparatu. Inoltre, ci hè un capitulu assai interessante nantu à l'annullamentu di i cuntrolli reCaptcha. Questu hè ghjuntu cum'è una nutizia per mè, postu chì ùn sapia ancu chì ci sò arnesi spiciali è ancu servizii interi per risolve tali prublemi.

Ti piace viaghjà ?!

À a quistione simplice è piuttostu innocu pusata in u tìtulu di sta sezione, pudete spessu sente una risposta pusitiva, accumpagnata da un paru di storie da i viaghji di a persona à quale hè stata dumandata. A maiò parte di noi avaristi d'accordu chì viaghjà hè una bella manera di immerse in novi ambienti culturali è allargate i vostri orizonti. Tuttavia, se dumandate à qualchissia s'ellu li piace à circà i biglietti d'aerei, sò sicuru chì a risposta ùn serà micca cusì pusitiva. In fatti, Python vene à u nostru aiutu quì.

U primu compitu chì avemu bisognu di risolve in a strada per creà un sistema per a ricerca di l'infurmazioni nantu à i biglietti aerei serà a selezzione di una piattaforma adattata da quale avemu da piglià l'infurmazioni. Risolve stu prublema ùn era micca faciule per mè, ma à a fine aghju sceltu u serviziu di Kayak. Pruvatu i servizii di Momondo, Skyscanner, Expedia, è uni pochi altri, ma i meccanismi di prutezzione di robot nantu à queste risorse eranu impenetrable. Dopu à parechji tentativi, durante i quali aghju avutu à trattà cù semafori, passaghji di pedoni è bicicletta, pruvatu à cunvince i sistemi chì eru umanu, decisu chì Kayak era più adattatu per mè, malgradu u fattu chì ancu s'è Troppu pagine sò caricate. in pocu tempu, è i cuntrolli cumincianu ancu. Aghju riesciutu à fà chì u bot invià e dumande à u situ à intervalli di 4 à 6 ore, è tuttu hà travagliatu bè. Da u tempu à u tempu, i difficultà si sviluppanu quandu u travagliu cù Kayak, ma s'ellu si cumincianu à fastidiu cù cuntrolli, allora avete bisognu di trattà cun elli manualmente è poi lancià u bot, o aspittà uni pochi d'ore è i cuntrolli duveranu piantà. Se necessariu, pudete facilmente adattà u codice per una altra plataforma, è se fate cusì, pudete rapportà in i cumenti.

Sè avete principiatu cù u web scraping è ùn sapete micca perchè certi siti web si battenu cun ellu, allora prima di inizià u vostru primu prughjettu in questa zona, fate un favore è fate una ricerca di Google nantu à e parolle "etichetta di scraping web". . I vostri esperimenti ponu finisce prima di ciò chì pensate se fate un scraping web imprudente.

Getting passé

Eccu una panoramica generale di ciò chì succede in u nostru codice web scraper:

  • Importà e librerie richieste.
  • Apertura di una tabulazione Google Chrome.
  • Chjamate una funzione chì principia u bot, passendu e cità è e date chì seranu usate quandu cercate i biglietti.
  • Sta funzione piglia i primi risultati di ricerca, ordinati da u megliu, è cliccate un buttone per carica più risultati.
  • Una altra funzione raccoglie dati da tutta a pagina è torna un quadru di dati.
  • I dui passi precedenti sò realizati aduprendu tipi di classificazione per prezzu di u bigliettu (u prezzu) è per a velocità di volu (più veloce).
  • L'utilizatore di u script hè mandatu un email chì cuntene un riassuntu di i prezzi di u bigliettu (biglietti più economici è prezzu mediu), è un quadru di dati cù l'infurmazioni ordenati da i trè indicatori sopra citati hè salvatu cum'è un schedariu Excel.
  • Tutte l'azzioni sopra sò realizati in un ciclu dopu un periudu di tempu.

Hè da nutà chì ogni prughjettu di Selenium principia cù un driver web. Aghju aduprà Chromedriver, U travagliu cù Google Chrome, ma ci sò altre opzioni. PhantomJS è Firefox sò ancu populari. Dopu avè scaricatu u driver, avete bisognu à mette in u cartulare apprupriatu, è questu compie a preparazione per u so usu. E prime linee di u nostru script apre una nova tabulazione Chrome.

Tenite in mente chì in a mo storia ùn sò micca pruvatu à apre novi orizonti per truvà grandi offerte nantu à i biglietti aerei. Ci sò metudi assai più avanzati di ricerca di tali offerte. Vogliu solu offre à i lettori di stu materiale un modu simplice ma praticu per risolve stu prublema.

Eccu u codice chì avemu parlatu sopra.

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)

À u principiu di u codice pudete vede i cumandamenti di impurtazione di u pacchettu chì sò usati in tuttu u nostru prughjettu. Allora, randint utilizatu per fà u bot "addormentà" per un numeru aleatoriu di seconde prima di inizià una nova operazione di ricerca. Di solitu, micca un solu bot pò fà senza questu. Se eseguite u codice sopra, una finestra di Chrome si apre, chì u bot hà da aduprà per travaglià cù siti.

Facemu un pocu esperimentu è apre u situ web kayak.com in una finestra separata. Selezziemu a cità da quale andemu à vola, è a cità chì vulemu ghjunghje, è ancu e date di u volu. Quandu sceglite e date, assicuratevi chì a gamma di + -3 ghjorni hè utilizata. Aghju scrittu u codice in cunsiderà ciò chì u situ pruduce in risposta à tali dumande. Se, per esempiu, avete bisognu di circà i biglietti solu per e date specificate, allora ci hè una alta probabilità chì avete da mudificà u codice bot. Quandu parlu di u codice, aghju datu spiegazioni appropritate, ma se vi sentite cunfusu, fatemi sapè.

Avà cliccate nant'à u buttone di ricerca è fighjate à u ligame in a barra di indirizzu. Deve esse simile à u ligame chì aghju utilizatu in l'esempiu sottu induve a variàbile hè dichjarata kayak, chì guarda l'URL, è u metudu hè utilizatu get driver web. Dopu à cliccà u buttone di ricerca, i risultati duveranu apparisce in a pagina.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Quandu aghju utilizatu u cumandamentu get più di duie o trè volte in pochi minuti, mi hè statu dumandatu à compie a verificazione cù reCaptcha. Pudete passà stu cuntrollu manualmente è cuntinuà à sperimentà finu à chì u sistema decide di eseguisce un novu cuntrollu. Quandu aghju pruvatu u script, pareva chì a prima sessione di ricerca hè sempre andata bè, per quessa, se vulete sperimentà u codice, avete bisognu di verificà periodicamente manualmente è lascià u codice corre, utilizendu intervalli longu trà e sessioni di ricerca. E, se pensate à questu, una persona hè improbabile di avè bisognu d'infurmazioni nantu à i prezzi di i biglietti ricevuti à intervalli di 10 minuti trà e operazioni di ricerca.

U travagliu cù una pagina cù XPath

Allora, avemu apertu una finestra è caricate u situ. Per uttene i prezzi è altre informazioni, avemu bisognu di utilizà a tecnulugia XPath o selettori CSS. Aghju decisu di stà cun XPath è ùn sentu micca bisognu di utilizà selettori CSS, ma hè abbastanza pussibule di travaglià cusì. Navigazione intornu à una pagina cù XPath pò esse difficiule, è ancu s'ellu utilizate e tecniche chì aghju descrittu questu articulu, chì implicava a copia di l'identificatori currispondenti da u codice di a pagina, aghju realizatu chì questu hè, in fattu, micca u modu ottimali per accede à l'elementi necessarii. Per via, in questu U libru furnisce una descrizzione eccellente di i fundamenti di travaglià cù e pagine cù selettori XPath è CSS. Questu hè u metudu di u driver web currispundente.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Dunque, cuntinuemu à travaglià nantu à u bot. Utilizemu e capacità di u prugramma per selezziunà i biglietti più economici. In l'imagine seguente, u codice di selettore XPath hè evidenziatu in rossu. Per vede u codice, avete bisognu à cliccà cù u dirittu nantu à l'elementu di a pagina chì vi interessa è selezziunate l'ordine Inspect da u menù chì appare. Stu cumandamentu pò esse chjamatu per diversi elementi di pagina, u codice di quale serà mostratu è evidenziatu in u visor di codice.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Vede u codice di a pagina

Per truvà cunferma di u mo ragiunamentu nantu à i disadvantages di cupià selettori da u codice, fate attenzione à e seguenti caratteristiche.

Questu hè ciò chì uttene quandu copiate u codice:

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

Per copià qualcosa cum'è questu, avete bisognu di cliccà cù u dirittu nantu à a sezione di codice chì vi interessa è selezziunate l'ordine Copia> Copia XPath da u menù chì appare.

Eccu ciò chì aghju utilizatu per definisce u buttone più economicu:

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

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Copia Command> Copia XPath

Hè abbastanza ovvi chì a seconda opzione pare assai più simplice. Quandu s'utilice, cerca un elementu a chì hà l'attributu data-codeuguale à price. Quandu si usa a prima opzione, l'elementu hè cercatu id chì hè uguale à wtKI-price_aTab, è u percorsu XPath à l'elementu s'assumiglia /div[1]/div/div/div[1]/div/span/span. Una dumanda XPath cum'è questa à una pagina farà u truccu, ma solu una volta. Possu dì avà chì id cambierà a prossima volta chì a pagina hè caricata. Sequenza di caratteri wtKI cambia dinamicamente ogni volta chì a pagina hè caricata, cusì u codice chì l'utiliza serà inutile dopu a ricarica di a pagina successiva. Allora pigliate un pocu di tempu per capisce XPath. Sta cunniscenza vi serve bè.

In ogni casu, deve esse nutatu chì cupià i selettori XPath pò esse utile à travaglià cù siti abbastanza simplici, è se site cunfortu cù questu, ùn ci hè nunda di male.

Avà pensemu à ciò chì deve fà s'ellu ci vole à ottene tutti i risultati di ricerca in parechje linee, in una lista. Assai sèmplice. Ogni risultatu hè in un oggettu cù una classa resultWrapper. Caricà tutti i risultati pò esse fattu in un ciclu simile à quellu mostratu quì sottu.

Si deve esse nutatu chì s'è vo capisce u sopra, allura tu avissi a facirmenti capisce a maiò parte di u codice chì avemu da analizà. Cume stu codice corre, accede à ciò chì avemu bisognu (in fattu, l'elementu in quale u risultatu hè imballatu) utilizendu un tipu di mecanismu di specificazione di a strada (XPath). Questu hè fattu per piglià u testu di l'elementu è mette in un oggettu da quale dati ponu esse leghjiti (prima utilizatu flight_containers, allora - flights_list).

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
I primi trè linii sò affissati è pudemu vede chjaramente tuttu ciò chì avemu bisognu. Tuttavia, avemu modi più interessanti di ottene infurmazioni. Avemu bisognu di piglià dati da ogni elementu separatamente.

Mettite à u travagliu !

A manera più faciule di scrive una funzione hè di carricà risultati supplementari, cusì hè quì chì avemu da principià. Vogliu maximizà u nùmeru di voli chì u prugramma riceve infurmazione, senza suscitarà suspetti in u serviziu chì porta à una ispezione, per quessa, cliccu nantu à u buttone Carica più risultati una volta ogni volta chì a pagina hè visualizata. In questu codice, duvete attentu à u bloccu try, chì aghju aghjustatu perchè qualchì volta u buttone ùn carica micca bè. Sè vo ancu scontru questu, cummentate e chjama à sta funzione in u codice di funzione start_kayak, chì guardemu quì sottu.

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

Avà, dopu una longa analisi di sta funzione (a volte possu esse purtatu), simu pronti à dichjarà una funzione chì scraperà a pagina.

Aghju digià cullatu a maiò parte di ciò chì hè necessariu in a seguente funzione chjamata page_scrape. A volte, i dati di u percorsu restituitu sò cumminati, cusì aduprate un metudu simplice per separà. Per esempiu, quandu aghju utilizatu variàbili per a prima volta section_a_list и section_b_list. A nostra funzione torna un quadru di dati flights_df, questu ci permette di separà i risultati ottenuti da diversi metudi di sorte di dati è più tardi cumminà.

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

Aghju pruvatu à nome di e variàbili in modu chì u codice sia comprensibile. Ricurdativi chì i variàbili cumincianu cù a appartene à a prima tappa di a strada, è b - à u sicondu. Andemu à a funzione dopu.

Meccanismi di sustegnu

Avemu avà una funzione chì ci permette di carricà risultati di ricerca supplementari è una funzione per processà quelli risultati. Questu articulu puderia esse finitu quì, postu chì sti dui funzioni furnisce tuttu ciò chì avete bisognu di scrape pagine chì pudete apre. Ma ùn avemu ancu cunsideratu alcuni di i miccanismi ausiliarii discututi sopra. Per esempiu, questu hè u codice per mandà e-mail è altre cose. Tuttu chistu pò esse truvatu in a funzione start_kayak, chì avemu da cunsiderà avà.

Per fà sta funzione, avete bisognu d'infurmazioni nantu à e cità è e date. Utilizendu sta informazione, forma un ligame in una variabile kayak, chì hè utilizatu per piglià à una pagina chì cuntene i risultati di ricerca ordinati da u so megliu match à a dumanda. Dopu a prima sessione di scraping, avemu da travaglià cù i prezzi in a tavula in cima di a pagina. Vale à dì, truveremu u prezzu minimu di u bigliettu è u prezzu mediu. Tuttu chistu, inseme cù a predizione emessa da u situ, serà mandatu per email. In a pagina, a tavula currispundente deve esse in l'angulu superiore manca. U travagliu cù sta tavula, per via, pò causà un errore durante a ricerca cù e date precise, postu chì in questu casu a tavola ùn hè micca visualizata nantu à a pagina.

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

Aghju pruvatu stu script cù un contu Outlook (hotmail.com). Ùn aghju micca pruvatu à travaglià currettamente cù un contu Gmail, stu sistema di email hè abbastanza populari, ma ci sò parechje opzioni pussibuli. Sè vo aduprate un contu Hotmail, tandu in ordine per tuttu à travaglià, vi basta à entre i vostri dati in u codice.

Se vulete capisce ciò chì esattamente hè fattu in sezzioni specifiche di u codice per questa funzione, pudete copià è sperimentà cun elli. Sperimentà cù u codice hè l'unicu modu per capiscenu veramente.

Sistema prontu

Avà chì avemu fattu tuttu ciò chì avemu parlatu, pudemu creà un ciclu simplice chì chjama e nostre funzioni. U script richiede dati da l'utilizatori nantu à e cità è e date. Quandu a prova cù un riavviu constante di u script, hè improbabile chì vulete inserisce queste dati manualmente ogni volta, cusì e linee currispundenti, per u tempu di a prova, ponu esse cummentate da uncommenting quelli sottu à elli, in quale i dati necessarii da u script hè hardcoded.

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

# city_from = 'LIS'
# city_to = 'SIN'
# date_start = '2019-08-21'
# date_end = '2019-09-07'

for n in range(0,5):
    start_kayak(city_from, city_to, date_start, date_end)
    print('iteration {} was complete @ {}'.format(n, strftime("%Y%m%d-%H%M")))
    
    # Ждём 4 часа
    sleep(60*60*4)
    print('sleep finished.....')

Questu hè ciò chì un test run di u script pare.
Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà
Test run di u script

Risultati

Sè vo avete fattu finu à quì, felicitazioni ! Avete avà un scraper web di travagliu, ancu s'ellu possu digià vede parechje manere di migliurà. Per esempiu, pò esse integratu cù Twilio per ch'ellu manda missaghji di testu invece di email. Pudete utilizà una VPN o qualcosa altru per riceve risultati simultaneamente da parechji servitori. Ci hè ancu un prublema periòdicamente chì cuntrollà l'utilizatori di u situ per vede s'ellu hè una persona, ma questu prublema pò ancu esse risolta. In ogni casu, avà avete una basa chì pudete espansione se vulete. Per esempiu, assicuratevi chì un schedariu Excel hè mandatu à l'utilizatore cum'è un attache à un email.

Python - un assistente à truvà biglietti aerei di prezzu per quelli chì amanu viaghjà

Solu l'utilizatori registrati ponu participà à l'indagine. Firmà lu, per piacè.

Aduprate tecnulugia di scraping web?

  • chì

  • No

8 utilizatori anu vutatu. 1 utilizatore s'hè astenutu.

Source: www.habr.com

Add a comment