Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат

Авторот на написот, чиј превод го објавуваме денеска, вели дека неговата цел е да зборува за развој на веб-скрепер во Python со помош на Selenium, кој бара цени за авионски билети. При пребарување на билети, се користат флексибилни датуми (+- 3 дена во однос на наведените датуми). Скреперот ги зачувува резултатите од пребарувањето во датотека Excel и му испраќа е-пошта на лицето кое го извршило пребарувањето со резиме на она што го пронашле. Целта на овој проект е да им помогне на патниците да ги најдат најдобрите зделки.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат

Ако додека го разбирате материјалот се чувствувате изгубено, погледнете ова напис.

Што ќе бараме?

Слободно можете да го користите системот опишан овде како што сакате. На пример, го користев за пребарување викенд тури и билети за мојот роден град. Ако сте сериозни за наоѓање профитабилни билети, можете да ја извршите скриптата на серверот (едноставно сервер, за 130 рубли месечно, е сосема погодно за ова) и погрижете се да работи еднаш или двапати дневно. Резултатите од пребарувањето ќе ви бидат испратени по е-пошта. Дополнително, препорачувам да поставите сè така што скриптата зачувува датотека Excel со резултати од пребарувањето во папката Dropbox, што ќе ви овозможи да ги гледате таквите датотеки од каде било и во секое време.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Сè уште не најдов тарифи со грешки, но мислам дека е можно

При пребарувањето, како што веќе споменавме, се користи „флексибилен датум“; скриптата наоѓа понуди кои се во рок од три дена од дадените датуми. Иако при извршувањето на скриптата, таа бара понуди само во една насока, лесно е да се измени за да може да собира податоци за неколку насоки на летот. Со негова помош, можете дури и да барате погрешни тарифи; таквите наоди може да бидат многу интересни.

Зошто ви е потребен друг веб стругач?

Кога првпат започнав со веб-стружење, искрено не бев особено заинтересиран за тоа. Сакав да направам повеќе проекти од областа на предвидливо моделирање, финансиска анализа, а можеби и во областа на анализа на емоционалното обојување на текстовите. Но, се покажа дека е многу интересно да се открие како да се создаде програма која собира податоци од веб-страниците. Како што навлегував во оваа тема, сфатив дека веб-стружењето е „мотор“ на Интернет.

Можеби мислите дека ова е премногу смела изјава. Но, сметајте дека Google започна со веб-скрапер што Лери Пејџ го создаде со помош на Java и Python. Роботите на Google истражуваат на Интернет, обидувајќи се на своите корисници да им дадат најдобри одговори на нивните прашања. Веб-стружењето има бесконечна употреба, па дури и ако сте заинтересирани за нешто друго во Data Science, ќе ви требаат некои вештини за стружење за да ги добиете податоците што треба да ги анализирате.

Најдов некои од техниките што се користат овде во прекрасен книгата за веб-стружење, што неодамна го купив. Содржи многу едноставни примери и идеи за практична примена на она што сте го научиле. Покрај тоа, постои многу интересно поглавје за заобиколување на проверките на reCaptcha. Ова ми дојде како вест, бидејќи не ни знаев дека има специјални алатки, па дури и цели услуги за решавање на вакви проблеми.

Сакаш ли да патуваш?!

На едноставното и прилично безопасно прашање поставено во насловот на овој дел, често можете да слушнете позитивен одговор, придружен со неколку приказни од патувањата на лицето на кое му е поставено. Повеќето од нас би се согласиле дека патувањето е одличен начин да се нурнете во нови културни средини и да ги проширите своите хоризонти. Меѓутоа, ако прашате некого дали сака да бара авионски билети, сигурен сум дека одговорот нема да биде толку позитивен. Всушност, Python ни доаѓа на помош овде.

Првата задача што треба да ја решиме на патот кон создавање систем за пребарување информации за авио билетите ќе биде избор на соодветна платформа од која ќе земеме информации. Решавањето на овој проблем не ми беше лесно, но на крајот ја избрав услугата кајак. Ги пробав услугите на Momondo, Skyscanner, Expedia и неколку други, но механизмите за заштита на роботите на овие ресурси беа непробојни. По неколку обиди, за време на кои морав да се справам со семафори, пешачки премини и велосипеди, обидувајќи се да ги убедам системите дека сум човек, решив дека Кајакот е најсоодветен за мене, и покрај фактот дека дури и ако се вчитаат премногу страници за кратко време, а почнуваат и проверките. Успеав да го натерам ботот да испраќа барања до страницата во интервали од 4 до 6 часа, и сè функционираше добро. Одвреме-навреме се појавуваат потешкотии кога работите со Кајак, но ако почнат да ве мачат со проверки, тогаш треба или да се справите со нив рачно и потоа да го стартувате ботот или да почекате неколку часа и проверките треба да престанат. Доколку е потребно, можете лесно да го прилагодите кодот за друга платформа, а доколку го направите тоа, можете да го пријавите во коментари.

Ако штотуку започнавте со веб-стружење и не знаете зошто некои веб-локации се борат со тоа, тогаш пред да го започнете вашиот прв проект во оваа област, направете си услуга и направете пребарување на Google за зборовите „бонтон за гребење на веб“. . Вашите експерименти може да завршат порано отколку што мислите ако неразумно правите гребење на веб.

Getting Started

Еве општ преглед на она што ќе се случи во нашиот код за гребење на веб:

  • Увезете ги потребните библиотеки.
  • Отворање таб на 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 дена. Го напишав кодот земајќи го предвид она што го произведува страницата како одговор на таквите барања. Ако, на пример, треба да барате билети само за одредени датуми, тогаш постои голема веројатност дека ќе мора да го измените кодот на ботот. Кога зборувам за кодот, давам соодветни објаснувања, но ако се чувствувате збунети, известете ме.

Сега кликнете на копчето за пребарување и погледнете ја врската во лентата за адреси. Треба да биде слична на врската што ја користам во примерот подолу каде што е декларирана променливата kayak, кој ја зачувува URL-то и се користи методот get веб-двигател. Откако ќе кликнете на копчето за пребарување, резултатите треба да се појават на страницата.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Кога ја користев командата get повеќе од два или три пати во рок од неколку минути, од мене беше побарано да ја завршам верификацијата користејќи reCaptcha. Оваа проверка може да ја поминете рачно и да продолжите да експериментирате додека системот не одлучи да изврши нова проверка. Кога ја тестирав скриптата, се чинеше дека првата сесија за пребарување секогаш се одвиваше непречено, па ако сакате да експериментирате со кодот, ќе треба само периодично рачно да проверувате и да го пуштате кодот да работи, користејќи долги интервали помеѓу сесиите за пребарување. И, ако размислите за тоа, на лицето веројатно нема да му требаат информации за цените на билетите добиени во интервали од 10 минути помеѓу операциите за пребарување.

Работа со страница користејќи XPath

Значи, отворивме прозорец и ја вчитавме страницата. За да добиеме цени и други информации, треба да користиме XPath технологија или CSS селектори. Решив да се задржам на XPath и не почувствував потреба да користам CSS селектори, но сосема е можно да се работи на тој начин. Навигацијата низ страница користејќи XPath може да биде незгодно, па дури и ако ги користите техниките што ги опишав ова статија, која вклучуваше копирање на соодветните идентификатори од кодот на страницата, сфатив дека ова, всушност, не е оптималниот начин за пристап до потребните елементи. Патем, во ова Книгата дава одличен опис на основите за работа со страници користејќи XPath и CSS селектори. Вака изгледа соодветниот метод на веб-двигател.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Значи, да продолжиме да работиме на ботот. Ајде да ги искористиме можностите на програмата за да ги избереме најевтините билети. На следната слика, кодот за избирање XPath е означен со црвено. За да го видите кодот, треба да кликнете со десното копче на елементот на страницата што ве интересира и да ја изберете командата Inspect од менито што се појавува. Оваа команда може да се повика за различни елементи на страницата, чиј код ќе биде прикажан и означен во прегледувачот на кодови.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Погледнете го кодот на страницата

За да најдете потврда за моето размислување за недостатоците на копирањето на избирачите од кодот, обрнете внимание на следните карактеристики.

Ова е она што го добивате кога го копирате кодот:

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

За да копирате нешто како ова, треба да кликнете со десното копче на делот од кодот за кој ве интересира и да ја изберете командата Copy > Copy XPath од менито што се појавува.

Еве што користев за да го дефинирам копчето Најевтино:

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

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Копирање на командата > Копирај 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).

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Првите три линии се прикажани и јасно можеме да видиме се што ни треба. Сепак, имаме поинтересни начини за добивање информации. Треба да земеме податоци од секој елемент посебно.

Фати се на работа!

Најлесен начин да се напише функција е да се вчитаат дополнителни резултати, па оттука ќе започнеме. Би сакал да го максимизирам бројот на летови за кои програмата добива информации, без да предизвикувам сомневања во услугата што води до проверка, па кликнувам на копчето Вчитај повеќе резултати еднаш секој пат кога се прикажува страницата. Во овој код, треба да обрнете внимание на блокот 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.....')

Вака изгледа тестот на сценариото.
Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат
Тестирање на сценариото

Резултатите од

Ако сте стигнале до тука, ви честитаме! Сега имате работен веб стругач, иако веќе можам да видам многу начини за негово подобрување. На пример, може да се интегрира со Twilio за да испраќа текстуални пораки наместо е-пошта. Можете да користите VPN или нешто друго за истовремено да добивате резултати од неколку сервери. Исто така, периодично се појавува проблем со проверка на корисникот на страницата за да се види дали е личност, но и овој проблем може да се реши. Во секој случај, сега имате база која можете да ја проширите доколку сакате. На пример, проверете дали датотеката Excel е испратена до корисникот како прилог на е-пошта.

Пајтон - асистент во наоѓање евтини авионски билети за оние кои сакаат да патуваат

Само регистрирани корисници можат да учествуваат во анкетата. Најави се, вие сте добредојдени.

Дали користите технологии за гребење на веб?

  • Да

  • Не

Гласаа 8 корисници. 1 корисник се воздржа.

Извор: www.habr.com

Додадете коментар