Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi

Tərcüməsini bu gün dərc etdiyimiz məqalənin müəllifi deyir ki, məqsədi aviabilet qiymətlərini axtaran Selenium-dan istifadə edərək Python-da veb skreperin hazırlanmasından danışmaqdır. Biletlərin axtarışı zamanı çevik tarixlərdən istifadə olunur (göstərilən tarixlərə nisbətən +- 3 gün). Scraper axtarış nəticələrini Excel faylında saxlayır və axtarışı aparan şəxsə tapdıqlarının xülasəsi ilə e-poçt göndərir. Bu layihənin məqsədi səyahətçilərə ən yaxşı təklifləri tapmaqda kömək etməkdir.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi

Əgər materialı başa düşərkən özünüzü itmiş hiss edirsinizsə, ona nəzər salın bu məqalə.

Nə axtaracağıq?

Burada təsvir olunan sistemdən istədiyiniz kimi istifadə etməkdə sərbəstsiniz. Məsələn, mən ondan həftə sonu turları və doğma şəhərimə biletlər axtarmaq üçün istifadə etdim. Qazanclı biletlər tapmaqda ciddisinizsə, skripti serverdə işlədə bilərsiniz (sadə server, ayda 130 rubl üçün, bunun üçün olduqca uyğundur) və gündə bir və ya iki dəfə işlədiyinə əmin olun. Axtarış nəticələri sizə e-poçt vasitəsilə göndəriləcək. Bundan əlavə, mən hər şeyi elə qurmağı məsləhət görürəm ki, skript axtarış nəticələri ilə Excel faylını Dropbox qovluğunda saxlasın ki, bu da sizə bu cür fayllara istənilən yerdən və istənilən vaxt baxmaq imkanı verəcək.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Hələ səhvləri olan tarifləri tapmamışam, amma məncə, mümkündür

Axtarış zamanı, artıq qeyd edildiyi kimi, "çevik tarix" istifadə olunur; skript verilən tarixdən üç gün ərzində olan təklifləri tapır. Skripti işləyərkən o, yalnız bir istiqamətdə təkliflər axtarsa ​​da, bir neçə uçuş istiqaməti üzrə məlumat toplaya bilməsi üçün onu dəyişdirmək asandır. Onun köməyi ilə hətta səhv tarifləri də axtara bilərsiniz, bu cür tapıntılar çox maraqlı ola bilər.

Niyə başqa bir veb kazıyıcıya ehtiyacınız var?

Mən ilk dəfə veb kazımağa başlayanda, düzünü desəm, o qədər də maraqlı deyildim. Mən proqnozlaşdırıcı modelləşdirmə, maliyyə təhlili sahəsində və ola bilsin ki, mətnlərin emosional rənglənməsinin təhlili sahəsində daha çox layihələr həyata keçirmək istəyirdim. Amma məlum oldu ki, vebsaytlardan məlumat toplayan proqramın necə yaradılacağını anlamaq çox maraqlıdır. Bu mövzunu araşdırarkən anladım ki, veb kazıma İnternetin “mühərriki”dir.

Bunun çox cəsarətli bir ifadə olduğunu düşünə bilərsiniz. Ancaq nəzərə alın ki, Google Larry Page Java və Python istifadə edərək yaratdığı veb kazıyıcı ilə başladı. Google robotları interneti araşdıraraq istifadəçilərinin suallarına ən yaxşı cavabları təqdim etməyə çalışırlar. Veb kazıma sonsuz istifadələrə malikdir və Data Science-da başqa bir şeylə maraqlansanız belə, təhlil etmək üçün lazım olan məlumatları əldə etmək üçün bəzi kazıma bacarıqlarına ehtiyacınız olacaq.

Burada istifadə edilən bəzi texnikaları gözəl tapdım kitab bu yaxınlarda əldə etdiyim veb kazıma haqqında. Burada öyrəndiklərinizin praktiki tətbiqi üçün çoxlu sadə nümunələr və ideyalar var. Bundan əlavə, reCaptcha yoxlamalarından yan keçmək haqqında çox maraqlı bir fəsil var. Bu, mənə xəbər kimi gəldi, çünki belə problemlərin həlli üçün xüsusi vasitələrin və hətta bütün xidmətlərin olduğunu bilmirdim.

Sən Səyahət etməyi xoşlayirsan?!

Bu bölmənin başlığında verilən sadə və olduqca zərərsiz bir suala, soruşulduğu şəxsin səyahətlərindən bir neçə hekayə ilə müşayiət olunan müsbət cavabı tez-tez eşidə bilərsiniz. Çoxumuz razılaşarıq ki, səyahət özünüzü yeni mədəni mühitlərə qərq etmək və üfüqlərinizi genişləndirmək üçün əla bir yoldur. Bununla belə, kimdənsə aviabilet axtarmağı xoşlayırmı deyə soruşsanız, əminəm ki, cavab o qədər də müsbət olmayacaq. Əslində burada Python köməyimizə gəlir.

Aviabiletlər haqqında məlumat axtarışı sisteminin yaradılması yolunda həll etməli olduğumuz ilk vəzifə məlumat alacağımız uyğun platformanın seçilməsi olacaq. Bu problemi həll etmək mənim üçün asan olmadı, amma sonda Kayak xidmətini seçdim. Mən Momondo, Skyscanner, Expedia və bir neçə başqa şirkətlərin xidmətlərini sınadım, lakin bu resurslarda robotların qorunması mexanizmləri keçilməz idi. Svetoforlar, piyada keçidləri və velosipedlərlə qarşılaşmalı olduğum, sistemləri insan olduğuma inandırmağa çalışdığım bir neçə cəhddən sonra Həddindən artıq səhifə yüklənməsinə baxmayaraq Kayakın mənim üçün ən uyğun olduğuna qərar verdim. Qısa müddətdə və yoxlamalar da başlayır. Mən botun sayta 4-6 saat aralıqlarla sorğu göndərməsinə nail oldum və hər şey qaydasında idi. Kayak ilə işləyərkən vaxtaşırı çətinliklər yaranır, lakin onlar sizi çeklərlə bezdirməyə başlayarsa, ya onlarla əl ilə məşğul olmalı, sonra botu işə salmalı və ya bir neçə saat gözləməlisiniz və yoxlamalar dayanmalıdır. Lazım gələrsə, kodu asanlıqla başqa platformaya uyğunlaşdıra bilərsiniz və bunu etsəniz, şərhlərdə bildirə bilərsiniz.

Əgər veb kazıma ilə yeni başlayırsınızsa və bəzi veb saytların niyə bununla mübarizə apardığını bilmirsinizsə, bu sahədə ilk layihənizə başlamazdan əvvəl özünüzə bir yaxşılıq edin və "veb kazıma etiketi" sözləri ilə Google-da axtarış edin. . Ağılsızlıqla veb qırıntıları etsəniz, təcrübələriniz düşündüyünüzdən daha tez bitə bilər.

Başlarken

Veb kazıyıcı kodumuzda nələrin baş verəcəyinə dair ümumi bir xülasə:

  • Lazımi kitabxanaları idxal edin.
  • Google Chrome tabının açılması.
  • Bilet axtararkən istifadə olunacaq şəhərləri və tarixləri ona ötürərək botu işə salan funksiyaya zəng edin.
  • Bu funksiya ən yaxşısına görə çeşidlənmiş ilk axtarış nəticələrini götürür və daha çox nəticə yükləmək üçün düyməni klikləyir.
  • Başqa bir funksiya bütün səhifədən məlumatları toplayır və məlumat çərçivəsini qaytarır.
  • Əvvəlki iki addım bilet qiymətinə (ucuz) və uçuş sürətinə (ən sürətli) görə çeşidləmə növlərindən istifadə etməklə həyata keçirilir.
  • Skript istifadəçisinə bilet qiymətlərinin xülasəsi (ən ucuz biletlər və orta qiymət) olan elektron məktub göndərilir və yuxarıda qeyd olunan üç göstərici üzrə çeşidlənmiş məlumat çərçivəsi Excel faylı kimi saxlanılır.
  • Yuxarıda göstərilən bütün hərəkətlər müəyyən bir müddətdən sonra bir dövrədə həyata keçirilir.

Qeyd etmək lazımdır ki, hər bir Selenium layihəsi veb-driverlə başlayır. Mən istifadə edirəm Chromedriver, Google Chrome ilə işləyirəm, amma başqa variantlar da var. PhantomJS və Firefox da məşhurdur. Sürücüyü yüklədikdən sonra onu müvafiq qovluğa yerləşdirmək lazımdır və bu, onun istifadəsinə hazırlığı tamamlayır. Skriptimizin ilk sətirləri yeni Chrome nişanını açır.

Nəzərə alın ki, hekayəmdə aviabiletlərdə böyük təkliflər tapmaq üçün yeni üfüqlər açmağa çalışmıram. Bu cür təklifləri axtarmaq üçün daha təkmil üsullar var. Mən sadəcə olaraq bu materialın oxucularına bu problemi həll etmək üçün sadə, lakin praktiki üsul təklif etmək istəyirəm.

Yuxarıda bəhs etdiyimiz kod budur.

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)

Kodun əvvəlində siz bütün layihəmizdə istifadə olunan paket idxal əmrlərini görə bilərsiniz. Belə ki, randint yeni axtarış əməliyyatına başlamazdan əvvəl botun təsadüfi bir neçə saniyə ərzində “yuxuya getməsi” üçün istifadə olunur. Adətən, heç bir bot bunsuz edə bilməz. Yuxarıdakı kodu işlətsəniz, botun saytlarla işləmək üçün istifadə edəcəyi Chrome pəncərəsi açılacaq.

Gəlin kiçik bir təcrübə edək və kayak.com saytını ayrıca pəncərədə açaq. Uçuş edəcəyimiz şəhəri və getmək istədiyimiz şəhəri, həmçinin uçuş tarixlərini seçəcəyik. Tarixləri seçərkən +-3 gün aralığından istifadə olunduğundan əmin olun. Bu cür müraciətlərə cavab olaraq saytın nə istehsal etdiyini nəzərə alaraq kodu yazdım. Məsələn, yalnız müəyyən tarixlər üçün biletlər axtarmaq lazımdırsa, o zaman bot kodunu dəyişdirməli olma ehtimalınız yüksəkdir. Kod haqqında danışanda mən müvafiq izahatlar verirəm, amma çaşqınlıq hiss edirsinizsə, mənə bildirin.

İndi axtarış düyməsini basın və ünvan çubuğundakı linkə baxın. Aşağıdakı misalda dəyişənin elan olunduğu linkə oxşar olmalıdır kayakURL-i saxlayan , və metoddan istifadə olunur get veb sürücü. Axtarış düyməsini kliklədikdən sonra nəticələr səhifədə görünməlidir.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Mən əmrdən istifadə edərkən get bir neçə dəqiqə ərzində iki və ya üç dəfədən çox, məndən reCaptcha istifadə edərək yoxlamanı tamamlamam istəndi. Siz bu yoxlanışı əl ilə keçə və sistem yeni yoxlama aparmağa qərar verənə qədər sınaqdan keçirə bilərsiniz. Skripti sınaqdan keçirəndə mənə elə gəlirdi ki, ilk axtarış sessiyası həmişə rəvan gedir, ona görə də kodla təcrübə etmək istəsəniz, axtarış seansları arasında uzun fasilələrdən istifadə edərək, yalnız vaxtaşırı olaraq əl ilə yoxlamalı və kodu işə salmalı olacaqsınız. Fikir versəniz, axtarış əməliyyatları arasında 10 dəqiqəlik fasilələrlə alınan bilet qiymətləri ilə bağlı məlumatın insana ehtiyacı olması ehtimalı azdır.

XPath istifadə edərək səhifə ilə işləmək

Beləliklə, bir pəncərə açdıq və saytı yüklədik. Qiymət və digər məlumatları əldə etmək üçün XPath texnologiyasından və ya CSS seçicilərindən istifadə etməliyik. Mən XPath ilə qalmaq qərarına gəldim və CSS seçicilərindən istifadə etməyə ehtiyac hiss etmədim, lakin bu şəkildə işləmək olduqca mümkündür. XPath istifadə edərək səhifə ətrafında naviqasiya çətin ola bilər və hətta təsvir etdiyim üsullardan istifadə etsəniz belə bu səhifə kodundan müvafiq identifikatorların surətini çıxarmaqdan ibarət olan məqalədə başa düşdüm ki, bu, əslində lazımi elementlərə daxil olmaq üçün optimal yol deyil. Yeri gəlmişkən, in bu Kitab XPath və CSS seçicilərindən istifadə edərək səhifələrlə işləməyin əsaslarının əla təsvirini təqdim edir. Müvafiq veb sürücü metodu belə görünür.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Beləliklə, bot üzərində işləməyə davam edək. Ən ucuz biletləri seçmək üçün proqramın imkanlarından istifadə edək. Aşağıdakı şəkildə, XPath seçici kodu qırmızı rənglə vurğulanır. Kodu görmək üçün sizi maraqlandıran səhifə elementinin üzərinə siçanın sağ düyməsini sıxmaq və görünən menyudan Təftiş əmrini seçmək lazımdır. Bu əmr müxtəlif səhifə elementləri üçün çağırıla bilər, onların kodu kod görüntüləyicisində göstəriləcək və vurğulanacaq.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Səhifə koduna baxın

Koddan seçicilərin surətini çıxarmağın çatışmazlıqları haqqında fikirlərimin təsdiqini tapmaq üçün aşağıdakı xüsusiyyətlərə diqqət yetirin.

Kodu kopyaladığınız zaman əldə etdiyiniz budur:

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

Buna bənzər bir şeyi kopyalamaq üçün maraqlandığınız kod bölməsinə sağ klikləməlisiniz və görünən menyudan Copy > Copy XPath əmrini seçməlisiniz.

Ən ucuz düyməni təyin etmək üçün istifadə etdiyim budur:

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

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Kopyalama əmri > XPath-ı kopyalayın

Tamamilə aydındır ki, ikinci variant daha sadə görünür. İstifadə edildikdə, o, atributuna malik olan elementi axtarır data-codebərabərdir price. Birinci variantdan istifadə edərkən element axtarılır id bərabərdir wtKI-price_aTab, və elementə XPath yolu bənzəyir /div[1]/div/div/div[1]/div/span/span. Səhifəyə bu kimi XPath sorğusu hiylə işlədəcək, ancaq bir dəfə. Mən bunu indi deyə bilərəm id səhifə növbəti dəfə yükləndikdə dəyişəcək. Simvol ardıcıllığı wtKI səhifə hər dəfə yükləndikdə dinamik olaraq dəyişir, ona görə də onu istifadə edən kod növbəti səhifə yenidən yükləndikdən sonra faydasız olacaq. Beləliklə, XPath-ı başa düşmək üçün bir az vaxt ayırın. Bu bilik sizə yaxşı xidmət edəcəkdir.

Bununla belə, qeyd etmək lazımdır ki, XPath selektorlarının surətini çıxarmaq kifayət qədər sadə saytlarla işləyərkən faydalı ola bilər və əgər siz bununla rahatsınızsa, onda heç bir səhv yoxdur.

İndi gəlin bütün axtarış nəticələrini bir neçə sətirdə, siyahı içərisində əldə etmək lazımdırsa, nə edəcəyinizi düşünək. Çox sadə. Hər bir nəticə sinfi olan obyektin içərisindədir resultWrapper. Bütün nəticələrin yüklənməsi aşağıda göstərilənə bənzər bir döngədə edilə bilər.

Qeyd etmək lazımdır ki, yuxarıda göstərilənləri başa düşsəniz, təhlil edəcəyimiz kodların əksəriyyətini asanlıqla başa düşməlisiniz. Bu kod işləyərkən, biz bir növ yolu təyin edən mexanizmdən (XPath) istifadə edərək ehtiyacımız olana (əslində nəticənin bükülü olduğu elementə) daxil oluruq. Bu, elementin mətnini əldə etmək və onu məlumatların oxuna biləcəyi obyektə yerləşdirmək üçün edilir (ilk istifadə flight_containers, sonra - flights_list).

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
İlk üç sətir göstərilir və biz lazım olan hər şeyi aydın görə bilərik. Bununla belə, məlumat əldə etmək üçün daha maraqlı üsullarımız var. Hər bir elementdən ayrı-ayrılıqda məlumat almalıyıq.

İşə get!

Funksiyanı yazmağın ən asan yolu əlavə nəticələri yükləməkdir, ona görə başlayacağıq. Yoxlamaya səbəb olan xidmətdə şübhələr yaratmadan proqramın məlumat aldığı uçuşların sayını maksimuma çatdırmaq istərdim, ona görə də səhifə hər dəfə görünəndə daha çox nəticə yüklə düyməsini sıxıram. Bu kodda bloka diqqət yetirməlisiniz try, bəzən düymə düzgün yüklənmir deyə əlavə etdim. Əgər siz də bununla qarşılaşırsınızsa, funksiya kodunda bu funksiyaya edilən zəngləri şərh edin start_kayak, biz aşağıda baxacağıq.

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

İndi bu funksiyanı uzun müddət təhlil etdikdən sonra (bəzən özümü götürə bilərəm) səhifəni sındıracaq bir funksiya elan etməyə hazırıq.

Mən artıq adlanan aşağıdakı funksiyada lazım olanların çoxunu toplamışam page_scrape. Bəzən geri qaytarılan yol məlumatları birləşdirilir, ona görə də onu ayırmaq üçün sadə üsuldan istifadə edirəm. Məsələn, dəyişənləri ilk dəfə istifadə edərkən section_a_list и section_b_list. Bizim funksiyamız məlumat çərçivəsini qaytarır flights_df, bu, müxtəlif verilənlərin çeşidlənməsi üsullarından əldə edilən nəticələri ayırmağa və sonra onları birləşdirməyə imkan verir.

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

Kodun başa düşülməsi üçün dəyişənləri adlandırmağa çalışdım. ilə başlayan dəyişənləri unutmayın a yolun birinci mərhələsinə aiddir və b - ikinciyə. Gəlin növbəti funksiyaya keçək.

Dəstək mexanizmləri

İndi bizdə əlavə axtarış nəticələrini yükləməyə imkan verən funksiya və həmin nəticələri emal etmək funksiyası var. Bu məqalə burada bitə bilərdi, çünki bu iki funksiya özünüz aça biləcəyiniz səhifələri qırmaq üçün lazım olan hər şeyi təmin edir. Ancaq yuxarıda müzakirə edilən bəzi köməkçi mexanizmləri hələ nəzərdən keçirməmişik. Məsələn, bu, e-poçt və bəzi başqa şeylər göndərmək üçün koddur. Bütün bunları funksiyada tapmaq olar start_kayak, indi nəzərdən keçirəcəyik.

Bu funksiya şəhərlər və tarixlər haqqında məlumat tələb edir. Bu məlumatdan istifadə edərək, dəyişəndə ​​bir keçid təşkil edir kayak, sizi sorğuya ən yaxşı uyğunluğu üzrə çeşidlənmiş axtarış nəticələrini ehtiva edən səhifəyə aparmaq üçün istifadə olunur. İlk kazıma seansından sonra səhifənin yuxarısındakı cədvəldəki qiymətlərlə işləyəcəyik. Yəni minimum bilet qiymətini və orta qiyməti tapacağıq. Bütün bunlar saytın verdiyi proqnozla birlikdə elektron poçtla göndəriləcək. Səhifədə müvafiq cədvəl yuxarı sol küncdə olmalıdır. Bu cədvəllə işləmək, yeri gəlmişkən, dəqiq tarixlərdən istifadə edərək axtarış zamanı xətaya səbəb ola bilər, çünki bu halda cədvəl səhifədə göstərilmir.

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

Mən bu skripti Outlook hesabından (hotmail.com) istifadə edərək sınaqdan keçirdim. Mən onu Gmail hesabı ilə düzgün işləmək üçün sınaqdan keçirməmişəm, bu e-poçt sistemi kifayət qədər populyardır, lakin bir çox mümkün variant var. Hotmail hesabından istifadə edirsinizsə, onda hər şeyin işləməsi üçün sadəcə məlumatlarınızı koda daxil etməlisiniz.

Bu funksiya üçün kodun xüsusi bölmələrində tam olaraq nə edildiyini başa düşmək istəyirsinizsə, onları kopyalaya və onlarla təcrübə edə bilərsiniz. Kodla təcrübə etmək onu həqiqətən dərk etməyin yeganə yoludur.

Hazır sistem

İndi danışdığımız hər şeyi etdikdən sonra funksiyalarımızı çağıran sadə bir dövrə yarada bilərik. Skript istifadəçidən şəhərlər və tarixlər haqqında məlumat tələb edir. Skriptin daimi yenidən başlaması ilə sınaqdan keçirərkən, bu məlumatları hər dəfə əl ilə daxil etmək istəməyiniz çətin olacaq, buna görə də test müddəti üçün müvafiq sətirlər aşağıda göstərilənləri şərh etməklə şərh edilə bilər, burada verilənlərin tələb etdiyi məlumatlar skript sərt kodlaşdırılıb.

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

Skriptin sınaqdan keçirilməsi belə görünür.
Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi
Skriptin sınaqdan keçirilməsi

Nəticələri

Bu günə qədər gəlib çatmısınızsa, təbrik edirik! İndi işləyən veb kazıyıcınız var, baxmayaraq ki, onu təkmilləşdirməyin bir çox yolunu artıq görə bilirəm. Məsələn, Twilio ilə inteqrasiya oluna bilər ki, o, e-poçt əvəzinə mətn mesajları göndərir. Eyni anda bir neçə serverdən nəticə almaq üçün VPN və ya başqa bir şey istifadə edə bilərsiniz. Sayt istifadəçisinin şəxs olub-olmadığını yoxlamaq üçün vaxtaşırı yaranan problem də var, lakin bu problemi də həll etmək olar. Hər halda, indi siz istəsəniz genişləndirə biləcəyiniz bir bazanız var. Məsələn, Excel faylının e-poçta əlavə olaraq istifadəçiyə göndərildiyinə əmin olun.

Python - səyahət etməyi sevənlər üçün ucuz aviabiletlərin tapılmasında köməkçi

Sorğuda yalnız qeydiyyatdan keçmiş istifadəçilər iştirak edə bilər. Daxil olunxahiş edirəm.

Veb kazıma texnologiyalarından istifadə edirsiniz?

  • Bəli

  • Heç bir

8 istifadəçi səs verib. 1 istifadəçi bitərəf qaldı.

Mənbə: www.habr.com

Добавить комментарий