Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista

Artikkelin, jonka käännöksen julkaisemme tänään, kirjoittaja sanoo, että sen tavoitteena on puhua web-kaavin kehittämisestä Pythonissa käyttämällä Seleniumia, joka etsii lentolippujen hintoja. Lippuja haettaessa käytetään joustavia päivämääriä (+-3 päivää suhteessa ilmoitettuihin päivämääriin). Kaavin tallentaa hakutulokset Excel-tiedostoon ja lähettää haun suorittaneelle henkilölle sähköpostin yhteenvedon löytämistään. Tämän projektin tavoitteena on auttaa matkailijoita löytämään parhaat tarjoukset.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista

Jos tunnet olevasi eksyksissä materiaalia ymmärtäessäsi, katso tämä artikkeli.

Mitä me etsimme?

Voit vapaasti käyttää tässä kuvattua järjestelmää haluamallasi tavalla. Käytin sitä esimerkiksi etsiessäni viikonloppumatkoja ja lippuja kotikaupunkiini. Jos aiot tosissasi löytää kannattavia lippuja, voit ajaa skriptin palvelimella (yksinkertainen palvelin, 130 ruplaa kuukaudessa, on varsin sopiva tähän) ja varmista, että se toimii kerran tai kahdesti päivässä. Hakutulokset lähetetään sinulle sähköpostitse. Lisäksi suosittelen kaiken asettamista niin, että skripti tallentaa Excel-tiedoston hakutuloksineen Dropbox-kansioon, jonka avulla voit katsella tällaisia ​​tiedostoja missä tahansa ja milloin tahansa.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
En ole vielä löytänyt virheellisiä tariffeja, mutta mielestäni se on mahdollista

Haussa, kuten jo mainittiin, käytetään "joustavaa päivämäärää"; skripti löytää tarjoukset, jotka ovat kolmen päivän sisällä annetuista päivämääristä. Vaikka skriptiä ajaessaan se etsii tarjouksia vain yhteen suuntaan, sitä on helppo muokata niin, että se voi kerätä tietoja useista lentosuunnista. Sen avulla voit jopa etsiä virheellisiä tariffeja; tällaiset löydöt voivat olla erittäin mielenkiintoisia.

Miksi tarvitset toisen verkkokaavin?

Kun aloitin verkkoraapimisen, en ollut siitä erityisen kiinnostunut. Halusin tehdä lisää projekteja ennakoivan mallinnuksen, talousanalyysin ja mahdollisesti tekstien tunnevärjäyksen analysoinnin saralla. Mutta kävi ilmi, että oli erittäin mielenkiintoista selvittää, kuinka luoda ohjelma, joka kerää tietoja verkkosivustoilta. Kun syvennyin tähän aiheeseen, ymmärsin, että verkon kaapiminen on Internetin "moottori".

Saatat ajatella, että tämä on liian rohkea lausunto. Mutta ajattele, että Google aloitti verkkokaapimella, jonka Larry Page loi Javalla ja Pythonilla. Googlen robotit ovat tutkineet Internetiä ja yrittäneet tarjota käyttäjilleen parhaat vastaukset heidän kysymyksiinsä. Verkkokaappauksella on loputtomasti käyttötarkoituksia, ja vaikka olisit kiinnostunut jostain muusta datatieteestä, tarvitset kaapimistaitoja saadaksesi analysoitavan tiedon.

Löysin joitain täällä käytettyjä tekniikoita upeana kirja äskettäin hankkimastani verkkoraapimisesta. Se sisältää monia yksinkertaisia ​​esimerkkejä ja ideoita oppimasi käytännön soveltamiseen. Lisäksi on erittäin mielenkiintoinen luku reCaptcha-tarkistusten ohittamisesta. Tämä tuli minulle uutisena, koska en edes tiennyt, että tällaisten ongelmien ratkaisemiseen on olemassa erikoistyökaluja ja jopa kokonaisia ​​palveluita.

Pidätkö matkustamisesta?!

Tämän osion otsikossa esitettyyn yksinkertaiseen ja melko vaarattomaan kysymykseen kuulet usein myönteisen vastauksen, johon liittyy pari tarinaa sen henkilön matkoilta, jolle se kysyttiin. Useimmat meistä ovat samaa mieltä siitä, että matkustaminen on loistava tapa uppoutua uusiin kulttuuriympäristöihin ja laajentaa näköaloja. Jos kuitenkin kysyt joltakin, pitävätkö hän lentolippujen etsimisestä, olen varma, että vastaus ei ole niin myönteinen. Itse asiassa Python tulee avuksemme täällä.

Ensimmäinen tehtävä, joka meidän on ratkaistava matkalla lentolipputietojen hakujärjestelmän luomiseen, on sopivan alustan valinta, josta otamme tiedot. Tämän ongelman ratkaiseminen ei ollut minulle helppoa, mutta lopulta valitsin Kayak-palvelun. Kokeilin Momondon, Skyscannerin, Expedian ja muutamien muiden palveluita, mutta näiden resurssien robotin suojausmekanismit olivat läpitunkemattomia. Useiden yritysten jälkeen, joiden aikana jouduin käsittelemään liikennevaloja, jalankulkijoiden risteyksiä ja polkupyöriä, yrittäen vakuuttaa järjestelmät, että olen ihminen, päätin, että Kayak sopi minulle parhaiten huolimatta siitä, että vaikka liian monta sivua olisi ladattu lyhyessä ajassa, ja myös tarkastukset alkavat. Onnistuin saamaan botin lähettämään pyyntöjä sivustolle 4-6 tunnin välein, ja kaikki toimi hyvin. Ajoittain Kayakin kanssa työskennellessä ilmenee vaikeuksia, mutta jos he alkavat kiusata sinua shekeillä, sinun on joko käsiteltävä niitä manuaalisesti ja sitten käynnistettävä botti tai odotettava muutama tunti ja tarkastukset lopetetaan. Tarvittaessa voit helposti muokata koodia toiselle alustalle, ja jos teet niin, voit ilmoittaa siitä kommenteissa.

Jos olet vasta aloittamassa verkkoraapimista etkä tiedä, miksi jotkut verkkosivustot kamppailevat sen kanssa, tee itsellesi palvelus ennen kuin aloitat ensimmäisen projektin tällä alueella ja tee Google-haku sanoilla "web scraping etiketti". . Kokeilusi voivat päättyä nopeammin kuin uskotkaan, jos raaputtelet verkkoa epäviisaasti.

Aloittaminen

Tässä on yleinen katsaus siitä, mitä verkkokaapimellemme tapahtuu:

  • Tuo tarvittavat kirjastot.
  • Google Chrome -välilehden avaaminen.
  • Kutsu toiminto, joka käynnistää botin ja välittää sille kaupungit ja päivämäärät, joita käytetään lippujen haussa.
  • Tämä toiminto ottaa ensimmäiset hakutulokset parhaiden mukaan lajiteltuina ja lataa lisää tuloksia napsauttamalla painiketta.
  • Toinen toiminto kerää tietoja koko sivulta ja palauttaa datakehyksen.
  • Kaksi edellistä vaihetta suoritetaan lajittelutyypeillä lipun hinnan (halpa) ja lentonopeuden (nopein) mukaan.
  • Skriptin käyttäjälle lähetetään sähköposti, jossa on yhteenveto lippujen hinnoista (halvimmat liput ja keskihinta), ja tietokehys, jossa tiedot on lajiteltu kolmen edellä mainitun indikaattorin mukaan, tallennetaan Excel-tiedostona.
  • Kaikki edellä mainitut toiminnot suoritetaan jaksossa tietyn ajan kuluttua.

On huomattava, että jokainen Selenium-projekti alkaa verkko-ohjaimella. käytän Chromedriver, Työskentelen Google Chromen kanssa, mutta vaihtoehtoja on muitakin. PhantomJS ja Firefox ovat myös suosittuja. Kun olet ladannut ohjaimen, sinun on sijoitettava se sopivaan kansioon, ja tämä viimeistelee valmistelun sen käyttöä varten. Skriptimme ensimmäiset rivit avaavat uuden Chrome-välilehden.

Muista, että tarinassani en yritä avata uusia näköaloja löytääksesi hyviä lentolipputarjouksia. Tällaisten tarjousten etsimiseen on paljon kehittyneempiä tapoja. Haluan vain tarjota tämän materiaalin lukijoille yksinkertaisen mutta käytännöllisen tavan ratkaista tämä ongelma.

Tässä on koodi, josta puhuimme edellä.

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)

Koodin alussa näet pakettien tuontikomennot, joita käytetään koko projektissamme. Niin, randint käytetään saamaan botti "nukahtamaan" satunnaisen määrän sekunteja ennen uuden hakutoiminnon aloittamista. Yleensä yksikään botti ei tule toimeen ilman tätä. Jos suoritat yllä olevan koodin, Chrome-ikkuna avautuu, jota botti käyttää sivustojen käsittelyyn.

Tehdään pieni kokeilu ja avataan kayak.com-sivusto erilliseen ikkunaan. Valitsemme kaupungin, josta aiomme lentää, ja kaupungin, johon haluamme päästä, sekä lentopäivät. Kun valitset päivämääriä, varmista, että käytetään +-3 päivän vaihteluväliä. Kirjoitin koodin ottaen huomioon, mitä sivusto tuottaa vastauksena tällaisiin pyyntöihin. Jos esimerkiksi sinun täytyy etsiä lippuja vain tietyille päivämäärille, on suuri todennäköisyys, että joudut muokkaamaan bottikoodia. Kun puhun koodista, annan asianmukaisia ​​selityksiä, mutta jos olet hämmentynyt, kerro minulle.

Napsauta nyt hakupainiketta ja katso osoitepalkin linkkiä. Sen pitäisi olla samanlainen kuin linkki, jota käytän alla olevassa esimerkissä, jossa muuttuja on ilmoitettu kayak, joka tallentaa URL-osoitteen, ja menetelmää käytetään get web-ohjain. Kun napsautat hakupainiketta, tulosten pitäisi ilmestyä sivulle.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Kun käytin komentoa get yli kaksi tai kolme kertaa muutaman minuutin sisällä minua pyydettiin suorittamaan vahvistus reCaptchalla. Voit läpäistä tämän tarkistuksen manuaalisesti ja jatkaa kokeilua, kunnes järjestelmä päättää suorittaa uuden tarkistuksen. Kun testasin komentosarjaa, vaikutti siltä, ​​että ensimmäinen hakuistunto sujui aina sujuvasti, joten jos halusit kokeilla koodia, sinun tarvitsee vain ajoittain tarkistaa ja antaa koodin suorittaa manuaalisesti käyttämällä pitkiä hakujaksojen väliä. Ja jos ajattelee sitä, henkilö tuskin tarvitsee tietoa lippujen hinnoista, jotka on saatu 10 minuutin välein hakutoimintojen välillä.

Työskentely sivun kanssa XPathilla

Joten avasimme ikkunan ja latasimme sivuston. Hintojen ja muiden tietojen saamiseksi meidän on käytettävä XPath-tekniikkaa tai CSS-valitsimia. Päätin pysyä XPathissa enkä tuntenut tarvetta käyttää CSS-valitsimia, mutta se on täysin mahdollista toimia niin. Liikkuminen sivulla XPathin avulla voi olla hankalaa, vaikka käyttäisit kohdassa kuvailtuja tekniikoita tämä artikkelissa, jossa kopioitiin vastaavat tunnisteet sivukoodista, ymmärsin, että tämä ei itse asiassa ole optimaalinen tapa päästä tarvittaviin elementteihin. Muuten sisään tämä Kirja tarjoaa erinomaisen kuvauksen XPath- ja CSS-valitsimia käyttävien sivujen käytön perusteista. Tältä vastaava verkkoohjainmenetelmä näyttää.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Jatketaan siis työskentelyä botin parissa. Hyödynnetään ohjelman ominaisuuksia edullisimpien lippujen valitsemiseen. Seuraavassa kuvassa XPath-valitsinkoodi on korostettu punaisella. Nähdäksesi koodin sinun tulee klikata sinua kiinnostavaa sivuelementtiä hiiren oikealla painikkeella ja valita näkyviin tulevasta valikosta Tarkista-komento. Tätä komentoa voidaan kutsua eri sivuelementeille, joiden koodi näytetään ja korostetaan koodin katseluohjelmassa.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Näytä sivun koodi

Saadaksesi vahvistuksen päättelylleni valitsimien koodista kopioimisen haitoista, kiinnitä huomiota seuraaviin ominaisuuksiin.

Tämän saat, kun kopioit koodin:

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

Jos haluat kopioida jotain tällaista, sinun on napsauta hiiren kakkospainikkeella sinua kiinnostavaa koodin osaa ja valitse Kopioi > Kopioi XPath -komento näkyviin tulevasta valikosta.

Tässä on mitä käytin määrittämään Halvin-painike:

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

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Kopioi komento > Kopioi XPath

On ilmeistä, että toinen vaihtoehto näyttää paljon yksinkertaisemmalta. Kun sitä käytetään, se etsii elementtiä a, jolla on attribuutti data-code, yhtä suuri price. Ensimmäistä vaihtoehtoa käytettäessä elementtiä haetaan id joka on yhtä suuri kuin wtKI-price_aTab, ja XPath-polku elementtiin näyttää tältä /div[1]/div/div/div[1]/div/span/span. Tämän kaltainen XPath-kysely sivulle tekee tempun, mutta vain kerran. Voin sanoa heti sen id muuttuu, kun sivu ladataan seuraavan kerran. Hahmosarja wtKI muuttuu dynaamisesti aina, kun sivu ladataan, joten sitä käyttävä koodi on hyödytön seuraavan sivun uudelleenlatauksen jälkeen. Joten kestää jonkin aikaa ymmärtääksesi XPath. Tämä tieto palvelee sinua hyvin.

On kuitenkin huomattava, että XPath-valitsimien kopioiminen voi olla hyödyllistä työskennellessäsi melko yksinkertaisten sivustojen kanssa, ja jos olet tyytyväinen tähän, siinä ei ole mitään vikaa.

Mietitään nyt, mitä tehdä, jos haluat saada kaikki hakutulokset useille riveille luettelon sisällä. Erittäin yksinkertainen. Jokainen tulos on objektin sisällä, jossa on luokka resultWrapper. Kaikkien tulosten lataaminen voidaan tehdä alla olevan kaltaisessa silmukassa.

On huomattava, että jos ymmärrät yllä olevan, sinun pitäisi helposti ymmärtää suurin osa analysoimastamme koodista. Kun tämä koodi suoritetaan, pääsemme siihen, mitä tarvitsemme (itse asiassa elementin, johon tulos on kääritty) käyttämällä jonkinlaista polun määrittävää mekanismia (XPath). Tämä tehdään elementin tekstin saamiseksi ja sen sijoittamiseksi objektiin, josta voidaan lukea dataa (ensimmäinen käyttö flight_containers, sitten - flights_list).

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Ensimmäiset kolme riviä näkyvät ja näemme selvästi kaiken tarvitsemamme. Meillä on kuitenkin mielenkiintoisempia tapoja saada tietoa. Meidän on otettava tiedot jokaisesta elementistä erikseen.

Mene töihin!

Helpoin tapa kirjoittaa funktio on ladata lisätuloksia, joten siitä aloitetaan. Haluaisin maksimoida niiden lentojen määrän, joista ohjelma saa tietoa, herättämättä epäilyksiä tarkastukseen johtavassa palvelussa, joten napsautan Lataa lisää tuloksia -painiketta kerran joka kerta, kun sivu tulee näkyviin. Tässä koodissa sinun tulee kiinnittää huomiota lohkoon try, jonka lisäsin, koska joskus painike ei lataudu kunnolla. Jos myös kohtaat tämän, kommentoi tämän funktion kutsut toimintokoodiin start_kayak, jota tarkastelemme alla.

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

Nyt tämän funktion pitkän analyysin jälkeen (joskus voin tarttua), olemme valmiita julistamaan funktion, joka kaapii sivun.

Olen jo kerännyt suurimman osan siitä, mitä tarvitaan seuraavaan toimintoon nimeltä page_scrape. Joskus palautetut polkutiedot yhdistetään, joten käytän yksinkertaista tapaa erottaa ne. Esimerkiksi kun käytän muuttujia ensimmäistä kertaa section_a_list и section_b_list. Funktiomme palauttaa tietokehyksen flights_df, jolloin voimme erottaa eri tiedonlajittelumenetelmistä saadut tulokset ja yhdistää ne myöhemmin.

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

Yritin nimetä muuttujat niin, että koodi olisi ymmärrettävä. Muista, että muuttujat alkavat a kuuluvat polun ensimmäiseen vaiheeseen ja b - toiselle. Siirrytään seuraavaan toimintoon.

Tukimekanismit

Meillä on nyt toiminto, jonka avulla voimme ladata lisää hakutuloksia, ja toiminto näiden tulosten käsittelemiseksi. Tämä artikkeli olisi voinut päättyä tähän, koska nämä kaksi toimintoa tarjoavat kaiken, mitä tarvitset sivujen kaapimiseen, jotka voit avata itse. Mutta emme ole vielä tarkastelleet joitain edellä käsitellyistä apumekanismeista. Tämä on esimerkiksi sähköpostien ja joidenkin muiden asioiden lähettämisen koodi. Kaikki tämä löytyy funktiosta start_kayak, jota tarkastelemme nyt.

Jotta tämä toiminto toimisi, tarvitset tietoja kaupungeista ja päivämääristä. Näitä tietoja käyttämällä se muodostaa linkin muuttujaan kayak, jota käytetään viemään sinut sivulle, joka sisältää hakutuloksia lajiteltuina niiden kyselyä parhaiten vastaavien hakujen mukaan. Ensimmäisen kaavintakerran jälkeen käytämme hintoja sivun yläreunan taulukossa. Nimittäin löydämme lipun vähimmäishinnan ja keskihinnan. Kaikki tämä yhdessä sivuston antaman ennusteen kanssa lähetetään sähköpostitse. Sivulla vastaavan taulukon tulee olla vasemmassa yläkulmassa. Tämän taulukon käyttäminen voi muuten aiheuttaa virheen haettaessa tarkkoja päivämääriä, koska tässä tapauksessa taulukkoa ei näytetä sivulla.

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

Testasin tätä komentosarjaa Outlook-tilillä (hotmail.com). En ole testannut, että se toimii oikein Gmail-tilin kanssa, tämä sähköpostijärjestelmä on melko suosittu, mutta vaihtoehtoja on monia. Jos käytät Hotmail-tiliä, sinun tarvitsee vain syöttää tietosi koodiin, jotta kaikki toimisi.

Jos haluat ymmärtää, mitä tämän toiminnon koodin tietyissä osissa tarkalleen tehdään, voit kopioida ne ja kokeilla niitä. Koodin kokeileminen on ainoa tapa ymmärtää se todella.

Valmis järjestelmä

Nyt kun olemme tehneet kaiken, mistä puhuimme, voimme luoda yksinkertaisen silmukan, joka kutsuu funktioitamme. Skripti pyytää käyttäjältä tietoja kaupungeista ja päivämääristä. Kun testataan jatkuvalla skriptin uudelleenkäynnistyksellä, et todennäköisesti halua syöttää näitä tietoja manuaalisesti joka kerta, joten vastaavat rivit voidaan testauksen ajaksi kommentoida poistamalla kommentteja niiden alla olevista, joissa ohjelman tarvitsemat tiedot. skripti on kovakoodattu.

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

Tältä skriptin testiajo näyttää.
Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista
Skriptin koekäyttö

Tulokset

Jos olet päässyt näin pitkälle, onnittelut! Sinulla on nyt toimiva verkkokaavin, vaikka näenkin jo monia tapoja parantaa sitä. Se voidaan esimerkiksi integroida Twilioon niin, että se lähettää tekstiviestejä sähköpostien sijaan. Voit käyttää VPN:ää tai jotain muuta saadaksesi tuloksia samanaikaisesti useilta palvelimilta. Ajoittain ilmaantuu myös ongelma, kun sivuston käyttäjä tarkistetaan, onko hän henkilö, mutta tämäkin ongelma voidaan ratkaista. Joka tapauksessa nyt sinulla on pohja, jota voit halutessasi laajentaa. Varmista esimerkiksi, että Excel-tiedosto lähetetään käyttäjälle sähköpostin liitteenä.

Python - avustaja löytämään edullisia lentolippuja niille, jotka rakastavat matkustamista

Vain rekisteröityneet käyttäjät voivat osallistua kyselyyn. Kirjaudu sisään, ole kiltti.

Käytätkö verkkokaappaustekniikoita?

  • Kyllä

  • Ei

8 käyttäjää äänesti. 1 käyttäjä pidättyi äänestämästä.

Lähde: will.com

Lisää kommentti