Autor artykułu, którego tłumaczenie publikujemy dzisiaj, mówi, że jego celem jest przedstawienie rozwoju web scrapera w Pythonie z wykorzystaniem Selenium, który wyszukuje ceny biletów lotniczych. Przy wyszukiwaniu biletów uwzględniane są elastyczne daty (+- 3 dni w stosunku do podanych dat). Scraper zapisuje wyniki wyszukiwania w pliku Excel i wysyła wiadomość e-mail do osoby, która go uruchomiła, z ogólnymi informacjami na temat tego, co udało mu się znaleźć. Celem tego projektu jest pomoc podróżnikom w znalezieniu najlepszych ofert.
Jeśli podczas przeglądania materiału poczujesz, że się zgubiłeś — zerknij na artykuł.
Czego będziemy szukać?
Masz swobodę korzystania z opisanego tutaj systemu tak, jak chcesz. Na przykład, ja używałem go do wyszukiwania wyjazdów weekendowych i biletów do mojego rodzinnego miasta. Jeśli poważnie myślisz o znalezieniu korzystnych biletów — możesz uruchomić skrypt na serwerze (prosty , za 130 złotych miesięcznie, jest do tego zupełnie wystarczający) i ustawić, aby uruchamiał się raz lub dwa razy dziennie. Wyniki wyszukiwania będą przysyłane na twój e-mail. Ponadto, polecam skonfigurowanie wszystkiego tak, aby skrypt zapisywał plik Excel z wynikami wyszukiwania w folderze Dropbox, co pozwoli ci przeglądać takie pliki z dowolnego miejsca i o dowolnej porze.

Na razie nie znalazłem taryf z błędami, ale sądzę, że jest to możliwe
Podczas wyszukiwania, jak już wspomniano, używana jest „elastyczna data”, skrypt znajduje oferty mieszczące się w trzech dniach od podanych dat. Chociaż przy uruchamianiu skryptu wyszukiwane są oferty tylko w jednym kierunku, łatwo go dostosować, aby mógł zbierać dane dla kilku kierunków lotów. Można nim nawet wyszukiwać błędne taryfy, a takie znaleziska mogą być naprawdę interesujące.
Po co potrzebny jest kolejny web scraper?
Kiedy po raz pierwszy zacząłem zajmować się web scrapingiem, szczerze mówiąc, nie wydawało mi się to zbyt interesujące. Chciałem realizować więcej projektów z zakresu modelowania prognostycznego, analizy finansowej i być może analizy sentymentu tekstów. Okazało się jednak, że jest to bardzo interesujące — zrozumieć, jak stworzyć program, który zbiera dane z witryn internetowych. W miarę zagłębiania się w ten temat zrozumiałem, że to właśnie web scraping jest „silnikiem” internetu.
Możliwe, że uznasz to za zbyt odważne stwierdzenie. Ale pomyśl o tym, że firma Google zaczęła jako web scraper, który Larry Page stworzył używając Javy i Pythona. Roboty Google badały i nadal badają internet, starając się dostarczyć swoim użytkownikom najlepsze odpowiedzi na ich pytania. Web scraping ma niezliczoną ilość zastosowań, a nawet jeśli interesuje Cię coś innego w dziedzinie Data Science, aby pozyskać dane do analizy, potrzebujesz pewnych umiejętności w zakresie scrapingu.
Niektóre z użytych tu metod znalazłem w wspaniałej książce o web scrapingu, którą niedawno nabyłem. Znajdziesz w niej wiele prostych przykładów i pomysłów na praktyczne zastosowanie tego, czego się nauczyłeś. Ponadto jest tam bardzo interesujący rozdział o omijaniu zabezpieczeń reCaptcha. To była dla mnie nowość, ponieważ nie wiedziałem, że istnieją specjalne narzędzia, a nawet całe usługi do rozwiązania podobnych zadań.
Lubisz podróżować?!
Na proste i dość niewinne pytanie, które zostało postawione w tytule tego działu, często można usłyszeć pozytywną odpowiedź, wzbogaconą o kilka historii z podróży osoby, która je usłyszała. Większość z nas zgodzi się, że podróże są wspaniałym sposobem na zanurzenie się w nowe kulturowe środowiska i poszerzenie własnych horyzontów. Jednak jeśli zapytasz kogoś, czy lubi szukać biletów lotniczych, jestem pewien, że odpowiedź na to pytanie nie będzie już tak pozytywna. W rzeczywistości tutaj z pomocą przychodzi Python.
Pierwszym zadaniem, które musimy rozwiązać na drodze do stworzenia systemu przeszukiwania informacji o biletach lotniczych, jest dobór odpowiedniej platformy, z której będziemy pozyskiwać dane. Rozwiązanie tego problemu nie było łatwe, ale ostatecznie wybrałem serwis Kayak. Próbowałem serwisów Momondo, Skyscanner, Expedia i jeszcze kilku innych, ale mechanizmy zabezpieczeń przed botami na tych platformach były nie do pokonania. Po kilku próbach, kiedy próbując przekonać systemy, że jestem człowiekiem, musiałem zmagać się ze światłami, przejściami dla pieszych i rowerami, zdecydowałem, że Kayak najlepiej mi odpowiada, mimo że również tutaj, jeśli w krótkim czasie załadujesz zbyt wiele stron, zaczynają się kontrole. Udało mi się skonfigurować bota tak, aby wysyłał zapytania do serwisu w odstępach 4 do 6 godzin, co działało prawidłowo. Okresowo pojawiają się trudności podczas korzystania z Kayak, ale jeśli zaczynają cię męczyć kontrole, musisz albo poradzić sobie z nimi ręcznie, a następnie uruchomić bota, albo poczekać kilka godzin, a kontrole powinny ustąpić. Możesz, jeśli chcesz, dostosować kod do innej platformy, a jeśli to zrobisz — możesz o tym poinformować w komentarzach.
Jeśli dopiero zaczynasz swoją przygodę z web scrapingiem i nie wiesz, dlaczego niektóre strony internetowe wszelkimi sposobami walczą z nim, to zanim przystąpisz do swojego pierwszego projektu w tej dziedzinie — zrób sobie przysługę i poszukaj w Google materiałów pod hasłem „etykieta web scrapingu”. Twoje eksperymenty mogą zakończyć się szybciej, niż się spodziewasz, jeśli będziesz zajmować się web scrapingiem w nierozważny sposób.
Rozpoczęcie pracy
Oto ogólny przegląd tego, co będzie dziać się w kodzie naszego web scrape'a:
- Importowanie potrzebnych bibliotek.
- Otwieranie karty w Google Chrome.
- Wywołanie funkcji, która uruchamia bota, przekazując mu miasta i daty, które będą używane do wyszukiwania biletów.
- Ta funkcja zdobywa pierwsze wyniki wyszukiwania, posortowane według kryterium największej atrakcyjności (najlepiej), i klika przycisk, aby załadować dodatkowe wyniki.
- Kolejna funkcja zbiera dane z całej strony i zwraca ramkę danych.
- Dwa poprzednie kroki są wykonywane z użyciem typów sortowania według ceny biletów (najtańsze) i według czasu lotu (najszybsze).
- Użytkownik skryptu otrzymuje e-mail z krótkim podsumowaniem cen biletów (najtańsze bilety i średnia cena), a ramka danych zawierająca informacje posortowane według trzech wspomnianych wskaźników jest zapisywana jako plik Excel.
- Wszystkie powyższe działania są wykonywane w pętli w zadanym przedziale czasowym.
Należy zauważyć, że każdy projekt Selenium zaczyna się od sterownika przeglądarki. Używam , współpracuję z Google Chrome, ale są także inne opcje. Popularnością cieszą się jeszcze PhantomJS i Firefox. Po pobraniu sterownika należy go umieścić w odpowiednim folderze, na tym kończy się przygotowanie do jego użycia. W pierwszych linijkach naszego skryptu otwierana jest nowa karta Chrome.
Pamiętaj, że w mojej opowieści nie próbuję odkrywać nowych horyzontów w poszukiwaniu korzystnych ofert na bilety lotnicze. Istnieją znacznie bardziej zaawansowane metody wyszukiwania takich ofert. Chcę jedynie zaproponować czytelnikom tego materiału prostą, ale praktyczną metodę rozwiązania tego zadania.
Oto kod, o którym mówiliśmy wcześniej.
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
# Użyj tutaj swojej ścieżki do chromedrivera!
chromedriver_path = 'C:/{YOUR PATH HERE}/chromedriver_win32/chromedriver.exe'
driver = webdriver.Chrome(executable_path=chromedriver_path) # Ta komenda otwiera okno Chrome
sleep(2) Na początku kodu można zobaczyć polecenia importu pakietów, które są używane w całym naszym projekcie. Tak więc, randint jest używane, aby bot 'zasnął' na losową liczbę sekund przed rozpoczęciem nowej operacji wyszukiwania. Zwykle bez tego nie obędzie się żaden bot. Jeśli uruchomisz powyższy kod, otworzy się okno Chrome, które bot będzie używał do pracy z witrynami.
Przeprowadzimy mały eksperyment i otworzymy w osobnym oknie stronę kayak.com. Wybierzemy miasto, z którego zamierzamy lecieć, oraz miasto, do którego chcemy dotrzeć, a także daty lotu. Wybierając daty, upewnimy się, że używamy zakresu +-3 dni. Napisałem kod, biorąc pod uwagę to, co strona zwraca w odpowiedzi na takie zapytania. Jeśli jednak potrzebujesz np. szukać biletów tylko na wybrane daty, istnieje duże prawdopodobieństwo, że będziesz musiał dostosować kod bota. Opowiadając o kodzie, robię odpowiednie objaśnienia, ale jeśli poczujesz się zagubiony — daj mi znać.
Teraz klikamy przycisk uruchomienia wyszukiwania i patrzymy na link w pasku adresu. Powinien być podobny do linku, którego używam w przykładzie poniżej, gdzie deklarowana jest zmienna kayak, przechowująca URL, i używana jest metoda get web drivera. Po kliknięciu przycisku wyszukiwania na stronie powinny pojawić się wyniki.
![]()
Kiedy użyłem polecenia get więcej niż dwa-trzy razy w ciągu kilku minut, zaproponowano mi przejście weryfikacji przy użyciu reCaptcha. Można przejść tę weryfikację ręcznie i kontynuować eksperymenty, dopóki system nie zdecyduje się na nową weryfikację. Kiedy testowałem skrypt, miałem wrażenie, że pierwsza sesja wyszukiwania zawsze przebiega bez problemów, dlatego jeśli chcesz eksperymentować z kodem, będziesz musiał tylko okazjonalnie przechodzić weryfikację ręcznie i pozostawiać kod do wykonania, używając długich przerw między sesjami wyszukiwania. I tak, jeśli pomyśleć, człowiek raczej nie potrzebuje informacji o cenach biletów uzyskanych przy 10-minutowych przerwach między operacjami wyszukiwania.
Praca ze stroną przy użyciu XPath
Otóż otworzyliśmy okno i załadowaliśmy stronę. Aby uzyskać informacje o cenach i inne dane, musimy skorzystać z technologii XPath lub selektorów CSS. Zdecydowałem się na XPath i nie czułem potrzeby korzystania z selektorów CSS, ale oczywiście można też tak pracować. Poruszanie się po stronie przy użyciu XPath może okazać się trudnym zadaniem, a nawet jeśli skorzystasz z metod, które opisałem w W artykule, w którym stosowano kopiowanie odpowiednich identyfikatorów z kodu strony, zrozumiałem, że to tak naprawdę nieoptymalny sposób odnoszenia się do potrzebnych elementów. Swoją drogą, w książce można znaleźć doskonały opis podstaw pracy ze stronami przy użyciu XPath i selektorów CSS. Oto jak wygląda odpowiednia metoda web drivera.
![]()
Zatem kontynuujemy pracę nad botem. Skorzystamy z możliwości programu do wyszukiwania najtańszych biletów. Na następnym obrazku czerwonym kolorem zaznaczony jest kod selektora XPath. Aby zobaczyć kod, należy kliknąć prawym przyciskiem myszy na interesującym nas elemencie strony i w pojawiającym się menu wybrać opcję Zbadaj element (Inspect). Tę opcję można wywołać dla różnych elementów strony, a kod będzie wyświetlany i zaznaczany w oknie przeglądarki kodu.

Podgląd kodu strony
Aby znaleźć potwierdzenie moich rozważań dotyczących wad kopiowania selektorów z kodu, zwróć uwagę na następujące cechy.
Oto co otrzymujemy przy kopiowaniu kodu:
//*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/spanAby skopiować coś podobnego, należy kliknąć prawym przyciskiem myszy na interesującą nas część kodu i wybrać w pojawiającym się menu opcję Kopiuj > Kopiuj XPath.
Oto co użyłem do określenia przycisku Cheapest:
cheap_results = ‘//a[@data-code = "price"]’ 
Opcja Kopiuj > Kopiuj XPath
Jest oczywiste, że drugi wariant wygląda znacznie prościej. Przy jego użyciu odbywa się wyszukiwanie elementu a, który ma atrybut data-code, równy cena. Przy użyciu pierwszego wariantu następuje wyszukiwanie elementu, id którego wartość to wtKI-price_aTab, przy czym ścieżka XPath do elementu wygląda jak /div[1]/div/div/div[1]/div/span/span. Taki zapytanie XPath do strony wykona swoją robotę, ale — tylko raz. Mogę powiedzieć, że id zmieni się przy następnym ładowaniu strony. Ciąg znaków wtKI dynamicznie zmienia się przy każdym ładowaniu strony, w wyniku czego kod, w którym jest używany, po kolejnym przeładowaniu strony stanie się bezużyteczny. Dlatego poświęć trochę czasu na zrozumienie XPath. Ta wiedza dobrze ci służy.
Należy jednak zauważyć, że kopiowanie selektorów XPath może być przydatne w pracy z dość prostymi stronami, a jeśli ci to odpowiada, nie ma w tym nic złego.
Teraz zastanówmy się nad tym, jak uzyskać wszystkie wyniki wyszukiwania w kilku wierszach, w liście. To bardzo proste. Każdy wynik znajduje się w obiekcie o klasie resultWrapper. Ładowanie wszystkich wyników można zrealizować w pętli, przypominającej tę, która zostanie przedstawiona poniżej.
Należy zauważyć, że jeśli zrozumiałeś powyższe, powinieneś bez problemu zrozumieć większość kodu, który będziemy omawiać. W trakcie działania tego kodu, do elementu, który nas interesuje (w rzeczywistości jest to element, w którym osadzone są wyniki), odnosimy się za pomocą pewnego mechanizmu wskazania ścieżki (XPath). Robi się to, aby uzyskać tekst elementu i umieścić go w obiekcie, z którego można odczytać dane (najpierw używana jest flight_containers, następnie — flights_list).

Wynikają pierwsze trzy wiersze i możemy jasno zobaczyć wszystko, czego potrzebujemy. Mamy jednak również ciekawsze sposoby pozyskiwania informacji. Musimy pobierać dane z każdego elementu osobno.
Do pracy!
Najłatwiej jest napisać funkcję do ładowania dodatkowych wyników, więc od niej zaczniemy. Chciałbym zmaksymalizować liczbę lotów, informacje o których program zbiera, a jednocześnie nie wzbudzać podejrzeń u usługi prowadzących do sprawdzenia, dlatego co jakiś czas klikam przycisk Załaduj więcej wyników, za każdym razem, gdy pojawia się strona. W tym kodzie należy zwrócić uwagę na blok try, który dodałem, ponieważ czasami przycisk nie ładuje się poprawnie. Jeśli również się z tym spotkasz — zakomentuj wywołania tej funkcji w kodzie funkcji start_kayak, którą omówimy poniżej.
# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
def load_more():
try:
more_results = '//a[@class = "moreButton"]'
driver.find_element_by_xpath(more_results).click()
# Вывод этих заметок в ходе работы программы помогает мне быстро выяснить то, чем она занята
print('sleeping.....')
sleep(randint(45,60))
except:
passTeraz, po długim omówieniu tej funkcji (czasami mogę być zbyt zapalony), jesteśmy gotowi do ogłoszenia funkcji, która będzie zajmować się skrobankiem strony.
Już zebrałem większość tego, co potrzebne, w następnej funkcji, zwanej page_scrape. Czasami zwracane dane o etapach drogi okazują się połączone, aby je rozdzielić, używam prostego metody. Na przykład, gdy pierwszy raz korzystam z zmiennych section_a_list i section_b_list. Nasza funkcja zwraca ramkę danych flights_df, co pozwala nam podzielić wyniki uzyskane przy użyciu różnych metod sortowania danych, a później — połączyć je.
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 Starałem się nazywać zmienne w sposób, który sprawi, że kod będzie zrozumiały. Pamiętaj, że zmienne zaczynające się od a należą do pierwszego etapu ścieżki, a b — do drugiego. Przechodzimy do następnej funkcji.
Mechanizmy pomocnicze
Teraz mamy funkcję, która pozwala na ładowanie dodatkowych wyników wyszukiwania oraz funkcję do przetwarzania tych wyników. Artykuł ten mógłby zakończyć się na tym, ponieważ te dwie funkcje zapewniają wszystko, co potrzebne do skrobania stron, które można otworzyć samodzielnie. Ale jak dotąd nie omówiliśmy niektórych mechanizmów pomocniczych, o których wspomnieliśmy wcześniej. Na przykład — to kod do wysyłania wiadomości e-mail i kilka innych rzeczy. Wszystko to można znaleźć w funkcji start_kayak, którą teraz rozważymy.
Aby ta funkcja działała, potrzebne są informacje o miastach i datach. Wykorzystując te dane, generuje link w zmiennej kayak, który jest używany do przejścia na stronę, na której znajdą się wyniki wyszukiwania, posortowane według najlepszego dopasowania do zapytania. Po pierwszej sesji skrobania zajmiemy się cenami znajdującymi się w tabeli na górze strony. A mianowicie, znajdziemy minimalną cenę biletu oraz średnią cenę. Wszystko to, razem z przewidywaniem dostarczanym przez stronę, zostanie wysłane e-mailem. Na stronie odpowiednia tabela powinna być w lewym górnym rogu. Praca z tą tabelą, nawiasem mówiąc, może spowodować błąd podczas wyszukiwania z wykorzystaniem dokładnych dat, ponieważ w takim przypadku tabela na stronie nie jest wyświetlana.
def start_kayak(city_from, city_to, date_start, date_end):
"""Kody miast - to kody IATA!
Format daty - 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))
# Czasami pojawia się okno wyskakujące; możesz użyć blok try, aby to sprawdzić i zamknąć
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('ładowanie więcej.....')
# load_more()
print('rozpoczynanie pierwszego skanowania.....')
df_flights_best = page_scrape()
df_flights_best['sort'] = 'najlepsze'
sleep(randint(60,80))
# Weźmiemy najniższą cenę z tabeli, znajdującej się na górze strony
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('przełączanie na najtańsze wyniki.....')
cheap_results = '//*[@data-code = "price"]'
driver.find_element_by_xpath(cheap_results).click()
sleep(randint(60,90))
print('ładowanie więcej.....')
# load_more()
print('rozpoczynanie drugiego skanowania.....')
df_flights_cheap = page_scrape()
df_flights_cheap['sort'] = 'tanio'
sleep(randint(60,80))
print('przełączanie na najszybsze wyniki.....')
quick_results = '//*[@data-code = "duration"]'
driver.find_element_by_xpath(quick_results).click()
sleep(randint(60,90))
print('ładowanie więcej.....')
# load_more()
print('rozpoczynanie trzeciego skanowania.....')
df_flights_fast = page_scrape()
df_flights_fast['sort'] = 'szybko'
sleep(randint(60,80))
# Zapisz nową ramkę w pliku Excel, a jej nazwa odzwierciedla miasta i daty
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('zapisano df.....')
# Można obserwować, jak prognoza wydawana przez stronę odnosi się do rzeczywistości
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)
# Czasami zmienna loading zawiera ten ciąg, co później powoduje problemy z wysyłaniem e-maili
# Jeśli tak się zdarzyło - zmieniamy go na "Niepewne"
weird = '¯_(ツ)_/¯'
if loading == weird:
loading = 'Niepewne'
username = 'YOUREMAIL@hotmail.com'
password = 'YOUR PASSWORD'
server = smtplib.SMTP('smtp.outlook.com', 587)
server.ehlo()
server.starttls()
server.login(username, password)
msg = ('Temat: Flight Scrapernn
Najtańszy lot: {}nŚrednia cena: {}nnRekomendacja: {}nnKoniec wiadomości'.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('wysłano e-mail.....')Przetestowałem ten skrypt, korzystając z konta Outlook (hotmail.com). Nie sprawdzałem jego działania z kontem Gmail, który jest bardzo popularny, ale jest wiele różnych możliwości. Jeśli używasz konta Hotmail, wystarczy, że wprowadzisz swoje dane w kodzie, aby wszystko działało.
Jeśli chcesz zrozumieć, co dokładnie wykonuje się w poszczególnych fragmentach kodu tej funkcji, możesz je skopiować i eksperymentować z nimi. Eksperymentowanie z kodem to jedyny sposób, aby go naprawdę zrozumieć.
Gotowy system
Teraz, gdy zrobiliśmy wszystko, o czym mówiliśmy, możemy stworzyć prostą pętlę, w której wywołujemy nasze funkcje. Skrypt prosi użytkownika o dane dotyczące miast i dat. Podczas testowania z ciągłym uruchamianiem skryptu, mało prawdopodobne jest, że będziesz chciał za każdym razem wprowadzać te dane ręcznie, dlatego odpowiednie linie można zakomentować, odkomentowując te, które są poniżej i w których są sztywno przypisane potrzebne dane.
city_from = input('Z którego miasta? ')
city_to = input('Dokąd? ')
date_start = input('Szukaj w okolicach której daty wyjazdu? Proszę używać tylko formatu YYYY-MM-DD ')
date_end = input('Kiedy wrócić? Proszę używać tylko formatu 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('iteracja {} została zakończona @ {}'.format(n, strftime("%Y%m%d-%H%M")))
# Czekamy 4 godziny
sleep(60*60*4)
print('czekanie zakończone.....') Oto jak wygląda testowe uruchomienie skryptu.

Testowe uruchomienie skryptu
Podsumowanie
Jeśli dotarłeś do tego momentu, gratulacje! Teraz masz działającego web scrapera, chociaż już widzę wiele sposobów na jego ulepszenie. Na przykład, można zintegrować go z Twilio, aby zamiast e-maili wysyłał wiadomości tekstowe. Można użyć VPN lub czegoś innego, aby jednocześnie uzyskiwać wyniki z kilku serwerów. Jest również okresowo występujący problem z weryfikacją, czy użytkownik strony jest człowiekiem, ale i ten problem można rozwiązać. W każdym razie, teraz masz bazę, którą możesz, jeśli chcesz, rozwijać. Na przykład, możesz rozwiązanie tak, aby plik Excel był wysyłany użytkownikowi jako załącznik do e-maila.
Tylko zarejestrowani użytkownicy mogą brać udział w ankiecie. , proszę.
Czy korzystasz z technologii web scrapingu?
Tak
Nie
8 użytkowników zagłosowało. 1 użytkownik wstrzymał się od głosu.
Źródło: habr.com
