diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9d21dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +## My IDE + +.idea/ + +## Python .gitignore template from GitHub + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/1/main.py b/1/main.py deleted file mode 100644 index 2472655..0000000 --- a/1/main.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -from selenium import webdriver - -os.environ['PATH'] += r"C:/SeleniumDrivers" -driver = webdriver.Chrome() -driver.get("https://www.seleniumeasy.com/test/jquery-download-progress-bar-demo.html") -driver.implicitly_wait(30) -my_element = driver.find_element_by_id('downloadButton') -my_element.click() \ No newline at end of file diff --git a/2/main.py b/2/main.py deleted file mode 100644 index 6ddba56..0000000 --- a/2/main.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC - - -os.environ['PATH'] += r"C:/SeleniumDrivers" -driver = webdriver.Chrome() -driver.get("https://www.seleniumeasy.com/test/jquery-download-progress-bar-demo.html") -driver.implicitly_wait(8) -my_element = driver.find_element_by_id('downloadButton') -my_element.click() - -WebDriverWait(driver, 30).until( - EC.text_to_be_present_in_element( - (By.CLASS_NAME, 'progress-label') , # Element filtration - 'Complete!'# The expected text - ) -) \ No newline at end of file diff --git a/3/main.py b/3/main.py deleted file mode 100644 index 9c1d921..0000000 --- a/3/main.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -from selenium import webdriver -from selenium.webdriver.common.keys import Keys - -os.environ['PATH'] += r"C:/SeleniumDrivers" -driver = webdriver.Chrome() - -driver.get('https://www.seleniumeasy.com/test/basic-first-form-demo.html') -driver.implicitly_wait(5) -try: - no_button = driver.find_element_by_class_name('at-cm-no-button') - no_button.click() -except: - print('No element with this class name. Skipping ....') - -sum1 = driver.find_element_by_id('sum1') -sum2 = driver.find_element_by_id('sum2') - -sum1.send_keys(Keys.NUMPAD1, Keys.NUMPAD5) -sum2.send_keys(15) - -btn = driver.find_element_by_css_selector('button[onclick="return total()"]') -btn.click() \ No newline at end of file diff --git a/Bot Project/04 - Structure a Bot Project/booking/booking.py b/Bot Project/04 - Structure a Bot Project/booking/booking.py deleted file mode 100644 index 609929d..0000000 --- a/Bot Project/04 - Structure a Bot Project/booking/booking.py +++ /dev/null @@ -1,19 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver - - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - super(Booking, self).__init__() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) diff --git a/Bot Project/04 - Structure a Bot Project/booking/constants.py b/Bot Project/04 - Structure a Bot Project/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/04 - Structure a Bot Project/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/04 - Structure a Bot Project/run.py b/Bot Project/04 - Structure a Bot Project/run.py deleted file mode 100644 index 3b05541..0000000 --- a/Bot Project/04 - Structure a Bot Project/run.py +++ /dev/null @@ -1,6 +0,0 @@ -from booking.booking import Booking - - -with Booking() as bot: - bot.land_first_page() - diff --git a/Bot Project/05 - Deal Searching Part 1/booking/__init__.py b/Bot Project/05 - Deal Searching Part 1/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/05 - Deal Searching Part 1/booking/booking.py b/Bot Project/05 - Deal Searching Part 1/booking/booking.py deleted file mode 100644 index ead8325..0000000 --- a/Bot Project/05 - Deal Searching Part 1/booking/booking.py +++ /dev/null @@ -1,43 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver - - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - super(Booking, self).__init__() - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() diff --git a/Bot Project/05 - Deal Searching Part 1/booking/constants.py b/Bot Project/05 - Deal Searching Part 1/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/05 - Deal Searching Part 1/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/05 - Deal Searching Part 1/run.py b/Bot Project/05 - Deal Searching Part 1/run.py deleted file mode 100644 index 0400fc3..0000000 --- a/Bot Project/05 - Deal Searching Part 1/run.py +++ /dev/null @@ -1,7 +0,0 @@ -from booking.booking import Booking - - -with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go('New York') diff --git a/Bot Project/06 - Deal Searching Part 2/booking/__init__.py b/Bot Project/06 - Deal Searching Part 2/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/06 - Deal Searching Part 2/booking/booking.py b/Bot Project/06 - Deal Searching Part 2/booking/booking.py deleted file mode 100644 index bcf8a15..0000000 --- a/Bot Project/06 - Deal Searching Part 2/booking/booking.py +++ /dev/null @@ -1,88 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver -from booking.booking_filtration import BookingFiltration - - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - super(Booking, self).__init__() - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() - - def select_dates(self, check_in_date, check_out_date): - check_in_element = self.find_element_by_css_selector( - f'td[data-date="{check_in_date}"]' - ) - check_in_element.click() - - check_out_element = self.find_element_by_css_selector( - f'td[data-date="{check_out_date}"]' - ) - check_out_element.click() - - def select_adults(self, count=1): - selection_element = self.find_element_by_id('xp__guests__toggle') - selection_element.click() - - while True: - decrease_adults_element = self.find_element_by_css_selector( - 'button[aria-label="Decrease number of Adults"]' - ) - decrease_adults_element.click() - #If the value of adults reaches 1, then we should get out - #of the while loop - adults_value_element = self.find_element_by_id('group_adults') - adults_value = adults_value_element.get_attribute( - 'value' - ) # Should give back the adults count - - if int(adults_value) == 1: - break - - increase_button_element = self.find_element_by_css_selector( - 'button[aria-label="Increase number of Adults"]' - ) - - for _ in range(count - 1): - increase_button_element.click() - - def click_search(self): - search_button = self.find_element_by_css_selector( - 'button[type="submit"]' - ) - search_button.click() - diff --git a/Bot Project/06 - Deal Searching Part 2/booking/constants.py b/Bot Project/06 - Deal Searching Part 2/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/06 - Deal Searching Part 2/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/06 - Deal Searching Part 2/run.py b/Bot Project/06 - Deal Searching Part 2/run.py deleted file mode 100644 index 6801fcc..0000000 --- a/Bot Project/06 - Deal Searching Part 2/run.py +++ /dev/null @@ -1,12 +0,0 @@ -from booking.booking import Booking - - -with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go('New York') - bot.select_dates(check_in_date='2021-05-19', - check_out_date='2021-05-25') - bot.select_adults(1) - bot.click_search() - diff --git a/Bot Project/07 - Booking Filtrations/booking/__init__.py b/Bot Project/07 - Booking Filtrations/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-38.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 55b93e9..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-39.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 0d5aa5a..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-38.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-38.pyc deleted file mode 100644 index e113d35..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-39.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-39.pyc deleted file mode 100644 index 9c264d7..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking_filtration.cpython-38.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking_filtration.cpython-38.pyc deleted file mode 100644 index ea80929..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/booking_filtration.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-38.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-38.pyc deleted file mode 100644 index 16e8a32..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-39.pyc b/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-39.pyc deleted file mode 100644 index c359792..0000000 Binary files a/Bot Project/07 - Booking Filtrations/booking/__pycache__/constants.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/07 - Booking Filtrations/booking/booking.py b/Bot Project/07 - Booking Filtrations/booking/booking.py deleted file mode 100644 index e6ce8b7..0000000 --- a/Bot Project/07 - Booking Filtrations/booking/booking.py +++ /dev/null @@ -1,94 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver -from booking.booking_filtration import BookingFiltration - - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - super(Booking, self).__init__() - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() - - def select_dates(self, check_in_date, check_out_date): - check_in_element = self.find_element_by_css_selector( - f'td[data-date="{check_in_date}"]' - ) - check_in_element.click() - - check_out_element = self.find_element_by_css_selector( - f'td[data-date="{check_out_date}"]' - ) - check_out_element.click() - - def select_adults(self, count=1): - selection_element = self.find_element_by_id('xp__guests__toggle') - selection_element.click() - - while True: - decrease_adults_element = self.find_element_by_css_selector( - 'button[aria-label="Decrease number of Adults"]' - ) - decrease_adults_element.click() - #If the value of adults reaches 1, then we should get out - #of the while loop - adults_value_element = self.find_element_by_id('group_adults') - adults_value = adults_value_element.get_attribute( - 'value' - ) # Should give back the adults count - - if int(adults_value) == 1: - break - - increase_button_element = self.find_element_by_css_selector( - 'button[aria-label="Increase number of Adults"]' - ) - - for _ in range(count - 1): - increase_button_element.click() - - def click_search(self): - search_button = self.find_element_by_css_selector( - 'button[type="submit"]' - ) - search_button.click() - - def apply_filtrations(self): - filtration = BookingFiltration(driver=self) - filtration.apply_star_rating(4, 5) - - filtration.sort_price_lowest_first() - diff --git a/Bot Project/07 - Booking Filtrations/booking/booking_filtration.py b/Bot Project/07 - Booking Filtrations/booking/booking_filtration.py deleted file mode 100644 index e352aba..0000000 --- a/Bot Project/07 - Booking Filtrations/booking/booking_filtration.py +++ /dev/null @@ -1,24 +0,0 @@ -#This file will include a class with instance methods. -#That will be responsible to interact with our website -#After we have some results, to apply filtrations. -from selenium.webdriver.remote.webdriver import WebDriver - -class BookingFiltration: - def __init__(self, driver:WebDriver): - self.driver = driver - - def apply_star_rating(self, *star_values): - star_filtration_box = self.driver.find_element_by_id('filter_class') - star_child_elements = star_filtration_box.find_elements_by_css_selector('*') - - for star_value in star_values: - for star_element in star_child_elements: - if str(star_element.get_attribute('innerHTML')).strip() == f'{star_value} stars': - star_element.click() - - - def sort_price_lowest_first(self): - element = self.driver.find_element_by_css_selector( - 'li[data-id="price"]' - ) - element.click() \ No newline at end of file diff --git a/Bot Project/07 - Booking Filtrations/booking/constants.py b/Bot Project/07 - Booking Filtrations/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/07 - Booking Filtrations/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/07 - Booking Filtrations/run.py b/Bot Project/07 - Booking Filtrations/run.py deleted file mode 100644 index a1c52bb..0000000 --- a/Bot Project/07 - Booking Filtrations/run.py +++ /dev/null @@ -1,13 +0,0 @@ -from booking.booking import Booking - - -with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go('New York') - bot.select_dates(check_in_date='2021-05-19', - check_out_date='2021-05-25') - bot.select_adults(1) - bot.click_search() - bot.apply_filtrations() - diff --git a/Bot Project/08 - Execution from a CLI/booking/__init__.py b/Bot Project/08 - Execution from a CLI/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-38.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 55b93e9..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-39.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 0d5aa5a..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-38.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-38.pyc deleted file mode 100644 index 75b1975..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-39.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-39.pyc deleted file mode 100644 index 9c264d7..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking_filtration.cpython-38.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking_filtration.cpython-38.pyc deleted file mode 100644 index ea80929..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/booking_filtration.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-38.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-38.pyc deleted file mode 100644 index 16e8a32..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-39.pyc b/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-39.pyc deleted file mode 100644 index c359792..0000000 Binary files a/Bot Project/08 - Execution from a CLI/booking/__pycache__/constants.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/08 - Execution from a CLI/booking/booking.py b/Bot Project/08 - Execution from a CLI/booking/booking.py deleted file mode 100644 index 795c461..0000000 --- a/Bot Project/08 - Execution from a CLI/booking/booking.py +++ /dev/null @@ -1,96 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver -from booking.booking_filtration import BookingFiltration - - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - options = webdriver.ChromeOptions() - options.add_experimental_option('excludeSwitches', ['enable-logging']) - super(Booking, self).__init__(options=options) - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() - - def select_dates(self, check_in_date, check_out_date): - check_in_element = self.find_element_by_css_selector( - f'td[data-date="{check_in_date}"]' - ) - check_in_element.click() - - check_out_element = self.find_element_by_css_selector( - f'td[data-date="{check_out_date}"]' - ) - check_out_element.click() - - def select_adults(self, count=1): - selection_element = self.find_element_by_id('xp__guests__toggle') - selection_element.click() - - while True: - decrease_adults_element = self.find_element_by_css_selector( - 'button[aria-label="Decrease number of Adults"]' - ) - decrease_adults_element.click() - #If the value of adults reaches 1, then we should get out - #of the while loop - adults_value_element = self.find_element_by_id('group_adults') - adults_value = adults_value_element.get_attribute( - 'value' - ) # Should give back the adults count - - if int(adults_value) == 1: - break - - increase_button_element = self.find_element_by_css_selector( - 'button[aria-label="Increase number of Adults"]' - ) - - for _ in range(count - 1): - increase_button_element.click() - - def click_search(self): - search_button = self.find_element_by_css_selector( - 'button[type="submit"]' - ) - search_button.click() - - def apply_filtrations(self): - filtration = BookingFiltration(driver=self) - filtration.apply_star_rating(4, 5) - - filtration.sort_price_lowest_first() - diff --git a/Bot Project/08 - Execution from a CLI/booking/booking_filtration.py b/Bot Project/08 - Execution from a CLI/booking/booking_filtration.py deleted file mode 100644 index e352aba..0000000 --- a/Bot Project/08 - Execution from a CLI/booking/booking_filtration.py +++ /dev/null @@ -1,24 +0,0 @@ -#This file will include a class with instance methods. -#That will be responsible to interact with our website -#After we have some results, to apply filtrations. -from selenium.webdriver.remote.webdriver import WebDriver - -class BookingFiltration: - def __init__(self, driver:WebDriver): - self.driver = driver - - def apply_star_rating(self, *star_values): - star_filtration_box = self.driver.find_element_by_id('filter_class') - star_child_elements = star_filtration_box.find_elements_by_css_selector('*') - - for star_value in star_values: - for star_element in star_child_elements: - if str(star_element.get_attribute('innerHTML')).strip() == f'{star_value} stars': - star_element.click() - - - def sort_price_lowest_first(self): - element = self.driver.find_element_by_css_selector( - 'li[data-id="price"]' - ) - element.click() \ No newline at end of file diff --git a/Bot Project/08 - Execution from a CLI/booking/constants.py b/Bot Project/08 - Execution from a CLI/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/08 - Execution from a CLI/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/08 - Execution from a CLI/run.py b/Bot Project/08 - Execution from a CLI/run.py deleted file mode 100644 index 00785da..0000000 --- a/Bot Project/08 - Execution from a CLI/run.py +++ /dev/null @@ -1,25 +0,0 @@ -from booking.booking import Booking - -try: - with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go('New York') - bot.select_dates(check_in_date='2021-05-19', - check_out_date='2021-05-25') - bot.select_adults(1) - bot.click_search() - bot.apply_filtrations() - -except Exception as e: - if 'in PATH' in str(e): - print( - 'You are trying to run the bot from command line \n' - 'Please add to PATH your Selenium Drivers \n' - 'Windows: \n' - ' set PATH=%PATH%;C:path-to-your-folder \n \n' - 'Linux: \n' - ' PATH=$PATH:/path/toyour/folder/ \n' - ) - else: - raise \ No newline at end of file diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__init__.py b/Bot Project/09 - Deal Reporting Part 1/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-38.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 55b93e9..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-39.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 0d5aa5a..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-38.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-38.pyc deleted file mode 100644 index efe4bcb..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-39.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-39.pyc deleted file mode 100644 index 9c264d7..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_filtration.cpython-38.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_filtration.cpython-38.pyc deleted file mode 100644 index ea80929..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_filtration.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_report.cpython-38.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_report.cpython-38.pyc deleted file mode 100644 index 285ffb7..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/booking_report.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-38.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-38.pyc deleted file mode 100644 index 16e8a32..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-39.pyc b/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-39.pyc deleted file mode 100644 index c359792..0000000 Binary files a/Bot Project/09 - Deal Reporting Part 1/booking/__pycache__/constants.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/booking.py b/Bot Project/09 - Deal Reporting Part 1/booking/booking.py deleted file mode 100644 index f3eb503..0000000 --- a/Bot Project/09 - Deal Reporting Part 1/booking/booking.py +++ /dev/null @@ -1,103 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver -from booking.booking_filtration import BookingFiltration -from booking.booking_report import BookingReport - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - options = webdriver.ChromeOptions() - options.add_experimental_option('excludeSwitches', ['enable-logging']) - super(Booking, self).__init__(options=options) - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() - - def select_dates(self, check_in_date, check_out_date): - check_in_element = self.find_element_by_css_selector( - f'td[data-date="{check_in_date}"]' - ) - check_in_element.click() - - check_out_element = self.find_element_by_css_selector( - f'td[data-date="{check_out_date}"]' - ) - check_out_element.click() - - def select_adults(self, count=1): - selection_element = self.find_element_by_id('xp__guests__toggle') - selection_element.click() - - while True: - decrease_adults_element = self.find_element_by_css_selector( - 'button[aria-label="Decrease number of Adults"]' - ) - decrease_adults_element.click() - #If the value of adults reaches 1, then we should get out - #of the while loop - adults_value_element = self.find_element_by_id('group_adults') - adults_value = adults_value_element.get_attribute( - 'value' - ) # Should give back the adults count - - if int(adults_value) == 1: - break - - increase_button_element = self.find_element_by_css_selector( - 'button[aria-label="Increase number of Adults"]' - ) - - for _ in range(count - 1): - increase_button_element.click() - - def click_search(self): - search_button = self.find_element_by_css_selector( - 'button[type="submit"]' - ) - search_button.click() - - def apply_filtrations(self): - filtration = BookingFiltration(driver=self) - filtration.apply_star_rating(4, 5) - - filtration.sort_price_lowest_first() - - def report_results(self): - hotel_boxes = self.find_element_by_id( - 'hotellist_inner' - ) - - report = BookingReport(hotel_boxes) - report.pull_titles() \ No newline at end of file diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/booking_filtration.py b/Bot Project/09 - Deal Reporting Part 1/booking/booking_filtration.py deleted file mode 100644 index e352aba..0000000 --- a/Bot Project/09 - Deal Reporting Part 1/booking/booking_filtration.py +++ /dev/null @@ -1,24 +0,0 @@ -#This file will include a class with instance methods. -#That will be responsible to interact with our website -#After we have some results, to apply filtrations. -from selenium.webdriver.remote.webdriver import WebDriver - -class BookingFiltration: - def __init__(self, driver:WebDriver): - self.driver = driver - - def apply_star_rating(self, *star_values): - star_filtration_box = self.driver.find_element_by_id('filter_class') - star_child_elements = star_filtration_box.find_elements_by_css_selector('*') - - for star_value in star_values: - for star_element in star_child_elements: - if str(star_element.get_attribute('innerHTML')).strip() == f'{star_value} stars': - star_element.click() - - - def sort_price_lowest_first(self): - element = self.driver.find_element_by_css_selector( - 'li[data-id="price"]' - ) - element.click() \ No newline at end of file diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/booking_report.py b/Bot Project/09 - Deal Reporting Part 1/booking/booking_report.py deleted file mode 100644 index 40b3599..0000000 --- a/Bot Project/09 - Deal Reporting Part 1/booking/booking_report.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file is going to include method that will parse -# The specific data that we need from each one of the deal boxes. -from selenium.webdriver.remote.webelement import WebElement - - -class BookingReport: - def __init__(self, boxes_section_element:WebElement): - self.boxes_section_element = boxes_section_element - self.deal_boxes = self.pull_deal_boxes() - - def pull_deal_boxes(self): - return self.boxes_section_element.find_elements_by_class_name( - 'sr_property_block' - ) - - def pull_titles(self): - for deal_box in self.deal_boxes: - hotel_name = deal_box.find_element_by_class_name( - 'sr-hotel__name' - ).get_attribute('innerHTML').strip() - print(hotel_name) \ No newline at end of file diff --git a/Bot Project/09 - Deal Reporting Part 1/booking/constants.py b/Bot Project/09 - Deal Reporting Part 1/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/09 - Deal Reporting Part 1/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/09 - Deal Reporting Part 1/run.py b/Bot Project/09 - Deal Reporting Part 1/run.py deleted file mode 100644 index b1754fc..0000000 --- a/Bot Project/09 - Deal Reporting Part 1/run.py +++ /dev/null @@ -1,27 +0,0 @@ -from booking.booking import Booking - -try: - with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go('New York') - bot.select_dates(check_in_date='2021-05-19', - check_out_date='2021-05-25') - bot.select_adults(1) - bot.click_search() - bot.apply_filtrations() - bot.refresh() # A workaround to let our bot to grab the data properly - bot.report_results() - -except Exception as e: - if 'in PATH' in str(e): - print( - 'You are trying to run the bot from command line \n' - 'Please add to PATH your Selenium Drivers \n' - 'Windows: \n' - ' set PATH=%PATH%;C:path-to-your-folder \n \n' - 'Linux: \n' - ' PATH=$PATH:/path/toyour/folder/ \n' - ) - else: - raise \ No newline at end of file diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__init__.py b/Bot Project/10 - Deal Reporting Part 2/booking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-38.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 55b93e9..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-39.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 0d5aa5a..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-38.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-38.pyc deleted file mode 100644 index f344689..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-39.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-39.pyc deleted file mode 100644 index 9c264d7..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_filtration.cpython-38.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_filtration.cpython-38.pyc deleted file mode 100644 index ea80929..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_filtration.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_report.cpython-38.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_report.cpython-38.pyc deleted file mode 100644 index dd8a593..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/booking_report.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-38.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-38.pyc deleted file mode 100644 index 16e8a32..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-38.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-39.pyc b/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-39.pyc deleted file mode 100644 index c359792..0000000 Binary files a/Bot Project/10 - Deal Reporting Part 2/booking/__pycache__/constants.cpython-39.pyc and /dev/null differ diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/booking.py b/Bot Project/10 - Deal Reporting Part 2/booking/booking.py deleted file mode 100644 index 041fdca..0000000 --- a/Bot Project/10 - Deal Reporting Part 2/booking/booking.py +++ /dev/null @@ -1,108 +0,0 @@ -import booking.constants as const -import os -from selenium import webdriver -from booking.booking_filtration import BookingFiltration -from booking.booking_report import BookingReport -from prettytable import PrettyTable - -class Booking(webdriver.Chrome): - def __init__(self, driver_path=r"C:\SeleniumDrivers", - teardown=False): - self.driver_path = driver_path - self.teardown = teardown - os.environ['PATH'] += self.driver_path - options = webdriver.ChromeOptions() - options.add_experimental_option('excludeSwitches', ['enable-logging']) - super(Booking, self).__init__(options=options) - self.implicitly_wait(15) - self.maximize_window() - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.teardown: - self.quit() - - def land_first_page(self): - self.get(const.BASE_URL) - - def change_currency(self, currency=None): - currency_element = self.find_element_by_css_selector( - 'button[data-tooltip-text="Choose your currency"]' - ) - currency_element.click() - - selected_currency_element = self.find_element_by_css_selector( - f'a[data-modal-header-async-url-param*="selected_currency={currency}"]' - ) - selected_currency_element.click() - - - def select_place_to_go(self, place_to_go): - search_field = self.find_element_by_id('ss') - search_field.clear() - search_field.send_keys(place_to_go) - - first_result = self.find_element_by_css_selector( - 'li[data-i="0"]' - ) - first_result.click() - - def select_dates(self, check_in_date, check_out_date): - check_in_element = self.find_element_by_css_selector( - f'td[data-date="{check_in_date}"]' - ) - check_in_element.click() - - check_out_element = self.find_element_by_css_selector( - f'td[data-date="{check_out_date}"]' - ) - check_out_element.click() - - def select_adults(self, count=1): - selection_element = self.find_element_by_id('xp__guests__toggle') - selection_element.click() - - while True: - decrease_adults_element = self.find_element_by_css_selector( - 'button[aria-label="Decrease number of Adults"]' - ) - decrease_adults_element.click() - #If the value of adults reaches 1, then we should get out - #of the while loop - adults_value_element = self.find_element_by_id('group_adults') - adults_value = adults_value_element.get_attribute( - 'value' - ) # Should give back the adults count - - if int(adults_value) == 1: - break - - increase_button_element = self.find_element_by_css_selector( - 'button[aria-label="Increase number of Adults"]' - ) - - for _ in range(count - 1): - increase_button_element.click() - - def click_search(self): - search_button = self.find_element_by_css_selector( - 'button[type="submit"]' - ) - search_button.click() - - def apply_filtrations(self): - filtration = BookingFiltration(driver=self) - filtration.apply_star_rating(4, 5) - - filtration.sort_price_lowest_first() - - def report_results(self): - hotel_boxes = self.find_element_by_id( - 'hotellist_inner' - ) - - report = BookingReport(hotel_boxes) - table = PrettyTable( - field_names=["Hotel Name", "Hotel Price", "Hotel Score"] - ) - table.add_rows(report.pull_deal_box_attributes()) - print(table) \ No newline at end of file diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/booking_filtration.py b/Bot Project/10 - Deal Reporting Part 2/booking/booking_filtration.py deleted file mode 100644 index e352aba..0000000 --- a/Bot Project/10 - Deal Reporting Part 2/booking/booking_filtration.py +++ /dev/null @@ -1,24 +0,0 @@ -#This file will include a class with instance methods. -#That will be responsible to interact with our website -#After we have some results, to apply filtrations. -from selenium.webdriver.remote.webdriver import WebDriver - -class BookingFiltration: - def __init__(self, driver:WebDriver): - self.driver = driver - - def apply_star_rating(self, *star_values): - star_filtration_box = self.driver.find_element_by_id('filter_class') - star_child_elements = star_filtration_box.find_elements_by_css_selector('*') - - for star_value in star_values: - for star_element in star_child_elements: - if str(star_element.get_attribute('innerHTML')).strip() == f'{star_value} stars': - star_element.click() - - - def sort_price_lowest_first(self): - element = self.driver.find_element_by_css_selector( - 'li[data-id="price"]' - ) - element.click() \ No newline at end of file diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/booking_report.py b/Bot Project/10 - Deal Reporting Part 2/booking/booking_report.py deleted file mode 100644 index aedb64a..0000000 --- a/Bot Project/10 - Deal Reporting Part 2/booking/booking_report.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file is going to include method that will parse -# The specific data that we need from each one of the deal boxes. -from selenium.webdriver.remote.webelement import WebElement - - -class BookingReport: - def __init__(self, boxes_section_element:WebElement): - self.boxes_section_element = boxes_section_element - self.deal_boxes = self.pull_deal_boxes() - - def pull_deal_boxes(self): - return self.boxes_section_element.find_elements_by_class_name( - 'sr_property_block' - ) - - def pull_deal_box_attributes(self): - collection = [] - for deal_box in self.deal_boxes: - # Pulling the hotel name - hotel_name = deal_box.find_element_by_class_name( - 'sr-hotel__name' - ).get_attribute('innerHTML').strip() - hotel_price = deal_box.find_element_by_class_name( - 'bui-price-display__value' - ).get_attribute('innerHTML').strip() - hotel_score = deal_box.get_attribute( - 'data-score' - ).strip() - - collection.append( - [hotel_name, hotel_price, hotel_score] - ) - return collection \ No newline at end of file diff --git a/Bot Project/10 - Deal Reporting Part 2/booking/constants.py b/Bot Project/10 - Deal Reporting Part 2/booking/constants.py deleted file mode 100644 index 5ea7013..0000000 --- a/Bot Project/10 - Deal Reporting Part 2/booking/constants.py +++ /dev/null @@ -1 +0,0 @@ -BASE_URL = "https://www.booking.com" \ No newline at end of file diff --git a/Bot Project/10 - Deal Reporting Part 2/run.py b/Bot Project/10 - Deal Reporting Part 2/run.py deleted file mode 100644 index e3a34c2..0000000 --- a/Bot Project/10 - Deal Reporting Part 2/run.py +++ /dev/null @@ -1,27 +0,0 @@ -from booking.booking import Booking - -try: - with Booking() as bot: - bot.land_first_page() - bot.change_currency(currency='USD') - bot.select_place_to_go(input("Where you want to go ?")) - bot.select_dates(check_in_date=input("What is the check in date ?"), - check_out_date=input("What is the check out date ?")) - bot.select_adults(int(input("How many people ?"))) - bot.click_search() - bot.apply_filtrations() - bot.refresh() # A workaround to let our bot to grab the data properly - bot.report_results() - -except Exception as e: - if 'in PATH' in str(e): - print( - 'You are trying to run the bot from command line \n' - 'Please add to PATH your Selenium Drivers \n' - 'Windows: \n' - ' set PATH=%PATH%;C:path-to-your-folder \n \n' - 'Linux: \n' - ' PATH=$PATH:/path/toyour/folder/ \n' - ) - else: - raise \ No newline at end of file diff --git a/README.md b/README.md index a777f28..ba92c2e 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,68 @@ -# Selenium Series by JimShapedCoding - -## Prerequisites: - - Python Installed (Recommended version 3.8 or above) - - IDE or Text Editor configured with Python Installed (PyCharm/ Visual Code/ Sublime Text) - - Pip Package Manager (use `pip install selenium`) - - Driver for launching the automation (We will use chromedriver.exe) - - Be sure to match the version of Chrome you have - - [Download From this URL](https://chromedriver.storage.googleapis.com/index.html) - -## What you will learn ? - - - Selenium with Python Basics - - Best practices for element identification on websites - - The most useful methods - - Explicit wait vs Implicit wait - - Selenium Booking Project (Online Bot) - - OOP Project, how to maintain code in Selenium Projects - - Context Manager in Selenium Projects - - Using different arguments to launch different bots - - Selenium Unittest Project (Web Application Testing) - - What is Unittest? Why we need to test our applications? - - Testcase writing, reporting - - Deciding how to fail/pass a test - -## What you should know before starting this series ? - - [Python Basics Full Course](https://www.youtube.com/watch?v=m0LdKZ-prto) - - [Python Context Managers](https://www.youtube.com/watch?v=9TRKdYVzXA) - -

-

- Start here! -

+# Updated booking.com bot + +A booking.com webscraping bot using Selenium 4 and Python. + + +* [How to run](#how-to-run) +* [Issues and limitations](#issues-and-limitations) +* [Major changes](#major-changes) +* [Improvements](#improvements) +* [See also](#see-also) + + +## Why + +Jim from [JimShapedCoding](https://www.youtube.com/channel/UCU8d7rcShA7MGuDyYH1aWGg) +made this bot as an example for his Selenium tutorials. The bot no longer works, +so I decided to fork and update it. I'm by no means an expert, +but fairly happy with the code - hopefully someone will find it useful. + +## How to run + +1. Make sure Chrome is installed +1. Install requirements from `requirements.txt` +1. Manipulate `booking/config.py` to change location, check in/out dates, + star rating filters and other settings +1. execute `python3 run.py` + +## Issues and limitations + +I skipped selecting currency and selecting the number of people altogether. +Booking.com seems to have some terrible, unstable locators - not sure if it +was better two years ago, but now some elements seem impossible to navigate +without sacrificing readability. I might give it another try with +CSS selectors once I have more experience with them. + +The bot works around 7-8/10 times - the "*Where are you going?*" and +"*check-in - check-out*" dropdowns still misbehave sometimes. I suppose +Selenium actions could fix that. + +## Major changes + +1. Uses Selenium 4! +1. No inputs. A descriptive Python config file with some extra settings instead + (`booking/config.py`) +1. Explicit, conditional, configurable waits +1. Most Jim's locators no longer worked, so I used different ones - mostly + xpath if By.ID and By.NAME failed +1. I used [webdriver_manager](https://github.com/SergeyPirogov/webdriver_manager). + No need to download chrome drivers manually! + + +## Improvements + +1. Simplified and moved methods from `Filtration.py` and `Raport.py` +1. Conditional waits in `select_place_to_go()` prevent the driver + from accidentally choosing from "*Popular destinations nearby*" +1. The bot can now handle problematic deals marked as "*New to booking.com*" + (with not enough ratings) +1. Star rating checkboxes are "scrolled to" with JavaScript to avoid errors +1. Proper `requirements.txt` +1. A relative locator for the first location/place to go result +1. An extra `highligh_element()` function in `booking/js_utils.py`. I recommend + using it when testing or debugging. + + +## See also + +* Jim's tutorial was also feetured on [FreeCodeCamp's YT channel](https://www.youtube.com/watch?v=j7VZsCCnptM&t=4603s) diff --git a/Bot Project/04 - Structure a Bot Project/booking/__init__.py b/booking/__init__.py similarity index 100% rename from Bot Project/04 - Structure a Bot Project/booking/__init__.py rename to booking/__init__.py diff --git a/booking/booking.py b/booking/booking.py new file mode 100644 index 0000000..28622bc --- /dev/null +++ b/booking/booking.py @@ -0,0 +1,94 @@ +from selenium import webdriver +from selenium.common import NoSuchElementException, TimeoutException +from selenium.webdriver.support.relative_locator import locate_with +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.chrome.service import Service as ChromeService +from webdriver_manager.chrome import ChromeDriverManager + +from booking import config +from booking.config import MEDIUM_TIMEOUT, SHORT_TIMEOUT +from booking.js_utils import scroll_into_view_with_js + + +class Booking(webdriver.Chrome): + def __init__(self): + options = webdriver.ChromeOptions() + [options.add_argument(option) for option in config.CHROME_OPTIONS] + super(Booking, self).__init__(options=options, service=ChromeService(ChromeDriverManager().install())) + + def __exit__(self, exc_type, exc_val, exc_tb): + if config.TEARDOWN: + self.quit() + + def land_first_page(self): + self.get(config.BASE_URL) + + def select_place_to_go(self, place_to_go): + search_field = self.find_element(By.NAME, 'ss') + search_field.click() + search_field.clear() + + results_list_locator = (By.XPATH, "//ul") + popular_destinations_locator = (By.XPATH, "//div[contains(text(), 'Popular destinations nearby')]") + search_field.send_keys(place_to_go) + WebDriverWait(self, MEDIUM_TIMEOUT).until(EC.visibility_of_element_located(results_list_locator)) + WebDriverWait(self, MEDIUM_TIMEOUT).until(EC.invisibility_of_element_located(popular_destinations_locator)) + + first_result_locator = locate_with(By.XPATH, "//li[1]").below({By.NAME: 'ss'}) + self.find_element(first_result_locator).click() + # try: + # results_list_locator = (By.XPATH, "//ul") + # WebDriverWait(self, MEDIUM_TIMEOUT).until(EC.visibility_of_element_located(results_list_locator)) + # popular_destinations_locator = (By.XPATH, "//div[contains(text(), 'Popular destinations nearby')]") + # WebDriverWait(self, SHORT_TIMEOUT).until(EC.invisibility_of_element_located(popular_destinations_locator)) + # first_result_element = self.find_element(locate_with(By.XPATH, "//li[1]").below({By.NAME: 'ss'})) + # first_result_element.click() + # except TimeoutException: + # return + + + + def select_dates(self, check_in_date, check_out_date): + check_in_date_element = WebDriverWait(self, MEDIUM_TIMEOUT).until( + EC.visibility_of_element_located((By.XPATH, f'//*[@data-date="{check_in_date}"]'))) + check_in_date_element.click() + + check_out_element = self.find_element(By.XPATH, f'//*[@data-date="{check_out_date}"]') + check_out_element.click() + + def click_search(self): + search_button = self.find_element(By.CSS_SELECTOR, 'button[type="submit"]') + search_button.click() + + def apply_star_rating(self, *star_values): + star_filtration_box = self.find_element(By.XPATH, "//div[contains(@id, 'filter_group_class')]") + star_child_elements = star_filtration_box.find_elements(By.CSS_SELECTOR, '*') + + for star_value in star_values: + for star_element in star_child_elements: + if str(star_element.get_attribute('innerHTML')).strip() == f'{star_value} stars': + scroll_into_view_with_js(self, star_element) + star_element.click() + + def sort_price_lowest_first(self): + sort_by_element = self.find_element(By.XPATH, "//button[@data-testid='sorters-dropdown-trigger']") + sort_by_element.click() + lowest_price_element = WebDriverWait(self, MEDIUM_TIMEOUT).until( + EC.element_to_be_clickable((By.XPATH, "//span[contains(text(), 'Price') and contains(text(), 'lowest')]"))) + lowest_price_element.click() + + def extract_results(self) -> list[list[str]]: + deal_boxes = self.find_elements(By.XPATH, "//div[@data-testid='property-card']") + + results = [] + for deal_box in deal_boxes: + hotel_name = deal_box.find_element(By.XPATH, ".//*[@data-testid='title']").text + hotel_price = deal_box.find_element(By.XPATH, ".//*[@data-testid='price-and-discounted-price']").text + try: + hotel_score = deal_box.find_element(By.XPATH, ".//*[@data-testid='review-score']/div").text + except NoSuchElementException: + hotel_score = 'new' + results.append([hotel_name, hotel_price, hotel_score]) + return results diff --git a/booking/config.py b/booking/config.py new file mode 100644 index 0000000..7f20d0d --- /dev/null +++ b/booking/config.py @@ -0,0 +1,29 @@ +TEARDOWN = False + +BASE_URL = "https://booking.com" + +# use capital letter abbreviations, i.e. 'USD', 'EUR' etc. +CURRENCY = "USD" +PLACE_TO_GO = "warsaw" + +# must be in 'YYYY-MM-DD' format +CHECK_IN_DATE = "2023-02-20" +CHECK_OUT_DATE = "2023-02-24" + +# list of ints between 2 and 5 +PREFERRED_STAR_RATINGS = [4, 5] + +# to use with explicit/conditional waits, defined in seconds +SHORT_TIMEOUT = 0.5 +MEDIUM_TIMEOUT = 5. +LONG_TIMEOUT = 10. + +# uncomment the line below to run in fullscreen and/or add other options +CHROME_OPTIONS = [ + '--start-fullscreen' +] + + + + + diff --git a/booking/js_utils.py b/booking/js_utils.py new file mode 100644 index 0000000..5c3d531 --- /dev/null +++ b/booking/js_utils.py @@ -0,0 +1,8 @@ +def scroll_into_view_with_js(driver, element): + driver.execute_script("arguments[0].scrollIntoView();", element) + + +# to be used for testing or debugging +def highlight_element(driver, element): + driver.execute_script("arguments[0].setAttribute(arguments[1], arguments[2])", element, + "style", "border: 2px solid red;") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..661a87d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,23 @@ +async-generator==1.10 +attrs==22.2.0 +certifi==2022.12.7 +charset-normalizer==3.0.1 +exceptiongroup==1.1.0 +h11==0.14.0 +idna==3.4 +outcome==1.2.0 +packaging==23.0 +prettytable==3.6.0 +PySocks==1.7.1 +python-dotenv==0.21.1 +requests==2.28.2 +selenium==4.8.0 +sniffio==1.3.0 +sortedcontainers==2.4.0 +tqdm==4.64.1 +trio==0.22.0 +trio-websocket==0.9.2 +urllib3==1.26.14 +wcwidth==0.2.6 +webdriver-manager==3.8.5 +wsproto==1.2.0 diff --git a/run.py b/run.py new file mode 100644 index 0000000..9374266 --- /dev/null +++ b/run.py @@ -0,0 +1,30 @@ +from prettytable import PrettyTable + +from booking import config +from booking.booking import Booking + + +def main(): + with Booking() as bot: + bot.land_first_page() + bot.select_place_to_go(config.PLACE_TO_GO) + bot.select_dates(check_in_date=config.CHECK_IN_DATE, + check_out_date=config.CHECK_OUT_DATE) + bot.click_search() + bot.apply_star_rating(*config.PREFERRED_STAR_RATINGS) + bot.sort_price_lowest_first() + bot.refresh() + + results = bot.extract_results() + + print_results(results) + + +def print_results(results): + table = PrettyTable(["Hotel Name", "Hotel Price", "Hotel Score"]) + table.add_rows(results) + print(table) + + +if __name__ == '__main__': + main()