Home > Blockchain >  Is it possible to place functions in the main module if the program consists of several modules?
Is it possible to place functions in the main module if the program consists of several modules?

Time:01-20

Question about the structure of the application, if I have a lot of modules in it, is it possible to place functions in main? For example, I decided to separate the functions responsible for responding to vacancies into a separate module, is it possible to leave the rest in the main one? The question arose because I heard that main should only contain function calls without their definitions, but I can't figure out how to break this program into many modules without creating separate modules for each of them:


import time
import random
import os

import selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

from webdriver_manager.chrome import ChromeDriverManager
from contextlib import contextmanager
from enum import Enum
import configparser


class Link(Enum):
     LOGIN_PAGE = r"https://hh.ru/account/login"


class XPath(Enum):
     INPUT_LOGIN = r'//*[@id="HH-React-Root"]/div/div[3]/div[1]/div/div/div/div/div/div[1]/div[1 ]/div[1]/div/div[2]/form/div[1]/fieldset/input'
     INPUT_PASSWORD = r'//*[@id="HH-React-Root"]/div/div[3]/div[1]/div/div/div/div/div/div[1]/div[1 ]/div[1]/div/div[2]/form/div[2]/fieldset/input'
     BUTTON_EXPAND_LOGIN_BY_PASSWORD = r'//*[@id="HH-React-Root"]/div/div[3]/div[1]/div/div/div/div/div/div[1]/div[1 ]/div[1]/div/div[2]/div/form/div[4]/button[2]'
     BUTTON_LOGIN = r'//*[@id="HH-React-Root"]/div/div[3]/div[1]/div/div/div/div/div/div[1]/div[1 ]/div[1]/div/div[2]/form/div[4]/div/button[1]'
     LINK_TO_BUTTON_MY_RESUMES = (
         r'//*[@id="HH-React-Root"]/div/div[2]/div[1]/div/div/div/div[1]/a'
     )
     LINKS_TO_BUTTON_SUBMIT = r"//span[text()='Submit']/ancestor::a"
     LINKS_TO_BUTTON_NEXT = r"//span[text()='next']/ancestor::a"
     RESPONSE_LIMIT_WARNING = r"//div[text()='You can only submit a maximum of 200 responses within 24 hours. You have reached your response limit, please try again later.']"


class Tag_Value(Enum):
     SUITABLE_VACANCIES = r'resume-recommendations__button_updateResume'


def sleep_random():
     MIN_SLEEP = 2
     MAX_SLEEP = 3
     time.sleep(round(random.uniform(MIN_SLEEP, MAX_SLEEP), 2))


def open_config_file() -> configparser.ConfigParser:
     '''Find and open configuration file by default search in same directory as main script.'''
     path_to_config = os.path.join(os.getcwd(), 'config.ini')
     assert os.path.exists(path_to_config), "Path to config not found."

     config = configparser.ConfigParser()
     config.read(path_to_config, encoding="utf-8")
     return config


def check_exists_by_xpath(web_driver: webdriver.Chrome, xpath: str) -> bool:
     '''Check if an element exists by its Xpath.'''
     return len(web_driver.find_elements(By.XPATH, xpath)) > 0


def safety_get(driver: webdriver.Chrome, url: str):
     '''Safe opening where if the page is not opened within n seconds, it is reloaded.'''
     driver.set_page_load_timeout(120)

     try:
         driver.get(url)
     except TimeoutException:
         print('Page reload.')
         driver.refresh()



def login(web_driver: webdriver.Chrome, LOGIN: str, PASSWORD: str):
     '''Login to the site with login and password.'''
     safety_get(web_driver, Link.LOGIN_PAGE.value)

     # sleep_random()
     web_driver.find_element(
         By.XPATH, XPath.BUTTON_EXPAND_LOGIN_BY_PASSWORD.value
     ).click()
     # sleep_random()
     web_driver.find_element(By.XPATH, XPath.INPUT_LOGIN.value).send_keys(LOGIN)
     # sleep_random()
     web_driver.find_element(By.XPATH, XPath.INPUT_PASSWORD.value).send_keys(
         PASSWORD
     )
     # sleep_random()
     web_driver.find_element(By.XPATH, XPath.BUTTON_LOGIN.value).click()

     sleep_random()


def resume_selection(web_driver: webdriver.Chrome, TITLE_OF_RESUME):
     '''Go to the "my resumes" tab, select one of the user's resumes and go to the "n matching jobs" tab.'''
     link_my_resumes = web_driver.find_element(
         By.XPATH, XPath.LINK_TO_BUTTON_MY_RESUMES.value
     ).get_attribute('href')
     safety_get(web_driver, link_my_resumes)
     sleep_random()
     link_suitable_vacancies = (
         web_driver.find_element(
             By.CSS_SELECTOR, f"div[data-qa-title='{TITLE_OF_RESUME}']"
         )
         .find_element(
             By.CSS_SELECTOR,
             f"a[data-qa='{Tag_Value.SUITABLE_VACANCIES.value}']",
         )
         .get_attribute('href')
     )
     safety_get(web_driver, link_suitable_vacancies)
     sleep_random()


def submit_to_the_vacancy_on_the_all_pages(web_driver: webdriver.Chrome):
     '''
     Response to all vacancies on the page (in this case, there is a transition to the vacancy, and after
     go back to the list of vacancies) and iterate through all pages while the "Next" button exists.
     '''

     # The loop will stop if there is no more "next" button or a banner appears about exceeding the number of responses in 24 hours.
     while check_exists_by_xpath(
         web_driver, XPath.LINKS_TO_BUTTON_NEXT.value
     ) and not (
         check_exists_by_xpath(web_driver, XPath.RESPONSE_LIMIT_WARNING.value)
     ):

         list_of_elements_button_submit = web_driver.find_elements(
             By.XPATH, XPath.LINKS_TO_BUTTON_SUBMIT.value
         )

         list_of_links_to_button_submit = [
             link.get_attribute('href')
             for link in list_of_elements_button_submit
         ]

         for link_to_button_submit in list_of_links_to_button_submit:
             sleep_random()

             try:
                 web_driver.get(link_to_button_submit)
             except Exception as error:
                 print(error)

             sleep_random()
             web_driver.back()

         link_to_button_next = web_driver.find_element(
             By.XPATH, XPath.LINKS_TO_BUTTON_NEXT.value
         ).get_attribute('href')

         safety_get(web_driver, link_to_button_next)
         sleep_random()


def main():
     config = open_config_file()
     LOGIN = config["Account"]["login"]
     PASSWORD = config["Account"]["password"]
     TITLE_OF_RESUME = config["Resume Options"]["title_of_resume"]
    
     SUBMIT_LIMIT = 200

     with open_web_driver() as web_driver:
         login(webdriver, LOGIN, PASSWORD)
         resume_selection(web_driver, TITLE_OF_RESUME)
         submit_to_the_vacancy_on_the_all_pages(web_driver)


if __name__ == "__main__":
     main()

CodePudding user response:

In my opinion you should probably use Page Object model to structure your project. It would be much easier to manage as the project grows big. You can find more info here

CodePudding user response:

Generally, you can put all your code into one module and make the code plain, not even separated into classes, modules and methods.
We separate code into modules, classes and methods to make it readable, understandable, easy to maintain and easy to extend and change. This is some basic best coding practice we learn during learning to programm.
But still, if you will not do that the code will work. Until you will need to change it several times...

  • Related