Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa

Författaren till artikeln vi publicerar idag säger att syftet är att berätta om utvecklingen av en webbscraper i Python med hjälp av Selenium, som söker priser på flygbiljetter. Vid sökning av biljetter används flexibla datum (+- 3 dagar i förhållande till angivna datum). Scrapern sparar sökresultaten i en Excel-fil och skickar ett e-postmeddelande till den som körde den med en sammanfattning av vad den lyckades hitta. Målet med detta projekt är att hjälpa resenärer att hitta de mest förmånliga erbjudandena.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa

Om du, när du går igenom materialet, känner att du har tappat bort dig - ta en titt på denna artikel.

Vad ska vi leta efter?

Du är fri att använda det system som beskrivs här på det sätt du önskar. Jag, till exempel, har använt det för att leta efter weekendresor och biljetter till min hemstad. Om du är seriöst inställd på att hitta billiga biljetter - kan du köra skriptet på en server (en enkel server, för 130 rubel i månaden, passar utmärkt för detta) och ställa in så att det körs en eller två gånger om dagen. Sökresultaten kommer att skickas till din e-post. Dessutom rekommenderar jag att ställa in allt så att skriptet sparar en Excel-fil med sökresultat i Dropbox-mappen, vilket gör att du kan se dessa filer var som helst och när som helst.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
Jag har ännu inte hittat några felaktiga priser, men jag tror att det är möjligt.

Vid sökningen, som redan nämnts, används "flexibla datum", skriptet hittar erbjudanden som ligger inom tre dagar från de angivna datumen. Även om skriptet vid körning bara söker erbjudanden för en riktning, är det inte svårt att förbättra det så att det kan samla in data om flera flygrutter. Med det kan man till och med leta efter felaktiga priser, sådana fynd kan visa sig vara mycket intressanta.

Varför behövs ännu en webbscraper?

När jag först började med webbskrapning var jag, ärligt talat, inte särskilt intresserad av det. Jag ville göra fler projekt inom prognosmodulering, finansiell analys, och kanske inom känslomässig analys av texter. Men det visade sig vara väldigt intressant — att ta sig an hur man skapar ett program som samlar in data från webbplatser. Allteftersom jag fördjupade mig i ämnet insåg jag att det är just webbskrapning som är internets "motor".

Kanske anser du att detta är ett för djärvt påstående. Men tänk på att företaget Google började med en webbskrapare som Larry Page skapade med Java och Python. Googles robotar utforskar och utforskar internet i ett försök att ge sina användare de bästa svaren på deras frågor. Webbskrapning har ett oändligt antal tillämpningar, och även om du inom Data Science är intresserad av något annat, kommer du att behöva vissa skrapningskunskaper för att få tag på data för analys.

Några av de tekniker som använts här har jag funnit i en fantastisk bok om webbskrapning som jag nyligen har skaffat. Den innehåller många enkla exempel och idéer för praktisk tillämpning av det som lärts. Dessutom finns det ett mycket intressant kapitel om hur man kringgår reCaptcha-kontroller. För mig var detta en nyhet, eftersom jag inte visste att det finns speciella verktyg och hela tjänster för att lösa sådana problem.

Älskar du att resa?!

På den enkla och ganska harmlösa frågan som löftes i rubriken för detta avsnitt får man ofta ett positivt svar, ofta kompletterat med ett par reseberättelser från den som blivit tillfrågad. De flesta av oss håller med om att resande är ett utmärkt sätt att fördjupa sig i nya kulturella miljöer och vidga ens horisonter. Men om man ställer någon frågan om de tycker om att leta efter flygbiljetter, så är jag säker på att svaret på detta inte kommer att vara lika positivt. Egentligen är det här som Python kommer till vår hjälp.

Det första uppdraget vi måste lösa på vägen mot att skapa ett system för att söka efter flygbiljetter är att hitta en lämplig plattform från vilken vi kan hämta information. Denna uppgift var svår för mig, men i slutändan valde jag tjänsten Kayak. Jag provade tjänster som Momondo, Skyscanner och Expedia, samt några andra, men skyddsmekanismerna på dessa plattformar var oförstörbara. Efter flera försök, där jag försökte övertyga systemen om att jag var en människa, fick jag hantera trafikljus, övergångsställen och cyklar. Jag beslutade att Kayak passade mig bäst, trots att även här, om man laddar för många sidor på kort tid, börjar kontrollerna. Jag lyckades få boten att skicka förfrågningar till sajten med intervall på 4 till 6 timmar, och allt fungerade bra. Ibland uppstår det svårigheter även med Kayak, men om kontrollerna börjar bli plågsamma, behöver du antingen lösa dem manuellt och sedan starta boten, eller vänta några timmar så att kontrollerna upphör. Om det behövs kan du anpassa koden för en annan plattform, och om du gör det — informera gärna om det i kommentarerna.

Om du just börjat med web scraping och inte vet varför vissa webbplatser kämpar emot det, så innan du börjar ditt första projekt inom detta område — gör dig själv en tjänst och sök på Google efter material under "web scraping etiquette". Ditt experiment kan avslutas snabbare än du tror om du inte går tillväga på ett förnuftigt sätt.

Komma igång

Här är en översikt av vad som kommer att hända i koden för vår web scraper:

  • Import av nödvändiga bibliotek.
  • Öppna en flik i Google Chrome.
  • Anropa funktionen som startar boten, genom att ge den städer och datum som kommer att användas vid sökningen av biljetter.
  • Denna funktion hämtar de första sökresultaten, sorterade efter kriteriet mest attraktiv (best), och klickar på knappen för att ladda fler resultat.
  • En annan funktion samlar in data från hela sidan och returnerar en dataram.
  • De två tidigare stegen utförs med sorteringstyper baserat på biljettpriser (cheap) och flygtider (fastest).
  • Användaren av skriptet får ett e-postmeddelande som innehåller en kort sammanfattning av biljettpriserna (de billigaste biljetterna och genomsnittspriserna), och datasetet med information sorterad efter de tre ovan nämnda parametrarna sparas som en Excel-fil.
  • Alla ovanstående åtgärder utförs i en cykel med ett angivet tidsintervall.

Det är värt att notera att varje Selenium-projekt börjar med webbläsardrivrutinen. Jag använder Chromedriver, arbetar med Google Chrome, men det finns även andra alternativ. PhantomJS och Firefox är också populära. Efter att drivrutinen har laddats ner måste den placeras i rätt mapp, och förberedelserna för dess användning avslutas här. I de första raderna av vårt skript öppnas en ny flik i Chrome.

Tänk på att jag i min berättelse inte försöker öppna nya horisonter när det gäller att hitta förmånliga erbjudanden på flygbiljetter. Det finns mycket mer avancerade metoder för att hitta sådana erbjudanden. Jag vill bara föreslå läsarna av detta material en enkel men praktisk metod att lösa denna uppgift.

Här är koden som vi diskuterade tidigare.

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

# Använd din väg till chromedriver här!
chromedriver_path = 'C:/{DIN VÄG HÄR}/chromedriver_win32/chromedriver.exe'

driver = webdriver.Chrome(executable_path=chromedriver_path) # Denna kommando öppnar ett Chrome-fönster
sleep(2)

I början av koden kan man se importkommandon för de paket som används i hela vårt projekt. Så, randint används för att låta boten "sova" i ett slumpmässigt antal sekunder innan den påbörjar en ny sökoperation. Oftast är detta en nödvändighet för varje bot. Om man kör den ovanstående koden öppnas ett Chrome-fönster som boten kommer att använda för att arbeta med webbplatser.

Vi ska genomföra ett litet experiment och öppna webbplatsen kayak.com i ett separat fönster. Vi väljer staden vi ska flyga från, staden vi vill åka till, samt resedatum. Vid val av datum kontrollerar vi att intervallet är +-3 dagar. Jag har skrivit kod med hänsyn till vad webbplatsen ger som svar på sådana förfrågningar. Om du till exempel behöver söka biljetter endast på angivna datum, är det stor sannolikhet att du måste justera botens kod. När jag berättar om koden ger jag relevanta förklaringar, men om du känner att du har blivit förvirrad – låt mig veta.

Nu trycker vi på knappen för att starta sökningen och ser på länken i adressfältet. Den ska likna den länk som jag använder i exemplet nedan, där variabeln deklareras kayak, som lagrar URL:en, och metoden används av hämta web-drivern. Efter att ha tryckt på sökknappen bör resultaten dyka upp på sidan.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
När jag använde kommandot hämta mer än två-tre gånger inom några minuter, blev jag ombedd att genomgå en verifiering med reCaptcha. Denna verifiering kan göras manuellt så att man kan fortsätta experimentera tills systemet beslutar att införa en ny verifiering. När jag testade skriptet fick jag intrycket att den första sökseansen alltid går problemfritt, så om du vill experimentera med koden behöver du bara periodiskt genomgå verifieringen manuellt och låta koden köra med långa intervall mellan sökseanser. Och om man tänker efter, så kan det sällan behövas prisinformation om biljetter som inhämtas med 10-minuters intervaller mellan sökoperationerna.

Arbete med sidan med hjälp av XPath

Så, vi har öppnat fönstret och laddat webbplatsen. För att få information om priser och annan information måste vi använda teknologin XPath eller CSS-selektorer. Jag valde att stanna kvar vid XPath och kände ingen behov av att använda CSS-selektorer, men det är fullt möjligt att arbeta på det sättet också. Att navigera på sidan med hjälp av XPath kan vara en knepig uppgift, och även om du använder de metoder som jag har beskrivit i denna I artikeln där jag använde kopiering av motsvarande identifierare från sidans kod, insåg jag att det faktiskt inte är det optimala sättet att adressera de nödvändiga elementen. Förresten, i denna boken finns en utmärkt beskrivning av grunderna för arbete med sidor med hjälp av XPath och CSS-selektorer. Så här ser den relevanta metoden för webbdrivrutinen ut.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
Så, låt oss fortsätta arbetet med boten. Vi kommer att utnyttja programmets möjligheter för att välja de billigaste biljetterna. På nästa bild är koden för XPath-selektorn markerad i rött. För att visa koden behöver du högerklicka på det element på sidan som intresserar dig och välja alternativet Visa kod (Inspect) från den meny som visas. Detta alternativ kan kallas för olika element på sidan, vars kod kommer att visas och markeras i kodvisningsfönstret.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
Visa sidkod

För att hitta bevis på mina tankar om bristerna med att kopiera selektorer från koden, observera följande egenskaper.

Så här ser det ut när man kopierar koden:

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

För att kopiera något liknande behöver du högerklicka på den del av koden som intresserar dig och välja alternativet Copy > Copy XPath från menyn som visas.

Så här använde jag för att identifiera knappen Cheapest:

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

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
Kommandot Copy > Copy XPath

Det är uppenbart att det andra alternativet ser mycket enklare ut. Med det här alternativet söker man efter elementet a, som har attributet data-code, som är lika med price. Med det första alternativet söker man efter elementet id vars värde är wtKI-price_aTab, medan XPath-sökvägen till elementet ser ut som /div[1]/div/div/div[1]/div/span/span. En sådan XPath-förfrågan till sidan kommer att fungera, men - endast en gång. Jag kan säga direkt nu att id ändras vid nästa laddning av sidan. Teckenföljden wtKI ändras dynamiskt vid varje laddning av sidan, vilket gör att koden där den används blir värdelös efter nästa omladdning av sidan. Så ta lite tid att förstå XPath. Denna kunskap kommer att tjäna dig väl.

Det bör dock noteras att kopiering av XPath-selektorer kan vara användbart när man arbetar med ganska enkla webbplatser, och om du är okej med det, så är det inget dåligt med det.

Låt oss nu tänka på hur man ska göra om man vill få alla sökresultat i flera rader, inuti en lista. Det är mycket enkelt. Varje resultat finns inuti ett objekt med klassen resultWrapper. Att hämta alla resultat kan göras i en loop som liknar den som visas nedan.

Det är värt att notera att om du förstår det ovanstående, så borde du utan problem förstå det mesta av koden som vi kommer att gå igenom. Under körningen av denna kod kommer vi att referera till det som vi behöver (i själva verket är det det elementet som innehåller resultatet) med hjälp av en viss mekanism för att ange vägen (XPath). Detta görs för att få texten i elementet och placera den i ett objekt där vi kan läsa data (vi börjar med flight_containers, och sedan — flights_list).

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
De tre första raderna skrivs ut och vi kan tydligt se allt vi behöver. Men vi har också mer intressanta sätt att hämta information på. Vi behöver hämta data från varje element separat.

Låt oss börja!

Det är lättast att skriva en funktion för att ladda fler resultat, så vi börjar med den. Jag skulle vilja maximera antalet flygningar som programmet får information om, och samtidigt inte väcka misstankar hos tjänsten som leder till kontroller, så jag klickar en gång på knappen "Ladda fler resultat" varje gång sidan visas. I denna kod är det viktigt att notera blocket försök, som jag lade till eftersom knappen ibland inte laddas korrekt. Om du stöter på detta också — kommentera ut anropen av denna funktion i funktionen start_kayak, som vi kommer att titta på nedan.

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

Nu, efter en lång genomgång av denna funktion (ibland kan jag bli lite uppslukad), är vi redo att deklarera en funktion som ska ansvara för att skrapa sidan.

Jag har redan samlat det mesta av vad som behövs i nästa funktion som kallas page_scrape. Ibland är de returnerade uppgifterna om vägsteget sammankopplade, för att separera dem använder jag en enkel metod. Till exempel, när jag först använder variablerna section_a_list och section_b_list. Vår funktion returnerar en dataram flights_df, detta gör att vi kan separera resultaten som erhållits med olika metoder för datorsortering och sedan förena dem.

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

Jag har försökt namnge variablerna så att koden blir förståelig. Tänk på att variabler som börjar med a hör till det första steget, medan b hör till det andra. Vi går vidare till nästa funktion.

Hjälpfunktioner

Nu har vi en funktion som gör det möjligt att ladda in ytterligare sökresultat samt en funktion för att bearbeta dessa resultat. Denna artikel skulle kunna avslutas här, eftersom dessa två funktioner ger allt som behövs för att skrapa sidor som kan öppnas självständigt. Men vi har ännu inte behandlat några hjälpfunktioner som nämndes tidigare. Till exempel koden för att skicka e-post och några andra saker. Allt detta kan hittas i funktionen start_kayak, som vi nu ska gå igenom.

För att denna funktion ska fungera krävs information om städer och datum. Den använder denna information för att skapa en länk i variabeln kayak, som används för att navigera till den sida där sökresultaten är sorterade efter det bästa matchningen med förfrågan. Efter den första skrapningen kommer vi att arbeta med priserna som finns i tabellen högst upp på sidan. Vi ska nämligen hitta det lägsta biljettpriset och det genomsnittliga priset. Allt detta, tillsammans med en prognos som ges av webbplatsen, kommer att skickas via e-post. På sidan bör den motsvarande tabellen finnas i det övre vänstra hörnet. Att arbeta med denna tabell kan för övrigt orsaka ett fel när man söker med exakta datum, eftersom tabellen inte visas på sidan i sådana fall.

def start_kayak(city_from, city_to, date_start, date_end):
    """Stads koder - det är IATA koder!
    Datumformat -  ÅÅÅÅ-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))
    
    # Ibland dyker en popup upp, för att kontrollera detta och stänga den kan du använda try-blocket
    try:
        xp_popup_close = '//*[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('laddar mer.....')
    
#     load_more()
    
    print('börjar första skrapningen.....')
    df_flights_best = page_scrape()
    df_flights_best['sort'] = 'bäst'
    sleep(randint(60,80))
    
    # Vi tar det lägsta priset från tabellen högst upp på sidan
    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('byter till billigaste resultat.....')
    cheap_results = '//*[ @data-code = "price"]'
    driver.find_element_by_xpath(cheap_results).click()
    sleep(randint(60,90))
    print('laddar mer.....')
    
#     load_more()
    
    print('börjar andra skrapningen.....')
    df_flights_cheap = page_scrape()
    df_flights_cheap['sort'] = 'billig'
    sleep(randint(60,80))
    
    print('byter till snabbaste resultat.....')
    quick_results = '//*[ @data-code = "duration"]'
    driver.find_element_by_xpath(quick_results).click()  
    sleep(randint(60,90))
    print('laddar mer.....')
    
#     load_more()
    
    print('börjar tredje skrapningen.....')
    df_flights_fast = page_scrape()
    df_flights_fast['sort'] = 'snabb'
    sleep(randint(60,80))
    
    # Spara den nya ramen i en Excel-fil vars namn reflekterar städer och datum
    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('sparad df.....')
    
    # Man kan följa hur prognosen som ges av webbplatsen står i förhållande till verkligheten
    xp_loading = '//*[contains(@id,"advice")]'
    loading = driver.find_element_by_xpath(xp_loading).text
    xp_prediction = '//*[ @class="info-text"]'
    prediction = driver.find_element_by_xpath(xp_prediction).text
    print(loading+'n'+prediction)
    
    # ibland kan variabeln loading vara denna rad, vilket senare orsakar problem med att skicka e-post
    # om detta inträffar - ändrar vi den till "Not Sure"
    weird = '¯_(ツ)_/¯'
    if loading == weird:
        loading = 'Inte säker'
    
    username = 'YOUREMAIL@hotmail.com'
    password = 'DINTLÖSENORD'

    server = smtplib.SMTP('smtp.outlook.com', 587)
    server.ehlo()
    server.starttls()
    server.login(username, password)
    msg = ('Ämne: Flygskrapa
Billigaste flyg: {}nGenomsnittligt pris: {}nnRekommendation: {}nnSlut på meddelande'.format(matrix_min, matrix_avg, (loading+'n'+prediction)))
    message = MIMEMultipart()
    message['Från'] = 'YOUREMAIL@hotmail.com'
    message['till'] = 'YOUROTHEREMAIL@domain.com'
    server.sendmail('YOUREMAIL@hotmail.com', 'YOUROTHEREMAIL@domain.com', msg)
    print('skickade e-post.....')

Jag testade detta skripte med ett Outlook-konto (hotmail.com). Jag har inte kontrollerat hur det fungerar med ett Gmail-konto, vilket är en populär e-posttjänst, men det finns många möjliga alternativ. Om du använder ett Hotmail-konto räcker det med att du anger dina uppgifter i koden för att allt ska fungera.

Om du vill förstå vad som görs på de olika ställena i koden för denna funktion kan du kopiera dem och experimentera med dem. Experiment med koden är det enda sättet att verkligen förstå den.

Färdig system

Nu när vi har gjort allt vi pratade om kan vi skapa en enkel slinga där våra funktioner anropas. Skriptet frågar användaren om städer och datum. Vid testning med ständig omstart av skriptet kommer du antagligen inte vilja ange dessa uppgifter manuellt varje gång, så de relevanta raderna kan kommenteras bort under testningen, medan de nedan, där de nödvändiga skriptuppgifterna är hårdkodade, kan avkommenteras.

city_from = input('Från vilken stad? ')
city_to = input('Vart går vi? ')
date_start = input('Sök runt vilket avresedatum? Vänligen använd endast formatet ÅÅÅÅ-MM-DD ')
date_end = input('Återvänd när? Vänligen använd endast formatet ÅÅÅÅ-MM-DD ')

# 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 {} var klar @ {}'.format(n, strftime("%Y%m%d-%H%M")))
    
    # Väntar 4 timmar
    sleep(60*60*4)
    print('väntan är slut.....')

Så här ser den testkörningen av skriptet ut.
Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa
Testkörning av skriptet

Sammanfattning

Om du har kommit hit – grattis! Nu har du en fungerande webbscraper, även om jag redan ser många sätt att förbättra den. Till exempel kan den integreras med Twilio för att istället för e-post skicka SMS. Du kan använda en VPN eller något annat för att få resultat från flera servrar samtidigt. Det finns också ett problem som periodiskt uppstår med att webbplatsen kontrollerar om användaren är en människa, men det problemet kan också lösas. I vilket fall som helst har du nu en bas som du kan bygga vidare på om du vill. Till exempel kan du göra så att Excel-filen skickas till användaren som en bilaga i ett e-postmeddelande.

Python – en hjälp i sökandet efter billiga flygbiljetter för dem som älskar att resa

Endast registrerade användare kan delta i omröstningen. Logga in, tack.

Använder du webbskrapningstekniker?

  • Ja

  • Ingen

8 användare har röstat. 1 användare avstod.

Källa: habr.com

Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar 🔥 Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster