A cikk szerzője, akinek a fordítását ma publikáljuk, elmondja, hogy célja egy Python alapú web-scraper fejlesztése Selenium használatával, amely repjegyárakat keres. A jegyek keresése rugalmassal történik (+- 3 nap a megadott dátumokhoz képest). A scraper elmenti a keresési eredményeket egy Excel-fájlba, és e-mailben tájékoztatja a futtatót arról, hogy mit talált. A projekt célja, hogy segítsen az utazóknak a legjobb ajánlatok keresésében.
Ha a tartalommal foglalkozva úgy érzi, hogy elveszett — nézzen rá a cikkre.
Mit fogunk keresni?
Szabadon használhatja a leírt rendszert, ahogy szeretné. Én például hétvégi kirándulások és a szülővárosomba szóló jegyek keresésére használtam. Ha komolyan gondolja az olcsó jegyek keresését — futtathatja a scriptet egy szerveren (egy egyszerű , havi 130 forintért, teljesen megfelelő lesz) és beállíthatja, hogy naponta egyszer-kétszer fusson. A keresési eredmények e-mailben érkeznek. Ezen kívül javaslom, hogy állítsa be úgy, hogy a script elmentse az Excel-fájlt a keresési eredményekről egy Dropbox-mappába, így bármikor és bárhonnan megtekintheti az ilyen fájlokat.

Még nem találtam hibás tarifákat, de feltételezem, hogy ez lehetséges.
Kereséskor, ahogy már említettem, „rugalmasságot” alkalmazunk, a script olyan ajánlatokat talál, amelyek a megadott dátumoktól számított három napon belül vannak. Bár a script futtatásakor csak egy irányt keres, könnyen módosítható, hogy több járatra gyűjtsön adatokat. Ezzel még hibás tarifákat is kereshet, és ezek a találatok nagyon érdekesek lehetnek.
Miért van szükség újabb web-scraperre?
Amikor először kezdtem el webes adatgyűjtéssel foglalkozni, őszintén szólva nem volt különösebben érdekes számomra. Több projektet szerettem volna végezni a prediktív modellezés, pénzügyi elemzés és esetleg a szövegek érzelmi hangvételének elemzése terén. De kiderült, hogy nagyon izgalmas dolog – kitalálni, hogyan lehet létrehozni egy programot, amely adatokat gyűjt a weboldalakról. Ahogy egyre mélyebbre ástam magam a témában, rájöttem, hogy a webes adatgyűjtés az internet „motorja”.
Lehet, hogy úgy dönt, hogy ez - túl merész állítás. De gondoljon arra, hogy a Google cége egy webes adatgyűjtővel indult, amelyet Larry Page készített Java és Python nyelv használatával. A Google robotjai felfedezték és felfedezik az internetet, próbálva a legjobb válaszokat adni a felhasználóik kérdéseire. A webes adatgyűjtésnek végtelen sok alkalmazási lehetősége van, és még ha a Data Science területén valami más érdekli is, hogy adatokat szerezzen az elemzéshez, szüksége lesz néhány adatgyűjtési készségre is.
Néhány itt használt technikát egy csodálatos találtam a webes adatgyűjtésről, amelyet nemrég szereztem be. Sok egyszerű példát és ötletet találhatunk benne a tanultak gyakorlati alkalmazásáról. Ezenkívül van benne egy nagyon érdekes fejezet a reCaptcha ellenőrzések megkerüléséről. Számomra ez újdonság volt, mivel nem tudtam, hogy léteznek speciális eszközök és még egész szolgáltatások is az ilyen feladatok megoldására.
Szeretsz utazni?!
A szakasz címében szereplő egyszerű és elég ártalmatlan kérdésre gyakran pozitív választ kapunk, kiegészítve néhány utazási történettel attól, akitől feltették. A legtöbben egyetértenek azzal, hogy az utazás nagyszerű módja az új kulturális környezetekbe való belemerülésnek és a saját látókörünk szélesítésének. Azonban ha valaki megkérdezi, hogy szereti-e repülőjegyeket keresni, biztos vagyok benne, hogy a válasz már nem lesz ennyire pozitív. Valójában itt jön segítségünkre a Python.
Az első feladat, amit meg kell oldanunk az utazási információkereső rendszer létrehozása során, a megfelelő platform kiválasztása, ahonnan az információt szerezzük. E feladat megoldása nem volt könnyű, de végül a Kayak szolgáltatást választottam. Kipróbáltam a Momondo, Skyscanner, Expedia és még néhány más szolgáltatást is, de ezeknél a webhelyeknél a robotvédelmi mechanizmusok áthatolhatatlanok voltak. Miután több próbálkozást tettem, amikor megpróbáltam meggyőzni a rendszereket arról, hogy én egy ember vagyok, közlekedési lámpákkal, gyalogosátkelőkkel és kerékpárokkal kellett foglalkoznom, úgy döntöttem, hogy a Kayak a legjobban megfelel az igényeimnek, annak ellenére, hogy itt, ha túl sok oldalt töltök le rövid idő alatt, szintén ellenőrzések indulnak. Sikerült úgy beállítanom a botot, hogy 4-6 órás időközönként küldje a kéréseket a weboldalra, és minden rendben működött. Időnként problémák merülnek fel a Kayak használata közben is, de ha kezdik zavarni az ellenőrzések, akkor vagy kézzel kell azokat megoldanod, és utána elindítani a botot, vagy várni kell néhány órát, és az ellenőrzéseknek meg kell szűnniük. Ha szükséges, teljesen könnyedén átkonfigurálhatod a kódot más platformra, és ha ezt megteszed, kérlek, tudasd velünk a megjegyzésekben.
Ha éppen most ismerkedsz a webscraping világával, és nem tudod, miért harcolnak a weboldalak ennyire ellene, akkor mielőtt belekezdenél az első projektedbe ezen a területen, tedd meg magadnak a szívességet, és keress rá a Google-ban a "web scraping etiquette" kifejezésre. Kísérleteid gyorsabban véget érhetnek, mint gondolnád, ha gondatlanul foglalkozol a webscrapinggel.
Munka kezdetek
Ez egy általános áttekintés arról, hogy mi fog történni a webscraperünk kódjában:
- A szükséges könyvtárak importálása.
- A Google Chrome fülének megnyitása.
- A funkció hívása, amely elindítja a botot, átadva neki a városokat és időpontokat, amelyeket a jegyek keresésekor használnak.
- Ez a funkció lekéri az első keresési eredményeket, amelyeket a legnagyobb vonzerő (best) alapján rendeztek, és megnyomja a gombot az további eredmények letöltéséhez.
- Egy másik funkció összegyűjti az adatokat az egész oldalról, és visszaad egy adatkeretet.
- A két előző lépést a repülőjegyek árára (cheap) és a repülési sebességre (fastest) vonatkozó rendezési típusok alkalmazásával hajtják végre.
- A script felhasználójának egy e-mailt küldenek, amely összefoglalja a jegyárakat (legolcsóbb jegyek és átlagos ár), míg a három fent említett mutató szerint rendezett adatokat tartalmazó adatkeretet Excel fájl formájában mentik el.
- Az összes fent leírt művelet egy ciklusban történik meg, egy adott időközönként.
Meg kell jegyezni, hogy minden Selenium projekt a webdriverrel kezdődik. Én a , a Google Chrome-mal dolgozom, de más lehetőségek is vannak. Nagy népszerűségnek örvend a PhantomJS és a Firefox is. A driver letöltése után azt a megfelelő mappába kell helyezni, ezzel a felhasználási előkészületek befejeződnek. Skriptünk első soraiban egy új Chrome lap nyitása történik.
Fontos megjegyezni, hogy a történetem során nem próbálok új horizontokat felfedezni a repülőjegyek kedvező ajánlatainak keresésében. Léteznek sokkal fejlettebb módszerek a hasonló ajánlatok megtalálására. Csak annyit szeretnék ajánlani ennek az anyagnak az olvasóinak, hogy egy egyszerű, de gyakorlatban alkalmazható megoldást kínáljak erre a feladatra.
Itt található a kód, amelyről az előbb beszéltünk.
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
# Itt adja meg a chromedriver útvonalát!
chromedriver_path = 'C:/{YOUR PATH HERE}/chromedriver_win32/chromedriver.exe'
driver = webdriver.Chrome(executable_path=chromedriver_path) # Ezzel a parancssal nyílik meg a Chrome ablak
sleep(2) A kód elején láthatók a csomagok importálására szolgáló parancsok, amelyek az egész projektünkben használatban vannak. Ily módon randint arra szolgál, hogy a bot 'aludjon' egy véletlenszerű másodpercet, mielőtt elkezdené az új keresési műveletet. Általában ez elengedhetetlen minden bot számára. Ha az előbb említett kódot futtatják, egy Chrome ablak nyílik meg, amelyet a bot használni fog a weboldalakkal való munkához.
Végezünk egy kis kísérletet, és megnyitjuk külön ablakban a kayak.com weboldalt. Válasszuk ki a várost, ahonnan repülni kívánunk, és a célvárost, ahová szeretnénk eljutni, valamint a repülési dátumokat. A dátumok kiválasztásakor ellenőrizzük, hogy +/- 3 napos intervallumban legyen. Úgy írtam a kódot, hogy figyelembe vegye, mit ad vissza a weboldal az ilyen kérésekre. Ha például az Ön számára kifejezetten kijelölt dátumokra kell keresnie a jegyeket, akkor nagy valószínűséggel módosítania kell a bot kódját. Amikor a kódról beszélek, megfelelõ magyarázatokat adok, de ha úgy érzi, hogy zavarba jött — szóljon nekem.
Most kattintsunk a keresés indító gombra, és nézzük meg a linket a címsorban. Hasonlónak kell lennie ahhoz a linkhez, amelyet az alábbi példában használok, ahol a változó van meghatározva kayak, amely tárolja az URL-t, és a get módszert használja a webdriveren. A keresőgomb megnyomása után az oldalon meg kell jelennie az eredményeknek.
![]()
Amikor a parancsot használtam get két-három alkalommal néhány percen belül, felajánlották, hogy végezzem el a reCaptcha ellenőrzést. Ezt a vizsgálatot manuálisan el lehet végezni, és folytathatjuk a kísérletezést, amíg a rendszer újabb ellenőrzést nem rendel el. Amikor a szkriptet teszteltem, olyan érzésem volt, hogy az első keresési időszak mindig problémamentesen zajlik, így ha kísérletezni szeretne a kóddal, csak időnként kell manuálisan végigcsinálnia az ellenőrzést, és hagynia kell a kódot futni, hosszú időintervallumokat használva a keresési időszakok között. És ha belegondol, valószínűleg nem szükséges az ember számára, hogy 10 perces intervallumokkal keresési műveletekből származó árinformációkat kapjon.
A weboldallal való munka XPath segítségével
Tehát megnyitottunk egy ablakot és betöltöttük az oldalt. Ahhoz, hogy információkat kapjunk az árakról és más adatokról, a XPath vagy CSS szelektorok technológiáját kell használnunk. Úgy döntöttem, hogy a XPath-ra összpontosítok, és nem éreztem szükségét a CSS szelektorok alkalmazásának, de természetesen azzal is lehet dolgozni. Az XPath használata során a weboldalon való navigálás nehéz feladat lehet, és még akkor is, ha azokat a módszereket használja, amelyeket már említettem a A cikkben, ahol a weboldal kódjából másoltuk a megfelelő azonosítókat, rájöttem, hogy ez valójában nem az optimális módszer a szükséges elemekhez való hozzáféréshez. Egyébként, a könyvben nagyszerű leírás található az XPath és CSS-szelektorokkal való munkáról. Így néz ki a megfelelő web-driver metódus.
![]()
Folytassuk a bot fejlesztését. Használjuk a programot a legolcsóbb jegyek keresésére. A következő képen pirossal ki van emelve az XPath szeletelő kód. A kód megtekintéséhez jobb gombbal kattintson az érdeklődő elemre az oldalon, majd a megjelenő menüből válassza ki a Kód megtekintése (Inspect) parancsot. Ezt a parancsot különböző oldalelemekhez is ki lehet adni, melyek kódja megjelenik és kiemelkedik a kód néző ablakában.

Oldal kódjának megtekintése
Annak érdekében, hogy megerősítsem meglátásaimat a szeletelők másolásának hátrányairól, figyeljen a következő jellemzőkre.
Így néz ki, amikor a kódot másoljuk:
//*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/spanEhhez jobb gombbal kattintson az érdeklődő kód részére, és a megjelenő menüből válassza a Copy > Copy XPath parancsot.
Ez az, amit a Cheapest gomb meghatározásához használtam:
cheap_results = '//*[@data-code="price"]' 
Copy > Copy XPath parancs
Egyértelműen látszik, hogy a második lehetőség sokkal egyszerűbbnek tűnik. Ennek használata során a elemet keresjük, amelynek attribútuma van data-code, amely megegyezik a price-val. Az első lehetőség használatakor az elemet keresünk, amelynek id egyenlő a wtKI-price_aTab, míg az XPath út a következőképpen néz ki /div[1]/div/div/div[1]/div/span/span. Az ilyen XPath lekérdezés az oldalra elvégzi a dolgát, de - csak egyszer. Most azonnal ki tudom mondani, hogy id a következő oldalbetöltéskor megváltozik. A karakterek sorozata wtKI minden oldalbetöltéskor dinamikusan változik, ezért a kódban, amelyben használják, a következő oldalon való újratöltés után haszontalan lesz. Ezért szánjon egy kis időt az XPath megértésére. Ezek az ismeretek jó szolgálatot tehetnek önnek.
Fontos megjegyezni, hogy az XPath-szelektorok másolására lehet szükség viszonylag egyszerű weboldalak esetén, és ha ez önnek megfelel, akkor ebben nincs semmi rossz.
Most nézzük meg, mi a teendő, ha az összes keresési eredményt több sorban kell megjeleníteni egy listában. Nagyon egyszerű. Minden eredmény egy olyan objektumban található, amelynek osztálya resultWrapper. Az összes eredmény betöltése egy olyan ciklusban történhet, amely hasonló ahhoz, ami az alábbiakban látható.
Meg kell jegyezni, hogy ha az előbbieket megértetted, akkor problémamentesen meg fogod érteni a legtöbb kódot, amit elemezni fogunk. A kód futása során, hogy elérjük azt, amire szükségünk van (tulajdonképpen ez az elem, amely körülveszi az eredményt), egy mechanizmust használunk az útvonal megadására (XPath). Ezt azért tesszük, hogy megkapjuk az elem szövegét, és elhelyezzük egy objektumban, ahonnan adatokat tudunk olvasni (először a flight_containers, majd a flights_list).

Az első három sort jelenítjük meg, és egyértelműen látjuk mindent, amire szükségünk van. Ugyanakkor vannak érdekesebb módok az információk megszerzésére. Az adatokat minden egyes elemről külön kell gyűjtenünk.
Lássuk neki!
A legkönnyebb funkciót írni a további eredmények betöltéséhez, ezért ezzel kezdjük. Szeretném maximalizálni a program által begyűjtött járatok számát, ugyanakkor elkerülni, hogy a szolgáltatás gyanút fogjon, ami ellenőrzéshez vezethet, ezért minden alkalommal, amikor egy oldal megjelenik, egyszer rákattintok a 'További eredmények betöltése' gombra. Ebben a kódban figyelmet kell fordítani a tryblokkjára, amit azért adtam hozzá, mert néha a gomb nem töltődik be rendesen. Ha te is ezzel szembesülsz, kommentáld ki ennek a funkciónak a hívásait a start_kayakfunkcióban, amit alább fogunk megvizsgálni.
# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
def load_more():
try:
more_results = '//a[@class = "moreButton"]'
driver.find_element_by_xpath(more_results).click()
# Вывод этих заметок в ходе работы программы помогает мне быстро выяснить то, чем она занята
print('sleeping.....')
sleep(randint(45,60))
except:
passMost, hogy hosszasan elemeztük ezt a funkciót (néha el tudok kalandozni), készen állunk, hogy bejelentsük a funkciót, amely a weboldal adatainak kéregyűjtésével foglalkozik.
Már összegyűjtöttem a szükséges elemek nagy részét a következő funkcióban, amelyet page_scrape-nak hívnak. Néha a visszaadott adatok a szakaszok között össze vannak vonva, ezért egy egyszerű módszert használok a szétválasztásukra. Például, amikor először használom a következő változókat: section_a_list és section_b_list. Funkciónk egy adatkeretet ad vissza, flights_df, amely lehetővé teszi számunkra, hogy szétválasszuk a különböző adatfeldolgozási módszerekkel nyert eredményeket, és később egyesíthessük azokat.
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 Arra próbáltam neveket adni a változóknak, hogy a kód érthető legyen. Ne feledjétek, hogy a változók, amik a következővel kezdődnek, a az első lépéshez tartoznak, míg b — a másodikhoz. Térjünk át a következő funkcióra.
Segédmechanizmusok
Most van egy funkciónk, amely lehetővé teszi a további keresési eredmények betöltését, és egy funkciónk, amely ezek feldolgozását végzi. Ezen a ponton befejezhetnénk a cikket, mivel ezek a két funkció mindent megadnak a lapok saját maga által történő megkaparásához. De még nem tárgyaltunk néhány segédmechanizmust, amiről fent említést tettünk. Például — ez a kód az e-mailek küldésére és még néhány dologra vonatkozik. Mindezt a start_kayakfüggvényben találhatjuk, amelyet most meg fogunk vizsgálni.
Ehhez a funkcióhoz információkra van szükségünk a városokról és a dátumokról. Ez felhasználja ezeket az információkat, hogy linket alakítson ki a kayakváltozóban, amely az eredmények megjelenítésére szolgáló oldalra navigál. Az első megkaparás után foglalkozunk az árakkal, amelyek a lap tetején található táblázatban szerepelnek. Nevezetesen, megtaláljuk a legkisebb jegyárat és az átlagárat. Mindez, együtt a webhely által megadott előrejelzéssel, e-mailben lesz elküldve. Az oldalon a megfelelő táblázatnak a bal felső sarokban kell lennie. A táblázattal való munka, egyébként, hibát okozhat, ha pontos dátumokkal keresünk, mivel ilyenkor a táblázat nem jelenik meg az oldalon.
def start_kayak(city_from, city_to, date_start, date_end):
"""Városi kódok - ezek az IATA kódok!
Dátum formátum - 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))
# néha felugró ablak jelenik meg, erről való ellenőrzéshez és bezárásához használhatjuk a try blokkot
try:
xp_popup_close = '//*[@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('többet töltenek.....')
# load_more()
print('az első scrape kezdése.....')
df_flights_best = page_scrape()
df_flights_best['sort'] = 'best'
sleep(randint(60,80))
# Kiveszzük a legolcsóbb árat a táblázatból, amely az oldal tetején található
matrix = driver.find_elements_by_xpath('/*[@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('váltás a legolcsóbb eredményekre.....')
cheap_results = '//*[@data-code = "price"]'
driver.find_element_by_xpath(cheap_results).click()
sleep(randint(60,90))
print('többet töltenek.....')
# load_more()
print('a második scrape kezdése.....')
df_flights_cheap = page_scrape()
df_flights_cheap['sort'] = 'cheap'
sleep(randint(60,80))
print('váltás a leggyorsabb eredményekre.....')
quick_results = '//*[@data-code = "duration"]'
driver.find_element_by_xpath(quick_results).click()
sleep(randint(60,90))
print('többet töltenek.....')
# load_more()
print('a harmadik scrape kezdése.....')
df_flights_fast = page_scrape()
df_flights_fast['sort'] = 'fast'
sleep(randint(60,80))
# Az új keret mentése Excel fájlba, amelynek neve tükrözi a városokat és a dátumokat
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 elmentve.....')
# Nyomon követhetjük, hogy az oldal által megadott előrejelzés hogyan hasonlít a valósághoz
xp_loading = '//*[@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)
# néha a loading változóban ez a sor van, ami később problémát okoz a levél küldésénél
# ha ez bekövetkezik - megváltoztatjuk "Not Sure"-ra
weird = '¯_(ツ)_/¯'
if loading == weird:
loading = 'Nem biztos'
username = 'YOUREMAIL@hotmail.com'
password = 'YOUR PASSWORD'
server = smtplib.SMTP('smtp.outlook.com', 587)
server.ehlo()
server.starttls()
server.login(username, password)
msg = ('Tárgy: Flight Scrapernn
Legolcsóbb járat: {}nÁtlagos ár: {}nnAjánlás: {}nnÜzenet vége'.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('levél elküldve.....')A tesztelés során egy Outlook (hotmail.com) fiók segítségével teszteltem ezt a szkriptet. Nem ellenőriztem, hogy Gmail fiókkal hogyan működik, ez a levelezőrendszer nagyon népszerű, de sok lehetőség van. Ha azonban Hotmail fiókot használ, elég, ha beírja a saját adatait a kódba, hogy minden működjön.
Ha szeretné megérteni, hogy pontosan mi történik a kód ezen funkciójának egyes részein, másolja ki őket, és kísérletezzen velük. A kóddal való kísérletezés az egyetlen módja, hogy alaposan megértse.
Kész rendszer
Most, hogy mindent elvégeztünk, amiről beszéltünk, létrehozhatunk egy egyszerű ciklust, amely hívja a funkcióinkat. A szkript megkéri a felhasználót, hogy adja meg a városokat és a dátumokat. Ha a szkriptet folyamatosan újraindítja, aligha lesz kedve minden alkalommal manuálisan megadni ezeket az adatokat, ezért a megfelelő sorokat, a tesztelés idejére, megjegyezheti, és az az alatt következő sorokat, amelyekben a szkript által szükséges adatok rögzítettek, ki is kommentelheti.
city_from = input('Melyik városból? ')
city_to = input('Hova? ')
date_start = input('Melyik indulási dátum körül keres? Kérjük, csak YYYY-MM-DD formátumban. ')
date_end = input('Mikor térjen vissza? Kérjük, csak YYYY-MM-DD formátumban. ')
# 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('a(z) {} iteráció befejeződött @ {}'.format(n, strftime("%Y%m%d-%H%M")))
# Várunk 4 órát
sleep(60*60*4)
print('a várakozás véget ért.....') Íme, így néz ki a szkript tesztelése.

Szkript tesztelése
Összegzés
Ha eljutott ide, gratulálok! Most már van egy működő web-szörfözője, bár már látom számos lehetőséget a fejlesztésére. Például integrálható a Twilio-val, hogy ne e-maileket küldjön, hanem SMS-t. Használhat VPN-t vagy valamilyen más módszert, hogy egyszerre több szerver eredményeit is megkapja. Van egy időszakosan felmerülő probléma is a weboldal felhasználóinak kinyomozásával, hogy emberek-e, de ezt a problémát is meg lehet oldani. Mindenesetre most már rendelkezik egy alapfelépítéssel, amelyet, ha szeretne, bővíthet. Például úgy, hogy az Excel fájl csatolmányként kerüljön a felhasználóhoz e-mailben.
Csak a regisztrált felhasználók vehetnek részt a szavazáson. , kérem.
Használ web-szörfözési technológiákat?
Igen
Nem
8 felhasználó szavazott. 1 felhasználó tartózkodott.
Forrás: habr.com
