Autorul articolului, a cărui traducere o publicăm astăzi, afirmă că scopul său este de a vorbi despre dezvoltarea unui web scrapper în Python folosind Selenium, care caută prețuri pentru bilete de avion. Când caută bilete, acesta utilizează date flexibile (+- 3 zile față de datele specificate). Scraperul salvează rezultatele căutării într-un fișier Excel și trimite un e-mail către cel care l-a rulat, cu informații generale despre ceea ce a reușit să găsească. Scopul acestui proiect este de a ajuta călătorii să găsească cele mai avantajoase oferte.
Dacă, în timp ce te ocupi cu materialul, simți că te-ai pierdut — aruncă o privire pe articol.
Ce vom căuta?
Ești liber să folosești sistemul descris aici așa cum dorești. Eu, de exemplu, l-am utilizat pentru a căuta excursii de weekend și bilete către orașul meu natal. Dacă ești serios în ceea ce privește căutarea de bilete avantajoase — poți rula scriptul pe un server (un simplu , pentru 130 de ruble pe lună, se va potrivi perfect) și să-l configurezi să ruleze o dată sau de două ori pe zi. Rezultatele căutării îți vor fi trimise prin e-mail. În plus, îți recomand să configurezi totul astfel încât scriptul să salveze un fișier Excel cu rezultatele căutării într-un folder Dropbox, ceea ce îți va permite să vizualizezi fișierele respective de oriunde și în orice moment.

Deocamdată, nu am găsit tarife cu erori, dar bănuiesc că este posibil
În timpul căutării, așa cum am menționat anterior, se utilizează „data flexibilă”, scriptul găsește oferte aflate în termen de trei zile de datele specificate. Deși, atunci când rulezi scriptul, căutarea se efectuează doar pentru o singură direcție, nu este greu să-l modifici astfel încât să poată colecta date pentru mai multe direcții de zbor. Cu ajutorul său, poți chiar căuta tarife eronate, astfel de descoperiri pot fi destul de interesante.
De ce avem nevoie de încă un web scrapper?
Când am început să mă ocup de web scraping, trebuie să recunosc că nu mi s-a părut foarte interesant. Voiam să fac mai multe proiecte în domeniul modelării predictive, analizei financiare și poate, în analiza sentimentului textelor. Dar s-a dovedit a fi foarte interesant — să înțeleg cum să creez un program care colectează date de pe site-uri web. Pe măsură ce m-am aprofundat în acest subiect, am realizat că web scraping-ul este „motorul” internetului.
Poate că veți considera că aceasta este o afirmație prea îndrăzneață. Dar gândiți-vă că compania Google a început cu un web scraper creat de Larry Page folosind Java și Python. Roboții Google au explorat și continuă să exploreze internetul, încercând să ofere utilizatorilor cele mai bune răspunsuri la întrebările lor. Web scraping-ul are o multitudine nesfârșită de aplicații, iar chiar dacă, în domeniul Data Science, sunteți interesat de altceva, pentru a obține date pentru analiză, veți avea nevoie de abilități de scraping.
Unele dintre tehnicile folosite aici le-am găsit într-o minunată despre web scraping, pe care tocmai am achiziționat-o. Aceasta conține o mulțime de exemple simple și idei pentru aplicarea practică a ceea ce am învățat. În plus, există un capitol foarte interesant despre cum să ocolești verificările reCaptcha. A fost o noutate pentru mine, deoarece nu știam că există instrumente speciale și chiar servicii dedicate pentru a rezolva astfel de probleme.
Îți place să călătorești?!
La o întrebare simplă și oarecum inofensivă, expusă în titlul acestei secțiuni, deseori se poate auzi un răspuns pozitiv, însoțit de câteva povești din călătorii din partea celui căruia i s-a pus întrebarea. Cea mai mare parte dintre noi va fi de acord că călătoriile sunt o modalitate minunată de a te imersa în noi culturi și de a-ți extinde orizonturile. Cu toate acestea, dacă ai întreba pe cineva dacă îi place să caute bilete de avion, sunt sigur că răspunsul ar fi departe de a fi pozitiv. De fapt, aici ne vine în ajutor Python.
Primul sarcină pe care trebuie să o rezolvăm în drumul nostru către crearea unui sistem de căutare a informațiilor despre biletele de avion va fi alegerea platformei potrivite de la care vom obține informațiile. Rezolvarea acestei sarcini nu mi-a fost ușoară, dar în final am ales serviciul Kayak. Am încercat serviciile Momondo, Skyscanner, Expedia și altele, dar mecanismele de protecție împotriva roboților de pe aceste resurse erau de neînvins. După câteva încercări, în care am încercat să conving sistemele că sunt om, a trebuit să mă confrunt cu semafoare, treceri de pietoni și biciclete. Am decis că Kayak se potrivește cel mai bine nevoilor mele, chiar dacă și aici, dacă încarc prea multe pagini într-un timp scurt, încep și verificările. Am reușit să fac astfel încât botul să trimită cereri către site în intervale de 4 până la 6 ore și totul funcționa bine. Între timp, apar unele dificultăți și în utilizarea Kayak, dar dacă te apasă verificările, trebuie fie să le rezolvi manual și apoi să lansezi botul, fie să aștepți câteva ore, moment în care verificările ar trebui să înceteze. Dacă este necesar, poți adapta codul pentru o altă platformă, iar dacă o faci, nu uita să ne anunți în comentarii.
Dacă abia începi să te familiarizezi cu web scrapingul și nu știi de ce unele site-uri web se opun cu atâta înverșunare, înainte de a te apuca de primul tău proiect în acest domeniu — fă-ți un favor și caută pe Google materiale despre „eticheta web scrapingului”. Experimentele tale s-ar putea finaliza mai repede decât crezi, în cazul în care te apuci de web scraping fără o abordare rațională.
Începerea utilizării
Iată o prezentare generală a ceea ce se va întâmpla în codul web scraperului nostru:
- Importarea bibliotecilor necesare.
- Deschiderea unei filiale în Google Chrome.
- Apelarea unei funcții care lansează botul, transmițându-i orașele și datele care vor fi folosite în căutarea biletelor.
- Această funcție obține primele rezultate ale căutării, sortate după criteriul celei mai mari atractivități (best), și apasă pe butonul pentru a descărca rezultate suplimentare.
- Încă o funcție adună datele de pe întreaga pagină și returnează un cadru de date.
- Cele două pași anteriori sunt efectuate folosind tipuri de sortare după prețul biletelor (cheap) și după viteza zborului (fastest).
- Utilizatorului scriptului i se trimite un e-mail care conține un rezumat al prețurilor biletelor (cele mai ieftine bilete și prețul mediu), iar setul de date cu informațiile, sortate după cele trei indicatori menționați mai sus, este salvat sub formă de fișier Excel.
- Toate acțiunile descrise mai sus se desfășoară în ciclu, la un interval de timp stabilit.
Trebuie menționat că fiecare proiect Selenium începe cu un driver web. Eu folosesc , lucrez cu Google Chrome, dar există și alte opțiuni. PhantomJS și Firefox sunt și ele populare. După ce driverul este descărcat, trebuie plasat în folderul corespunzător, iar aceasta este ultima etapă de pregătire pentru utilizarea sa. În primele linii ale scriptului nostru, se deschide un nou tab în Chrome.
Rețineți că, în relatarea mea, nu încerc să descopăr orizonturi noi în căutarea unor oferte avantajoase pentru biletele de avion. Există metode mult mai avansate de a găsi astfel de oferte. Eu doar doresc să propun cititorilor acestui material o metodă simplă, dar aplicabilă în practică pentru a rezolva această problemă.
Iată codul despre care am vorbit mai sus.
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
# Folosiți aici calea dvs. către chromedriver!
chromedriver_path = 'C:/{YOUR PATH HERE}/chromedriver_win32/chromedriver.exe'
driver = webdriver.Chrome(executable_path=chromedriver_path) # Această comandă deschide fereastra Chrome
sleep(2) La începutul codului, puteți vedea comenzile de import pentru pachetele utilizate în întregul nostru proiect. Astfel, randint este utilizat pentru ca botul să "doarmă" un număr aleatoriu de secunde înainte de a începe o nouă operațiune de căutare. De obicei, această funcționalitate este prezentă în orice bot. Dacă rulăm codul de mai sus, se va deschide o fereastră Chrome, pe care botul o va folosi pentru a interacționa cu site-urile.
Vom face un mic experiment și vom deschide site-ul kayak.com într-o fereastră separată. Vom alege orașul din care vrem să zburăm și orașul în care dorim să ajungem, precum și datele zborurilor. Atunci când alegem datele, ne vom asigura că se folosește un interval de +-3 zile. Am scris un cod având în vedere ce returnează site-ul ca răspuns la astfel de cereri. Dacă, de exemplu, aveți nevoie să căutați bilete doar pentru datele specificate, este foarte probabil că va trebui să adaptați codul botului. Când vorbesc despre cod, fac explicațiile corespunzătoare, dar dacă simțiți că v-ați pierdut, nu ezitați să-mi spuneți.
Acum facem clic pe butonul de pornire a căutării și ne uităm la linkul din bara de adrese. Acesta ar trebui să arate similar cu linkul pe care îl folosesc în exemplul de mai jos, acolo unde este declarată variabila kayak, care stochează URL-ul, și se folosește metoda get webdriver-ului. După ce facem clic pe butonul de căutare, rezultatele ar trebui să apară pe pagină.
![]()
Când am folosit comanda get de mai mult de două-trei ori în câteva minute, mi s-a cerut să trec printr-o verificare folosind reCaptcha. Această verificare poate fi efectuată manual și putem continua experimentele până când sistemul decide să inițieze o nouă verificare. Când am testat scriptul, am avut senzația că prima sesiune de căutare trece întotdeauna fără probleme, așa că, dacă doriți să experimentați cu codul, va trebui doar să treceți periodic prin verificare manual și să lăsați codul să ruleze, folosind intervale lungi între sesiunile de căutare. În plus, dacă ne gândim bine, unei persoane nu îi vor fi necesare informații despre prețurile biletelor obținute cu intervale de 10 minute între căutări.
Lucrul cu pagina folosind XPath
Așadar, am deschis fereastra și am încărcat site-ul. Pentru a obține informații despre prețuri și alte date, trebuie să folosim tehnologia XPath sau selectorii CSS. Am decis să mă opresc la XPath și nu am simțit nevoia de a folosi selectorii CSS, dar este complet posibil să lucrăm și în acest fel. Navigarea pe pagină folosind XPath poate fi o sarcină dificilă, iar chiar dacă folosiți metodele pe care le-am descris în În articolul în care s-au utilizat identificatori corespunzători din codul paginii, am realizat că acesta nu este, de fapt, cea mai optimă modalitate de a accesa elementele necesare. Apropo, în carte se poate găsi o descriere excelentă a principiilor de lucru cu paginile folosind XPath și selecții CSS. Iată cum arată metoda corespunzătoare a web driver-ului.
![]()
Așadar, continuăm lucrul la bot. Vom folosi capacitățile programului pentru a căuta cele mai ieftine bilete. În imaginea următoare, codul selectorului XPath este evidențiat cu roșu. Pentru a vizualiza codul, trebuie să faceți clic dreapta pe elementul de pe pagină care vă interesează și să selectați comanda Inspecționați (Inspect) din meniul afișat. Această comandă poate fi invocată pentru diferite elemente ale paginii, codul cărora va fi afișat și evidențiat în fereastra de vizualizare a codului.

Vizualizarea codului paginii
Pentru a găsi o confirmare a observațiilor mele despre dezavantajele copiatului selectorilor din cod, acordați atenție următoarelor particularități.
Iată ce obținem atunci când copiem codul:
//*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/spanPentru a copia un cod asemănător, trebuie să faceți clic dreapta pe zona de interes din cod și să selectați în meniul afișat comanda Copy > Copy XPath.
Iată ce am folosit pentru a determina butonul Cheapest:
cheap_results = '//'a[@data-code = "price"]' 
Comanda Copy > Copy XPath
Este foarte clar că a doua opțiune arată mult mai simplu. Prin utilizarea sa, se caută elementul a, care are atributul data-code, egal cu price. Folosind prima opțiune, se caută elementul id care este egal cu wtKI-price_aTab, în timp ce calea XPath către element arată ca /div[1]/div/div/div[1]/div/span/span. O astfel de interogare XPath către pagină își va face treaba, dar — doar o dată. Pot să spun acum că id se va schimba la următoarea încărcare a paginii. Secvența de caractere wtKI se modifică dinamic la fiecare încărcare a paginii, astfel că codul în care este utilizat va deveni inutil după o nouă reîncărcare a paginii. De aceea, alocați puțin timp pentru a înțelege XPath. Aceste cunoștințe vă vor fi de mare ajutor.
Cu toate acestea, este de remarcat că copierea selectorilor XPath poate fi utilă atunci când lucrați cu site-uri suficient de simple și, dacă acest lucru vă convine, nu este nimic rău în asta.
Acum să ne gândim la ce trebuie să facem dacă dorim să obținem toate rezultatele căutării în mai multe rânduri, într-o listă. Foarte simplu. Fiecare rezultat se află în interiorul unui obiect cu clasa resultWrapper. Încărcarea tuturor rezultatelor poate fi realizată într-un ciclu, similar cu cel care va fi prezentat mai jos.
Trebuie menționat că, dacă ați înțeles cele de mai sus, atunci nu ar trebui să aveți probleme să înțelegeți majoritatea codului pe care vom analiza. În cadrul funcționării acestui cod, pentru ceea ce avem nevoie (de fapt — este elementul în care este înfășurat rezultatul), ne referim la el folosind un anumit mecanism pentru a indica calea (XPath). Se face acest lucru pentru a obține textul elementului și pentru a-l plasa într-un obiect din care putem citi datele (inițial se folosește flight_containers, apoi — flights_list).

Se afișează primele trei rânduri și putem observa clar tot ce avem nevoie. Cu toate acestea, există și metode mai interesante de a obține informații. Trebuie să luăm datele din fiecare element separat.
Să lucrăm!
Cel mai simplu este să scriem o funcție pentru a încărca rezultate suplimentare, astfel încât să începem. Mi-ar plăcea să maximizez numărul de zboruri despre care programul obține informații, fără a stârni suspiciuni din partea serviciului care să ducă la verificări, așa că fac clic o singură dată pe butonul Încărcați mai multe rezultate de fiecare dată când pagina este afișată. În acest cod, merită să acordăm atenție blocului try, pe care l-am adăugat deoarece uneori butonul nu se încarcă corect. Dacă vă confruntați și cu aceasta — comentați apelurile acestei funcții în codul funcției start_kayak, pe care o vom analiza mai jos.
# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
def load_more():
try:
more_results = '//a[@class = "moreButton"]'
driver.find_element_by_xpath(more_results).click()
# Вывод этих заметок в ходе работы программы помогает мне быстро выяснить то, чем она занята
print('sleeping.....')
sleep(randint(45,60))
except:
passAcum, după o analiză lungă a acestei funcții (uneori pot fi destul de captivat), suntem pregătiți să declarăm funcția care se va ocupa de scraping-ul paginii.
Am adunat deja cea mai mare parte din ceea ce avem nevoie în următoarea funcție, numită page_scrape. Uneori, datele returnate despre etapele călătoriei pot fi combinate, iar pentru a le separa folosesc o metodă simplă. De exemplu, atunci când folosesc pentru prima dată variabilele section_a_list și section_b_list. Funcția noastră returnează un cadru de date flights_df, ceea ce ne permite să separăm rezultatele obținute prin utilizarea diferitelor metode de sortare a datelor și apoi să le combinăm.
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 Am încercat să denumesc variabilele astfel încât codul să fie ușor de înțeles. Amintiți-vă că variabilele care încep cu a se referă la prima etapă a procesului, iar b – la a doua. Să trecem la următoarea funcție.
Mecanisme auxiliare
Acum avem o funcție care permite încărcarea rezultatelor suplimentare ale căutării și o funcție pentru procesarea acestor rezultate. Acest articol ar putea fi încheiat aici, deoarece aceste două funcții oferă tot ce este necesar pentru scraping-ul paginilor care pot fi deschise autonom. Dar nu am abordat încă unele mecanisme auxiliare despre care am vorbit mai sus. De exemplu, acesta este codul pentru trimiterea e-mailurilor și câteva alte aspecte. Toate acestea pot fi găsite în funcția start_kayak, pe care o vom analiza acum.
Pentru funcționarea acestei funcții sunt necesare informații despre orașe și date. Aceasta, folosind aceste informații, formează un link în variabila kayak, care este utilizată pentru a accesa pagina pe care se vor afla rezultatele căutării, sortate după cel mai bun răspuns la cerere. După prima sesiune de scraping, vom lucra cu prețurile aflate în tabel, în partea de sus a paginii. Mai exact, vom găsi prețul minim al biletului și prețul mediu. Toate acestea, împreună cu predicția oferită de site, vor fi trimise prin e-mail. Pe pagină, tabelul corespunzător ar trebui să fie în colțul din stânga sus. Lucrul cu acest tabel, de altfel, poate provoca o eroare în căutarea utilizând date exacte, deoarece în acest caz tabelul de pe pagină nu se afișează.
def start_kayak(city_from, city_to, date_start, date_end):
"""Coduri de oraș - acestea sunt codurile IATA!
Formatul datei - 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))
# uneori apare o fereastră pop-up, pentru a verifica aceasta și a o închide, se poate folosi blocul 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('încărcând mai multe.....')
# load_more()
print('începând prima extragere.....')
df_flights_best = page_scrape()
df_flights_best['sort'] = 'best'
sleep(randint(60,80))
# Vom lua cel mai mic preț din tabelul situat în partea superioară a paginii
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('comutând la cele mai ieftine rezultate.....')
cheap_results = '//' + 'a[@data-code = "price"]'
driver.find_element_by_xpath(cheap_results).click()
sleep(randint(60,90))
print('încărcând mai multe.....')
# load_more()
print('începând a doua extragere.....')
df_flights_cheap = page_scrape()
df_flights_cheap['sort'] = 'cheap'
sleep(randint(60,80))
print('comutând la cele mai rapide rezultate.....')
quick_results = '//' + 'a[@data-code = "duration"]'
driver.find_element_by_xpath(quick_results).click()
sleep(randint(60,90))
print('încărcând mai multe.....')
# load_more()
print('începând a treia extragere.....')
df_flights_fast = page_scrape()
df_flights_fast['sort'] = 'fast'
sleep(randint(60,80))
# Salvarea noului cadru într-un fișier Excel, al cărui nume reflectă orașele și datele
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('df salvat.....')
# Se poate urmări modul în care prognoza oferită de site se corelează cu realitatea
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)
# uneori în variabila loading apare această linie, care, mai târziu, cauzează probleme cu trimiterea email-ului
# dacă s-a întâmplat acest lucru - o schimbăm în "Not Sure"
weird = '¯_(ツ)_/¯'
if loading == weird:
loading = 'Nu sunt sigur'
username = 'YOUREMAIL@hotmail.com'
password = 'YOUR PASSWORD'
server = smtplib.SMTP('smtp.outlook.com', 587)
server.ehlo()
server.starttls()
server.login(username, password)
msg = ('Subject: Extragere zbornn
Cel mai ieftin zbor: {}nPreț mediu: {}nnRecomandare: {}nnSfârșitul mesajului'.format(matrix_min, matrix_avg, (loading+'n'+prediction)))
message = MIMEMultipart()
message['From'] = 'YOUREMAIL@hotmail.com'
message['to'] = 'YOUROTHEREMAIL@domain.com'
server.sendmail('YOUREMAIL@hotmail.com', 'YOUROTHEREMAIL@domain.com', msg)
print('email trimis.....')Am testat acest script folosind un cont Outlook (hotmail.com). Nu l-am verificat pentru a funcționa corect cu un cont Gmail, acest sistem de e-mail fiind destul de popular, dar există multe opțiuni posibile. Dacă folosiți un cont Hotmail, atunci, pentru a funcționa totul corect, este suficient să introduceți datele voastre în cod.
Dacă doriți să înțelegeți ce se întâmplă în anumite secțiuni ale codului acestei funcții, puteți să le copiați și să experimentați cu ele. Experimentele cu codul sunt singura modalitate de a-l înțelege cu adevărat.
Sistemul finalizat
Acum, când am realizat tot ce am discutat, putem crea un ciclu simplu în care apelăm funcțiile noastre. Scriptul solicită utilizatorului date despre orașe și date. Atunci când testați scriptul cu restarturi permanente, probabil că nu veți dori să introduceți aceste date manual de fiecare dată, așa că, pentru perioada de testare, puteți comenta liniile corespunzătoare, deblocând pe cele de mai jos care conțin datele necesare scriptului.
city_from = input('Din care oraș? ')
city_to = input('Unde mergem? ')
date_start = input('Căutăm în jurul cărei date de plecare? Vă rugăm să folosiți formatul YYYY-MM-DD ')
date_end = input('Întoarcerea când? Vă rugăm să folosiți formatul YYYY-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('iterația {} a fost completă @ {}'.format(n, strftime("%Y%m%d-%H%M")))
# Așteptăm 4 ore
sleep(60*60*4)
print('somnul s-a terminat.....') Iată cum arată lansarea de test a scriptului.

Lansarea de test a scriptului
Concluzii
Dacă ați ajuns până aici, acceptați felicitările! Acum aveți un web scraper funcțional, deși deja văd multe moduri de a-l îmbunătăți. De exemplu, ar putea fi integrat cu Twilio, pentru a trimite mesaje text în loc de e-mailuri. Puteți folosi un VPN sau ceva similar pentru a obține rezultate simultan de la mai multe servere. Există și problema periodică a verificării utilizatorului de către site, pentru a verifica dacă este om, dar această problemă poate fi rezolvată. Oricum, acum aveți o bază pe care, dacă doriți, o puteți extinde. De exemplu, ați putea face ca fișierul Excel să fie trimis utilizatorului ca atașament în e-mail.
Numai utilizatorii înregistrați pot participa la sondaj. , vă rugăm.
Folositi tehnologii de web scraping?
Da
Nu
8 utilizatori au votat. 1 utilizator s-a abținut.
Sursa: habr.com
