Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі

Бүгінгі аудармасы біз жариялап отырған мақаланың авторы оның мақсаты авиабилеттер бағасын іздейтін Selenium көмегімен Python-да веб-скреперді жасау туралы айту екенін айтады. Билеттерді іздеу кезінде икемді күндер қолданылады (көрсетілген күндерге қатысты +- 3 күн). Скрепер іздеу нәтижелерін Excel файлында сақтайды және іздеуді орындаған адамға олар тапқан нәрселердің қысқаша мазмұны бар электрондық поштаны жібереді. Бұл жобаның мақсаты - саяхатшыларға ең жақсы мәмілелерді табуға көмектесу.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі

Егер материалды түсініп жатқанда, өзіңізді жоғалтып алғаныңызды сезсеңіз, қараңыз бұл мақала.

Біз не іздейміз?

Мұнда сипатталған жүйені өз қалауыңыз бойынша пайдалана аласыз. Мысалы, мен оны демалыс күндеріндегі турлар мен туған жеріме билеттер іздеу үшін пайдаландым. Егер сіз тиімді билеттерді табуға тырыссаңыз, сценарийді серверде іске қосуға болады (қарапайым сервер, айына 130 рубль, бұл үшін өте қолайлы) және күніне бір немесе екі рет жұмыс істейтініне көз жеткізіңіз. Іздеу нәтижелері сізге электрондық пошта арқылы жіберіледі. Бұған қоса, сценарий іздеу нәтижелері бар Excel файлын Dropbox қалтасында сақтайтындай етіп орнатуды ұсынамын, бұл мұндай файлдарды кез келген жерден және кез келген уақытта көруге мүмкіндік береді.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Мен әлі қателері бар тарифтерді таппадым, бірақ бұл мүмкін деп ойлаймын

Іздеу кезінде, жоғарыда айтылғандай, «икемді күн» пайдаланылады, сценарий берілген күннен кейін үш күн ішінде болатын ұсыныстарды табады. Сценарийді іске қосқан кезде ол ұсыныстарды тек бір бағытта іздесе де, оны бірнеше ұшу бағыттары бойынша деректерді жинай алатындай өзгерту оңай. Оның көмегімен сіз тіпті қате тарифтерді іздей аласыз, мұндай табулар өте қызықты болуы мүмкін.

Неліктен сізге басқа веб-скрепер керек?

Мен алғаш рет веб-скрепингті бастаған кезде, шынымды айтсам, мен оған онша қызықпадым. Мен болжамды модельдеу, қаржылық талдау саласында және, мүмкін, мәтіндердің эмоционалды бояуын талдау саласында көбірек жобалар жасағым келді. Бірақ веб-сайттардан деректерді жинайтын бағдарламаны қалай жасау керектігін анықтау өте қызықты болып шықты. Мен осы тақырыпты зерттей келе, веб-скрепинг Интернеттің «қозғалтқышы» екенін түсіндім.

Сіз бұл тым батыл мәлімдеме деп ойлауыңыз мүмкін. Бірақ Google Ларри Пейдж Java және Python көмегімен жасалған веб-скреперден бастағанын ескеріңіз. Google роботтары Интернетті зерттеп, пайдаланушыларға олардың сұрақтарына жақсы жауап беруге тырысады. Веб-скрепингтің шексіз пайдалану мүмкіндігі бар, тіпті егер сіз Data Science бағдарламасында басқа нәрсеге қызығушылық танытсаңыз да, талдауға қажет деректерді алу үшін сізге кейбір қырғыш дағдылары қажет болады.

Мен мұнда қолданылатын әдістердің кейбірін тамаша таптым кітап Мен жақында алған веб-скрепинг туралы. Онда үйренгендеріңізді іс жүзінде қолдануға арналған көптеген қарапайым мысалдар мен идеялар бар. Бұған қоса, reCaptcha тексерулерін айналып өту туралы өте қызықты тарау бар. Бұл мен үшін жаңалық болды, өйткені мен мұндай мәселелерді шешуге арналған арнайы құралдар мен тіпті бүкіл қызметтер бар екенін білмедім.

Саяхаттауды ұнатасыз ба?!

Осы бөлімнің атауында қойылған қарапайым және өте зиянсыз сұраққа сіз сұралған адамның саяхаттарынан бірнеше оқиғамен бірге оң жауап естисіз. Саяхаттау – жаңа мәдени орталарға енудің және ой-өрісіңізді кеңейтудің тамаша тәсілі екендігімен көпшілігіміз келісеміз. Дегенмен, егер сіз біреуден әуе билеттерін іздеуді ұната ма деп сұрасаңыз, жауап онша жақсы болмайтынына сенімдімін. Шындығында, Python бізге көмекке келеді.

Әуе билеттері туралы ақпаратты іздеу жүйесін құру жолында шешуіміз керек бірінші міндет - біз ақпарат алатын қолайлы платформаны таңдау. Бұл мәселені шешу мен үшін оңай болған жоқ, бірақ соңында мен байдарка қызметін таңдадым. Мен Momondo, Skyscanner, Expedia және тағы басқалардың қызметтерін қолданып көрдім, бірақ бұл ресурстардағы роботтарды қорғау механизмдері өтпейтін болды. Бағдаршамдармен, жаяу жүргіншілер өткелдерімен және велосипедтермен күресуге тура келген бірнеше әрекеттен кейін жүйелерді адам екенімді дәлелдеуге тырыстым, мен тым көп беттер жүктелсе де, мен үшін қайық ең қолайлы деп шештім. қысқа мерзімде және тексерулер де басталады. Мен ботқа 4-6 сағат аралықпен сайтқа сұрау жіберуге мүмкіндік бердім және бәрі жақсы жұмыс істеді. Кейде Kayak-пен жұмыс істеу кезінде қиындықтар туындайды, бірақ олар сізді чектермен қорлай бастаса, сіз олармен қолмен жұмыс істеп, содан кейін ботты іске қосуыңыз керек немесе бірнеше сағат күтуіңіз керек және тексерулер тоқтауы керек. Қажет болса, кодты басқа платформаға оңай бейімдеуге болады, ал егер солай жасасаңыз, бұл туралы түсініктемелерде хабарлауға болады.

Егер сіз веб-скрепингті жаңадан бастап жатсаңыз және кейбір веб-сайттар неге онымен күресіп жатқанын білмесеңіз, осы саладағы бірінші жобаңызды бастамас бұрын, өзіңізге жақсылық жасаңыз және Google-да «веб-скрепинг этикеті» деген сөздерді іздеңіз. . Тәжірибелер сіз ойлағаннан тезірек аяқталуы мүмкін, егер сіз веб-сайтты ұқыпсыз жасасаңыз.

Жұмысты бастау

Міне, біздің веб-скрепер кодымызда не болатыны туралы жалпы шолу:

  • Қажетті кітапханаларды импорттаңыз.
  • Google Chrome қойындысын ашу.
  • Ботты іске қосатын функцияны шақырыңыз, оған билеттерді іздеу кезінде пайдаланылатын қалалар мен күндерді жіберіңіз.
  • Бұл функция ең жақсылары бойынша сұрыпталған бірінші іздеу нәтижелерін алады және көбірек нәтижелерді жүктеу үшін түймені басады.
  • Басқа функция бүкіл беттен деректерді жинайды және деректер кадрын қайтарады.
  • Алдыңғы екі қадам билет бағасы (арзан) және ұшу жылдамдығы (ең жылдам) бойынша сұрыптау түрлері арқылы орындалады.
  • Сценарийдің пайдаланушысына билет бағасының қысқаша мазмұны (ең арзан билеттер және орташа баға) бар электрондық хат жіберіледі және жоғарыда аталған үш көрсеткіш бойынша сұрыпталған ақпараты бар деректер кадры Excel файлы ретінде сақталады.
  • Жоғарыда аталған барлық әрекеттер белгілі бір уақыт кезеңінен кейін циклде орындалады.

Айта кету керек, әрбір Selenium жобасы веб-драйверден басталады. Мен қолданамын Chromedriver, Мен Google Chrome-мен жұмыс істеймін, бірақ басқа опциялар бар. PhantomJS және Firefox-та танымал. Драйверді жүктеп алғаннан кейін оны тиісті қалтаға орналастыру керек, бұл оны пайдалануға дайындықты аяқтайды. Біздің сценарийдің бірінші жолдары жаңа Chrome қойындысын ашады.

Есіңізде болсын, мен өзімнің әңгімемде әуе билеттері бойынша керемет ұсыныстар табудың жаңа көкжиектерін ашуға тырыспаймын. Мұндай ұсыныстарды іздеудің әлдеқайда жетілдірілген әдістері бар. Мен осы материалдың оқырмандарына бұл мәселені шешудің қарапайым, бірақ практикалық әдісін ұсынғым келеді.

Міне, біз жоғарыда айтқан код.

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)

Кодтың басында сіз бүкіл жобамызда қолданылатын пакетті импорттау пәрмендерін көре аласыз. Сонымен, randint жаңа іздеу әрекетін бастамас бұрын ботты кездейсоқ секундтар санына «ұйықтауы» үшін пайдаланылады. Әдетте, бірде-бір бот онсыз жасай алмайды. Жоғарыдағы кодты іске қоссаңыз, бот сайттармен жұмыс істеу үшін пайдаланатын Chrome терезесі ашылады.

Кішкене тәжірибе жасап, kayak.com веб-сайтын бөлек терезеде ашайық. Біз ұшатын қаланы, барғымыз келетін қаланы, сондай-ақ ұшу күндерін таңдаймыз. Күндерді таңдаған кезде +-3 күн диапазоны пайдаланылғанына көз жеткізіңіз. Мен кодты сайттың осындай сұраныстарға жауап беретінін ескере отырып жаздым. Егер, мысалы, билеттерді тек көрсетілген күндерге іздеу керек болса, онда бот кодын өзгертуге тура келу ықтималдығы жоғары. Мен код туралы сөйлескенде, мен тиісті түсініктемелер беремін, бірақ егер сіз шатастырсаңыз, маған хабарлаңыз.

Енді іздеу түймесін басып, мекенжай жолағындағы сілтемені қараңыз. Ол төмендегі мысалда айнымалы жарияланған сілтемеге ұқсас болуы керек kayakURL мекенжайын сақтайтын , және әдіс пайдаланылады get веб-драйвер. Іздеу түймесін басқаннан кейін нәтижелер бетте пайда болуы керек.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Мен команданы қолданған кезде get бірнеше минут ішінде екі немесе үш реттен артық, маған reCaptcha арқылы тексеруді аяқтау сұралды. Сіз бұл тексеруді қолмен өткізіп, жүйе жаңа тексеруді іске қосу туралы шешім қабылдағанша тәжірибені жалғастыра аласыз. Мен сценарийді сынаған кезде, бірінші іздеу сеансы әрқашан біркелкі өткен сияқты көрінді, сондықтан кодпен тәжірибе жасағыңыз келсе, іздеу сеанстары арасындағы ұзақ аралықтарды пайдаланып, кодты мезгіл-мезгіл қолмен тексеріп, іске қосуға рұқсат беру керек еді. Ал егер ойлап қарасаңыз, іздеу жұмыстары арасында 10 минуттық интервалда алынған билет бағасы туралы ақпарат адамға қажет болуы екіталай.

XPath арқылы бетпен жұмыс істеу

Сонымен, біз терезені ашып, сайтты жүктедік. Баға және басқа ақпаратты алу үшін XPath технологиясын немесе CSS селекторларын пайдалануымыз керек. Мен XPath-пен жұмыс істеуді шештім және CSS селекторларын пайдалану қажеттілігін сезбедім, бірақ осылай жұмыс істеуге әбден болады. XPath арқылы бетті шарлау қиын болуы мүмкін, тіпті мен сипаттаған әдістерді пайдалансаңыз да бұл бет кодынан сәйкес идентификаторларды көшіруді қамтитын мақалада мен бұл шын мәнінде қажетті элементтерге қол жеткізудің оңтайлы жолы емес екенін түсіндім. Айтпақшы, в бұл Кітапта XPath және CSS селекторлары арқылы беттермен жұмыс істеу негіздерінің тамаша сипаттамасы берілген. Сәйкес веб-драйвер әдісі осылай көрінеді.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Сонымен, ботпен жұмысты жалғастырайық. Ең арзан билеттерді таңдау үшін бағдарламаның мүмкіндіктерін қолданайық. Келесі суретте XPath селектор коды қызыл түспен бөлектелген. Кодты көру үшін сізді қызықтыратын бет элементін тінтуірдің оң жақ түймешігімен басып, пайда болған мәзірден Тексеру пәрменін таңдау керек. Бұл пәрменді әртүрлі бет элементтері үшін шақыруға болады, олардың коды код қарау құралында көрсетіледі және бөлектеледі.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Бет кодын қарау

Кодтан селекторларды көшірудің кемшіліктері туралы менің пікірімді растау үшін келесі мүмкіндіктерге назар аударыңыз.

Кодты көшіргенде мынаны аласыз:

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

Осындай нәрсені көшіру үшін сізді қызықтыратын код бөлімін тінтуірдің оң жақ түймешігімен басып, пайда болған мәзірден Көшіру > XPath көшіру пәрменін таңдау керек.

Міне, мен ең арзан түймені анықтау үшін пайдаландым:

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

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Көшіру пәрмені > XPath көшіру

Екінші нұсқа әлдеқайда қарапайым көрінетіні анық. Пайдаланылған кезде ол төлсипатқа ие a элементін іздейді data-code, тең price. Бірінші опцияны пайдаланған кезде элемент ізделеді id оған тең wtKI-price_aTab, және элементке XPath жолы ұқсайды /div[1]/div/div/div[1]/div/span/span. Бетке осындай XPath сұрауы трюк жасайды, бірақ тек бір рет. Мен дәл қазір айта аламын id бет келесі рет жүктелгенде өзгереді. Таңбалар тізбегі wtKI бет жүктелген сайын динамикалық түрде өзгереді, сондықтан оны пайдаланатын код келесі бетті қайта жүктегеннен кейін пайдасыз болады. Сондықтан XPath-ты түсіну үшін біраз уақыт қажет. Бұл білім сізге жақсы қызмет етеді.

Дегенмен, XPath селекторларын көшіру өте қарапайым сайттармен жұмыс істегенде пайдалы болуы мүмкін екенін атап өткен жөн және егер сіз мұны ыңғайлы болсаңыз, онда ештеңе жоқ.

Енді барлық іздеу нәтижелерін тізім ішінде бірнеше жолда алу қажет болса, не істеу керектігін ойластырайық. Өте оңай. Әрбір нәтиже класы бар нысанның ішінде болады resultWrapper. Барлық нәтижелерді жүктеу төменде көрсетілгенге ұқсас циклде орындалуы мүмкін.

Айта кету керек, егер сіз жоғарыда айтылғандарды түсінсеңіз, біз талдайтын кодтың көпшілігін оңай түсінуіңіз керек. Бұл код іске қосылғанда, жолды анықтау механизмінің (XPath) қандай да бір түрін пайдаланып, бізге қажет нәрсеге (шын мәнінде нәтиже оралған элементке) қол жеткіземіз. Бұл элемент мәтінін алу және оны деректерді оқуға болатын нысанға орналастыру үшін жасалады (алғашқы пайдаланылған flight_containers, содан кейін - flights_list).

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Алғашқы үш жол көрсетіледі және біз қажет нәрсенің бәрін анық көре аламыз. Дегенмен, бізде ақпарат алудың қызықты әдістері бар. Біз әрбір элементтен деректерді бөлек алуымыз керек.

Жұмысқа кіріс!

Функцияны жазудың ең оңай жолы - қосымша нәтижелерді жүктеу, сондықтан біз осы жерден бастаймыз. Мен тексеруге әкелетін қызметке күдік туғызбай, бағдарлама ақпарат алатын рейстер санын барынша арттырғым келеді, сондықтан бет көрсетілген сайын «Қосымша нәтижелерді жүктеу» түймесін бір рет басамын. Бұл кодта сіз блокқа назар аударуыңыз керек try, мен оны қостым, себебі кейде түйме дұрыс жүктелмейді. Егер сіз де осыған тап болсаңыз, функция кодында осы функцияға шақыруларға түсініктеме беріңіз start_kayak, біз төменде қарастырамыз.

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

Енді осы функцияны ұзақ талдағаннан кейін (кейде мен өзімді аластатып аламын), біз бетті сызып тастайтын функцияны жариялауға дайынбыз.

Мен келесі функцияда қажет нәрселердің көпшілігін жинадым page_scrape. Кейде қайтарылған жол деректері біріктіріледі, сондықтан оны бөлу үшін қарапайым әдісті қолданамын. Мысалы, айнымалы мәндерді бірінші рет пайдаланған кезде section_a_list и section_b_list. Біздің функция деректер кадрын қайтарады flights_df, бұл әртүрлі деректерді сұрыптау әдістерінен алынған нәтижелерді бөліп алуға және кейінірек оларды біріктіруге мүмкіндік береді.

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

Код түсінікті болуы үшін айнымалыларды атауға тырыстым. дегеннен басталатын айнымалы мәндерді есте сақтаңыз a жолдың бірінші сатысына жатады, және b - екіншісіне. Келесі функцияға көшейік.

Қолдау механизмдері

Енді бізде қосымша іздеу нәтижелерін жүктеуге мүмкіндік беретін функция және сол нәтижелерді өңдеу функциясы бар. Бұл мақала осы жерде аяқталуы мүмкін еді, өйткені бұл екі функция өзіңіз аша алатын беттерді қырып алу үшін қажет нәрсенің бәрін береді. Бірақ біз жоғарыда қарастырылған кейбір көмекші механизмдерді әлі қарастырған жоқпыз. Мысалы, бұл электрондық поштаны және басқа да нәрселерді жіберуге арналған код. Мұның барлығын функциядан табуға болады start_kayak, біз қазір қарастырамыз.

Бұл функция жұмыс істеуі үшін сізге қалалар мен күндер туралы ақпарат қажет. Осы ақпаратты пайдалана отырып, ол айнымалыда сілтеме жасайды kayak, ол сізді сұрауға ең жақсы сәйкестігі бойынша сұрыпталған іздеу нәтижелерін қамтитын бетке апару үшін пайдаланылады. Бірінші қырғыш сессиясынан кейін біз беттің жоғарғы жағындағы кестедегі бағалармен жұмыс істейміз. Атап айтқанда, біз билеттің ең төменгі бағасы мен орташа бағаны табамыз. Мұның бәрі сайт шығарған болжаммен бірге электрондық пошта арқылы жіберіледі. Беттің жоғарғы сол жақ бұрышында сәйкес кесте болуы керек. Бұл кестемен жұмыс істеу, айтпақшы, нақты күндерді пайдаланып іздеу кезінде қате тудыруы мүмкін, өйткені бұл жағдайда кесте бетте көрсетілмейді.

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

Мен бұл сценарийді Outlook тіркелгісі (hotmail.com) арқылы тексердім. Мен оны Gmail тіркелгісімен дұрыс жұмыс істеу үшін сынамадым, бұл электрондық пошта жүйесі өте танымал, бірақ көптеген мүмкін нұсқалар бар. Егер сіз Hotmail тіркелгісін пайдалансаңыз, барлығы жұмыс істеуі үшін кодқа деректеріңізді енгізу жеткілікті.

Осы функция үшін кодтың нақты бөлімдерінде нақты не істеп жатқанын түсінгіңіз келсе, оларды көшіріп, тәжірибе жасай аласыз. Кодпен тәжірибе жасау - оны шынымен түсінудің жалғыз жолы.

Дайын жүйе

Енді біз айтқандардың барлығын орындадық, біз өз функцияларымызды шақыратын қарапайым цикл жасай аламыз. Сценарий пайдаланушыдан қалалар мен күндер туралы деректерді сұрайды. Сценарийді үнемі қайта іске қосу арқылы тестілеу кезінде сіз бұл деректерді әр уақытта қолмен енгізгіңіз келуі екіталай, сондықтан тестілеу уақытындағы сәйкес жолдарға олардың астындағыларға түсініктеме беру арқылы түсініктеме беруге болады. сценарий қатты кодталған.

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

Сценарийдің сынақ нұсқасы осылай көрінеді.
Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі
Сценарийді сынақтан өткізу

Нәтижелері

Осы уақытқа дейін жеткен болсаңыз, құттықтаймыз! Сізде қазір жұмыс істейтін веб қырғыш бар, бірақ мен оны жақсартудың көптеген жолдарын көріп тұрмын. Мысалы, оны Twilio бағдарламасымен біріктіруге болады, осылайша ол электрондық поштаның орнына мәтіндік хабарламалар жібереді. Бірнеше серверлерден нәтижелерді бір уақытта алу үшін VPN немесе басқа нәрсені пайдалануға болады. Сондай-ақ сайт пайдаланушысын оның адам екенін тексеру кезінде мезгіл-мезгіл туындайтын мәселе бар, бірақ бұл мәселені де шешуге болады. Қалай болғанда да, қазір сізде қаласаңыз, кеңейтуге болатын база бар. Мысалы, Excel файлы пайдаланушыға электрондық поштаға тіркеме ретінде жіберілгенін тексеріңіз.

Python - саяхаттауды ұнататындар үшін арзан әуе билеттерін табудың көмекшісі

Сауалнамаға тек тіркелген пайдаланушылар қатыса алады. Кіру, өтінемін.

Сіз веб-скрепинг технологияларын қолданасыз ба?

  • сол

  • жоқ

8 қолданушы дауыс берді. 1 пайдаланушы қалыс қалды.

Ақпарат көзі: www.habr.com

пікір қалдыру