Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë

Autori i artikullit, përkthimin e të cilit po e botojmë sot, thotë se qëllimi i tij është të flasë për zhvillimin e një web scraper në Python duke përdorur Selenium, i cili kërkon çmimet e biletave të linjës ajrore. Kur kërkoni për bileta, përdoren data fleksibël (+- 3 ditë në lidhje me datat e specifikuara). Scraper ruan rezultatet e kërkimit në një skedar Excel dhe i dërgon personit që kreu kërkimin një email me një përmbledhje të asaj që gjeti. Qëllimi i këtij projekti është të ndihmojë udhëtarët të gjejnë ofertat më të mira.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë

Nëse, ndërsa kuptoni materialin, ndiheni të humbur, hidhini një sy kjo artikull.

Çfarë do të kërkojmë?

Ju jeni të lirë të përdorni sistemin e përshkruar këtu sipas dëshirës tuaj. Për shembull, e përdora për të kërkuar turne në fundjavë dhe bileta për në qytetin tim. Nëse jeni serioz për të gjetur bileta fitimprurëse, mund ta ekzekutoni skriptin në server (e thjeshtë server, për 130 rubla në muaj, është mjaft i përshtatshëm për këtë) dhe sigurohuni që të funksionojë një ose dy herë në ditë. Rezultatet e kërkimit do t'ju dërgohen me email. Për më tepër, unë rekomandoj të vendosni gjithçka në mënyrë që skripti të ruajë një skedar Excel me rezultatet e kërkimit në një dosje Dropbox, e cila do t'ju lejojë të shikoni skedarë të tillë nga kudo dhe në çdo kohë.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Nuk kam gjetur ende tarifa me gabime, por mendoj se është e mundur

Gjatë kërkimit, siç është përmendur tashmë, përdoret një "datë fleksibël"; skenari gjen oferta që janë brenda tre ditëve nga datat e dhëna. Edhe pse kur ekzekuton skriptin, ai kërkon oferta vetëm në një drejtim, është e lehtë ta modifikosh atë në mënyrë që të mund të mbledhë të dhëna për disa drejtime fluturimi. Me ndihmën e tij, madje mund të kërkoni tarifa të gabuara; gjetje të tilla mund të jenë shumë interesante.

Pse keni nevojë për një kruese tjetër në internet?

Kur fillova për herë të parë scraping në internet, sinqerisht nuk isha veçanërisht i interesuar për të. Doja të bëja më shumë projekte në fushën e modelimit parashikues, analizës financiare dhe, mundësisht, në fushën e analizimit të ngjyrosjes emocionale të teksteve. Por doli se ishte shumë interesante të kuptoje se si të krijohet një program që mbledh të dhëna nga faqet e internetit. Teksa u futa në këtë temë, kuptova se scraping në ueb është "motori" i internetit.

Ju mund të mendoni se kjo është një deklaratë shumë e guximshme. Por konsideroni se Google filloi me një web scraper që Larry Page krijoi duke përdorur Java dhe Python. Robotët e Google kanë eksploruar internetin, duke u përpjekur t'u ofrojnë përdoruesve të tij përgjigjet më të mira për pyetjet e tyre. Skrapimi i uebit ka përdorime të pafundme, dhe edhe nëse jeni të interesuar për diçka tjetër në Shkencën e të Dhënave, do t'ju nevojiten disa aftësi skrapimi për të marrë të dhënat që ju nevojiten për të analizuar.

Kam gjetur disa nga teknikat e përdorura këtu në një të mrekullueshme libri në lidhje me scraping në internet, të cilën e kam fituar së fundmi. Ai përmban shumë shembuj dhe ide të thjeshta për zbatimin praktik të asaj që keni mësuar. Përveç kësaj, ekziston një kapitull shumë interesant për anashkalimin e kontrolleve reCaptcha. Ky më erdhi si lajm, pasi as që e dija që kishte mjete speciale dhe madje shërbime të tëra për zgjidhjen e problemeve të tilla.

A ju pëlqen të udhëtoni?!

Pyetjes së thjeshtë dhe mjaft të padëmshme që shtrohet në titullin e këtij seksioni, shpesh mund të dëgjoni një përgjigje pozitive, të shoqëruar me disa histori nga udhëtimet e personit të cilit iu drejtua. Shumica prej nesh do të pajtoheshin se udhëtimi është një mënyrë e shkëlqyer për të zhytur veten në mjedise të reja kulturore dhe për të zgjeruar horizontet tuaja. Sidoqoftë, nëse pyet dikë nëse i pëlqen të kërkojë bileta ajrore, jam i sigurt se përgjigja nuk do të jetë aq pozitive. Në fakt, Python na vjen në ndihmë këtu.

Detyra e parë që duhet të zgjidhim në rrugën drejt krijimit të një sistemi për kërkimin e informacionit për biletat ajrore do të jetë zgjedhja e një platforme të përshtatshme nga e cila do të marrim informacion. Zgjidhja e këtij problemi nuk ishte e lehtë për mua, por në fund zgjodha shërbimin Kayak. Provova shërbimet e Momondo, Skyscanner, Expedia dhe disa të tjerë, por mekanizmat e mbrojtjes së robotëve në këto burime ishin të padepërtueshme. Pas disa përpjekjeve, gjatë të cilave m'u desh të merresha me semaforët, vendkalimet e këmbësorëve dhe biçikletat, duke u përpjekur të bindja sistemet se isha njeri, vendosa që Kayak ishte më i përshtatshmi për mua, pavarësisht se edhe nëse ngarkohen shumë faqe në një kohë të shkurtër dhe gjithashtu fillojnë kontrollet. Arrita të bëj që roboti të dërgojë kërkesa në sit në intervale prej 4 deri në 6 orë, dhe gjithçka funksionoi mirë. Herë pas here, lindin vështirësi kur punoni me Kayak, por nëse ata fillojnë t'ju ngacmojnë me çeqe, atëherë ju duhet ose t'i trajtoni ato me dorë dhe më pas të lansoni bot-in, ose të prisni disa orë dhe kontrollet duhet të ndalojnë. Nëse është e nevojshme, mund ta përshtatni lehtësisht kodin për një platformë tjetër dhe nëse e bëni këtë, mund ta raportoni në komente.

Nëse sapo keni filluar me scraping në ueb dhe nuk e dini pse disa faqe interneti luftojnë me të, atëherë përpara se të filloni projektin tuaj të parë në këtë fushë, bëjini vetes një nder dhe bëni një kërkim në Google për fjalët "etiketa e gërvishtjes së internetit" . Eksperimentet tuaja mund të përfundojnë më shpejt se sa mendoni nëse bëni gërvishtje në internet në mënyrë të pamatur.

Si T'ia Fillohet

Këtu është një përmbledhje e përgjithshme e asaj që do të ndodhë në kodin tonë të gërvishtjes së uebit:

  • Importoni bibliotekat e kërkuara.
  • Hapja e një skede Google Chrome.
  • Thirrni një funksion që nis bot-in, duke i kaluar qytetet dhe datat që do të përdoren gjatë kërkimit të biletave.
  • Ky funksion merr rezultatet e para të kërkimit, të renditura sipas më të mirave, dhe klikon një buton për të ngarkuar më shumë rezultate.
  • Një funksion tjetër mbledh të dhëna nga e gjithë faqja dhe kthen një kornizë të dhënash.
  • Dy hapat e mëparshëm kryhen duke përdorur llojet e renditjes sipas çmimit të biletës (e lirë) dhe sipas shpejtësisë së fluturimit (më e shpejtë).
  • Përdoruesit të skriptit i dërgohet një email që përmban një përmbledhje të çmimeve të biletave (biletat më të lira dhe çmimi mesatar) dhe një kornizë e të dhënave me informacione të renditura sipas tre treguesve të sipërpërmendur ruhet si një skedar Excel.
  • Të gjitha veprimet e mësipërme kryhen në një cikël pas një periudhe të caktuar kohe.

Duhet të theksohet se çdo projekt Selenium fillon me një drejtues web. Unë përdor Kromdriver, Unë punoj me Google Chrome, por ka mundësi të tjera. PhantomJS dhe Firefox janë gjithashtu të njohura. Pas shkarkimit të shoferit, duhet ta vendosni në dosjen e duhur dhe kjo përfundon përgatitjen për përdorimin e tij. Rreshtat e parë të skenarit tonë hapin një skedë të re të Chrome.

Mbani në mend se në historinë time nuk po përpiqem të hap horizonte të reja për të gjetur oferta të shkëlqyera për biletat ajrore. Ka metoda shumë më të avancuara për të kërkuar oferta të tilla. Unë thjesht dua t'u ofroj lexuesve të këtij materiali një mënyrë të thjeshtë por praktike për të zgjidhur këtë problem.

Këtu është kodi për të cilin folëm më lart.

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)

Në fillim të kodit mund të shihni komandat e importit të paketës që përdoren gjatë gjithë projektit tonë. Kështu që, randint përdoret për ta bërë robotin "të bie në gjumë" për një numër të rastësishëm sekondash përpara se të fillonte një operacion të ri kërkimi. Zakonisht, asnjë bot i vetëm nuk mund të bëjë pa këtë. Nëse përdorni kodin e mësipërm, do të hapet një dritare e Chrome, të cilën roboti do ta përdorë për të punuar me sajtet.

Le të bëjmë një eksperiment të vogël dhe të hapim faqen e internetit kayak.com në një dritare të veçantë. Ne do të zgjedhim qytetin nga i cili do të fluturojmë, qytetin ku duam të shkojmë, si dhe datat e fluturimit. Kur zgjidhni datat, sigurohuni që të përdoret diapazoni prej +-3 ditësh. E shkrova kodin duke marrë parasysh atë që prodhon faqja në përgjigje të kërkesave të tilla. Nëse, për shembull, ju duhet të kërkoni për bileta vetëm për data të specifikuara, atëherë ekziston një probabilitet i lartë që do t'ju duhet të modifikoni kodin e botit. Kur flas për kodin, jap shpjegimet e duhura, por nëse ndiheni konfuz, më njoftoni.

Tani klikoni në butonin e kërkimit dhe shikoni lidhjen në shiritin e adresave. Duhet të jetë e ngjashme me lidhjen që përdor në shembullin më poshtë ku është deklaruar variabla kayak, e cila ruan URL-në dhe përdoret metoda get shofer në internet. Pasi të klikoni butonin e kërkimit, rezultatet duhet të shfaqen në faqe.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Kur përdora komandën get më shumë se dy ose tre herë brenda pak minutash, më kërkuan të përfundoja verifikimin duke përdorur reCaptcha. Ju mund ta kaloni këtë kontroll me dorë dhe të vazhdoni të eksperimentoni derisa sistemi të vendosë të kryejë një kontroll të ri. Kur testova skriptin, dukej sikur sesioni i parë i kërkimit shkoi gjithmonë pa probleme, kështu që nëse dëshironi të eksperimentoni me kodin, do t'ju duhet vetëm të kontrolloni periodikisht manualisht dhe ta lini kodin të ekzekutohej, duke përdorur intervale të gjata midis seancave të kërkimit. Dhe, nëse mendoni për këtë, një person nuk ka gjasa të ketë nevojë për informacion në lidhje me çmimet e biletave të marra në intervale 10-minutëshe midis operacioneve të kërkimit.

Puna me një faqe duke përdorur XPath

Pra, hapëm një dritare dhe ngarkuam faqen. Për të marrë çmimet dhe informacione të tjera, duhet të përdorim teknologjinë XPath ose përzgjedhësit CSS. Vendosa të qëndroj me XPath dhe nuk ndjeva nevojën për të përdorur përzgjedhësit CSS, por është mjaft e mundur të punosh në këtë mënyrë. Lundrimi nëpër një faqe duke përdorur XPath mund të jetë i ndërlikuar, madje edhe nëse përdorni teknikat që përshkrova kjo artikull, i cili përfshinte kopjimin e identifikuesve përkatës nga kodi i faqes, kuptova se kjo, në fakt, nuk është mënyra optimale për të hyrë në elementët e nevojshëm. Nga rruga, në kjo Libri ofron një përshkrim të shkëlqyeshëm të bazave të punës me faqe duke përdorur përzgjedhësit XPath dhe CSS. Kështu duket metoda përkatëse e drejtuesit të uebit.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Pra, le të vazhdojmë të punojmë në bot. Le të përdorim aftësitë e programit për të zgjedhur biletat më të lira. Në imazhin e mëposhtëm, kodi i përzgjedhësit XPath është theksuar me të kuqe. Për të parë kodin, duhet të klikoni me të djathtën në elementin e faqes që ju intereson dhe të zgjidhni komandën Inspect nga menyja që shfaqet. Kjo komandë mund të thirret për elementë të ndryshëm të faqes, kodi i të cilave do të shfaqet dhe theksohet në shikuesin e kodit.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Shiko kodin e faqes

Për të gjetur konfirmimin e arsyetimit tim në lidhje me disavantazhet e kopjimit të përzgjedhësve nga kodi, kushtojini vëmendje veçorive të mëposhtme.

Kjo është ajo që merrni kur kopjoni kodin:

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

Për të kopjuar diçka të tillë, duhet të klikoni me të djathtën në seksionin e kodit që ju intereson dhe të zgjidhni komandën Copy > Copy XPath nga menyja që shfaqet.

Ja çfarë kam përdorur për të përcaktuar butonin më të lirë:

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

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Komanda e kopjimit > Kopjo XPath

Është mjaft e qartë se opsioni i dytë duket shumë më i thjeshtë. Kur përdoret, ai kërkon një element a që ka atributin data-codee barabartë me price. Kur përdorni opsionin e parë, elementi kërkohet id e cila është e barabartë me wtKI-price_aTab, dhe rruga XPath për në element duket si /div[1]/div/div/div[1]/div/span/span. Një pyetje XPath si kjo në një faqe do ta bëjë mashtrimin, por vetëm një herë. Mund të them që tani id do të ndryshojë herën tjetër që faqja të ngarkohet. Sekuenca e personazheve wtKI ndryshon në mënyrë dinamike sa herë që ngarkohet faqja, kështu që kodi që e përdor do të jetë i padobishëm pas ringarkimit të faqes tjetër. Pra, merrni pak kohë për të kuptuar XPath. Kjo njohuri do t'ju shërbejë mirë.

Sidoqoftë, duhet të theksohet se kopjimi i përzgjedhësve XPath mund të jetë i dobishëm kur punoni me sajte mjaft të thjeshta, dhe nëse jeni të kënaqur me këtë, nuk ka asgjë të keqe me të.

Tani le të mendojmë se çfarë të bëni nëse keni nevojë të merrni të gjitha rezultatet e kërkimit në disa rreshta, brenda një liste. Shume e thjeshte. Çdo rezultat është brenda një objekti me një klasë resultWrapper. Ngarkimi i të gjitha rezultateve mund të bëhet në një lak të ngjashëm me atë të paraqitur më poshtë.

Duhet të theksohet se nëse kuptoni sa më sipër, atëherë duhet të kuptoni lehtësisht pjesën më të madhe të kodit që do të analizojmë. Ndërsa ekzekutohet ky kod, ne aksesojmë atë që na nevojitet (në fakt, elementi në të cilin është mbështjellë rezultati) duke përdorur një lloj mekanizmi specifikues të rrugës (XPath). Kjo bëhet për të marrë tekstin e elementit dhe për ta vendosur atë në një objekt nga i cili mund të lexohen të dhënat (përdorur së pari flight_containers, atëherë - flights_list).

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Tre rreshtat e parë shfaqen dhe ne mund të shohim qartë gjithçka që na nevojitet. Megjithatë, ne kemi mënyra më interesante për të marrë informacion. Duhet të marrim të dhëna nga secili element veç e veç.

Shkoni në punë!

Mënyra më e lehtë për të shkruar një funksion është të ngarkoni rezultate shtesë, kështu që këtu do të fillojmë. Do të doja të maksimizoja numrin e fluturimeve për të cilat programi merr informacione, pa ngjallur dyshime në shërbimin që çon në një inspektim, ndaj klikoj butonin Load more results një herë sa herë që shfaqet faqja. Në këtë kod, duhet t'i kushtoni vëmendje bllokut try, të cilën e shtova sepse ndonjëherë butoni nuk ngarkohet siç duhet. Nëse e hasni edhe këtë, komentoni thirrjet për këtë funksion në kodin e funksionit start_kayak, të cilën do ta shohim më poshtë.

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

Tani, pas një analize të gjatë të këtij funksioni (ndonjëherë mund të marr me vete), ne jemi gati të deklarojmë një funksion që do të gërvisht faqen.

Unë kam mbledhur tashmë shumicën e asaj që nevojitet në funksionin e mëposhtëm të quajtur page_scrape. Ndonjëherë të dhënat e rrugës së kthyer kombinohen, kështu që unë përdor një metodë të thjeshtë për t'i ndarë ato. Për shembull, kur përdor variabla për herë të parë section_a_list и section_b_list. Funksioni ynë kthen një kornizë të dhënash flights_df, kjo na lejon të veçojmë rezultatet e marra nga metoda të ndryshme të renditjes së të dhënave dhe më vonë t'i kombinojmë ato.

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

Unë u përpoqa të emëroja variablat në mënyrë që kodi të ishte i kuptueshëm. Mos harroni se variablat duke filluar me a i përkasin fazës së parë të rrugës, dhe b - tek e dyta. Le të kalojmë te funksioni tjetër.

Mekanizmat mbështetës

Tani kemi një funksion që na lejon të ngarkojmë rezultate shtesë të kërkimit dhe një funksion për t'i përpunuar ato rezultate. Ky artikull mund të kishte përfunduar këtu, pasi këto dy funksione ofrojnë gjithçka që ju nevojitet për të gërvishtur faqet që mund t'i hapni vetë. Por ne ende nuk kemi shqyrtuar disa nga mekanizmat ndihmës të diskutuar më sipër. Për shembull, ky është kodi për dërgimin e emaileve dhe disa gjëra të tjera. E gjithë kjo mund të gjendet në funksion start_kayak, të cilën do ta shqyrtojmë tani.

Që ky funksion të funksionojë, ju nevojiten informacione për qytetet dhe datat. Duke përdorur këtë informacion, ai formon një lidhje në një variabël kayak, e cila përdoret për t'ju çuar në një faqe që do të përmbajë rezultatet e kërkimit të renditura sipas përputhjes së tyre më të mirë me pyetjen. Pas seancës së parë të skrapimit, ne do të punojmë me çmimet në tabelën në krye të faqes. Domethënë, do të gjejmë çmimin minimal të biletës dhe çmimin mesatar. E gjithë kjo, së bashku me parashikimin e lëshuar nga faqja, do të dërgohet me email. Në faqe, tabela përkatëse duhet të jetë në këndin e sipërm të majtë. Puna me këtë tabelë, nga rruga, mund të shkaktojë një gabim kur kërkoni duke përdorur data të sakta, pasi në këtë rast tabela nuk shfaqet në faqe.

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

E testova këtë skript duke përdorur një llogari të Outlook (hotmail.com). Nuk e kam testuar që të funksionojë siç duhet me një llogari Gmail, ky sistem emaili është mjaft popullor, por ka shumë opsione të mundshme. Nëse përdorni një llogari Hotmail, atëherë në mënyrë që gjithçka të funksionojë, thjesht duhet të futni të dhënat tuaja në kod.

Nëse doni të kuptoni se çfarë saktësisht po bëhet në seksione specifike të kodit për këtë funksion, mund t'i kopjoni dhe të eksperimentoni me to. Eksperimentimi me kodin është mënyra e vetme për ta kuptuar me të vërtetë atë.

Sistemi i gatshëm

Tani që kemi bërë gjithçka për të cilën folëm, mund të krijojmë një lak të thjeshtë që thërret funksionet tona. Skripti kërkon të dhëna nga përdoruesi për qytetet dhe datat. Kur testoni me rinisje të vazhdueshme të skriptit, nuk ka gjasa që të dëshironi t'i futni këto të dhëna manualisht çdo herë, kështu që rreshtat përkatës, për kohën e testimit, mund të komentohen duke mos komentuar ato poshtë tyre, në të cilat të dhënat e nevojshme nga skripti është i koduar.

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

Kështu duket një provë e skenarit.
Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë
Testimi i skenarit

Rezultatet e

Nëse keni arritur deri këtu, urime! Ju tani keni një kruajtës në internet që funksionon, megjithëse unë tashmë mund të shoh shumë mënyra për ta përmirësuar atë. Për shembull, mund të integrohet me Twilio në mënyrë që të dërgojë mesazhe me tekst në vend të emaileve. Ju mund të përdorni një VPN ose diçka tjetër për të marrë njëkohësisht rezultate nga disa serverë. Ekziston gjithashtu një problem që lind në mënyrë periodike me kontrollimin e përdoruesit të faqes për të parë nëse ai është një person, por edhe ky problem mund të zgjidhet. Në çdo rast, tani ju keni një bazë që mund ta zgjeroni nëse dëshironi. Për shembull, sigurohuni që një skedar Excel t'i dërgohet përdoruesit si një bashkëngjitje në një email.

Python - një asistent në gjetjen e biletave ajrore të lira për ata që duan të udhëtojnë

Vetëm përdoruesit e regjistruar mund të marrin pjesë në anketë. Hyni, te lutem

A përdorni teknologjitë e skrapimit të uebit?

  • Po

  • Jo

8 përdorues kanë votuar. 1 përdorues abstenoi.

Burimi: www.habr.com

Shto një koment