├── .github └── FUNDING.yml ├── .gitignore ├── Docker ├── Dockerfile ├── app │ ├── constants.py │ ├── linkedinBot.py │ └── utils.py └── docker-compose.yml ├── LICENSE.md ├── README.md ├── config.py ├── constants.py ├── globalLogic.py ├── linkedin.py ├── requirements.yaml ├── simple.py ├── test.py └── utils.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ['jjjjamess'] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://commerce.coinbase.com/checkout/576ee011-ba40-47d5-9672-ef7ad29b1e6c'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | config_internal.py 7 | 8 | config_local.py 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | share/python-wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | MANIFEST 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .nox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | *.py,cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | cover/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | .pybuilder/ 80 | target/ 81 | 82 | # Jupyter Notebook 83 | .ipynb_checkpoints 84 | 85 | # IPython 86 | profile_default/ 87 | ipython_config.py 88 | 89 | # pyenv 90 | # For a library or package, you might want to ignore these files since the code is 91 | # intended to run in multiple environments; otherwise, check them in: 92 | # .python-version 93 | 94 | # pipenv 95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 98 | # install all needed dependencies. 99 | #Pipfile.lock 100 | 101 | # poetry 102 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 103 | # This is especially recommended for binary packages to ensure reproducibility, and is more 104 | # commonly ignored for libraries. 105 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 106 | #poetry.lock 107 | 108 | # pdm 109 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 110 | #pdm.lock 111 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 112 | # in version control. 113 | # https://pdm.fming.dev/#use-with-ide 114 | .pdm.toml 115 | 116 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 117 | __pypackages__/ 118 | 119 | # Celery stuff 120 | celerybeat-schedule 121 | celerybeat.pid 122 | 123 | # SageMath parsed files 124 | *.sage.py 125 | 126 | # Environments 127 | .env 128 | .venv 129 | env/ 130 | venv/ 131 | ENV/ 132 | env.bak/ 133 | venv.bak/ 134 | 135 | # Spyder project settings 136 | .spyderproject 137 | .spyproject 138 | 139 | # Rope project settings 140 | .ropeproject 141 | 142 | # mkdocs documentation 143 | /site 144 | 145 | # mypy 146 | .mypy_cache/ 147 | .dmypy.json 148 | dmypy.json 149 | 150 | # Pyre type checker 151 | .pyre/ 152 | 153 | # pytype static type analyzer 154 | .pytype/ 155 | 156 | # Cython debug symbols 157 | cython_debug/ 158 | 159 | # PyCharm 160 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 161 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 162 | # and can be added to the global gitignore or merged into this file. For a more nuclear 163 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 164 | #.idea/ 165 | 166 | #pytransform 167 | pytransform/ 168 | 169 | #config file 170 | mainConfig.py 171 | 172 | # user files 173 | geckodriver.log 174 | *.txt 175 | *.exe 176 | 177 | # premium files 178 | angelco.py 179 | globalLogicCode.py 180 | -------------------------------------------------------------------------------- /Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-alpine 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | #COPY ./requirements.txt /requirements.txt 5 | RUN pip install -r /requirements.txt 6 | #RUN pip install selenium 7 | 8 | RUN mkdir /app 9 | COPY ./app /app 10 | WORKDIR /app -------------------------------------------------------------------------------- /Docker/app/constants.py: -------------------------------------------------------------------------------- 1 | jobsPerPage = 25 2 | 3 | fast = 2 4 | medium = 3 5 | slow = 5 6 | 7 | botSpeed = medium 8 | 9 | # TO DO ADD OTHER PRINT CONSTANTS 10 | -------------------------------------------------------------------------------- /Docker/app/linkedinBot.py: -------------------------------------------------------------------------------- 1 | import os,time,sys 2 | 3 | from selenium import webdriver 4 | from utils import prGreen,prRed,prYellow 5 | from selenium.webdriver.common.keys import Keys 6 | 7 | prYellow("ℹ️ This script will check if the bot can automatically log in Linkedin for you.") 8 | 9 | def checkPython(): 10 | try: 11 | if(sys.version): 12 | prGreen("✅ Python is succesfully installed!") 13 | else: 14 | prRed("❌ Python is not installed please install Python first: https://www.python.org/downloads/") 15 | except Exception as e: 16 | prRed(e) 17 | def checkPip(): 18 | try: 19 | import pip 20 | prGreen("✅ Pip is succesfully installed!") 21 | except ImportError: 22 | prRed("❌ Pip not present. Install pip: https://pip.pypa.io/en/stable/installation/") 23 | def checkSelenium(): 24 | try: 25 | import selenium 26 | prGreen("✅ Selenium is succesfully installed!") 27 | except ImportError: 28 | prRed("❌ Selenium not present. Install Selenium: https://pypi.org/project/selenium/") 29 | def checkDotenv(): 30 | try: 31 | import dotenv 32 | prGreen("✅ Dotenv is succesfully installed!") 33 | except ImportError: 34 | prRed("❌ Dotenv not present. Install Dotenv: https://pypi.org/project/python-dotenv/") 35 | 36 | 37 | def checkSeleniumLinkedin(): 38 | options = webdriver.FirefoxOptions() 39 | firefoxProfileRootDir = "/home/seluser/.mozilla/firefox/nrhpd5k5.linkbot" 40 | 41 | options.add_argument('--ignore-ssl-errors=yes') 42 | options.add_argument('--ignore-certificate-errors') 43 | #options.add_argument("-profile") 44 | options.add_argument(firefoxProfileRootDir) 45 | #options.headless = True 46 | 47 | browser = webdriver.Remote( 48 | command_executor='http://localhost:4000/wd/hub', 49 | options=options 50 | ) 51 | 52 | try: 53 | browser.get('https://www.ongundemirag.com') 54 | if(browser.title.index("Ongun")>-1): 55 | prGreen("✅ Selenium and geckodriver is working succesfully!") 56 | else: 57 | prRed("❌ Please check if Selenium and geckodriver is installed") 58 | except Exception as e: 59 | prRed(e) 60 | 61 | try: 62 | browser.get('https://www.linkedin.com/feed/') 63 | time.sleep(3) 64 | if "Feed" in browser.title: 65 | prGreen('✅ Successfully you are logged in to Linkedin, you can now run main bot script!') 66 | else: 67 | prRed('❌ You are not automatically logged in, please set up your Firefox Account correctly.') 68 | try: 69 | browser.get("https://www.linkedin.com/login?trk=guest_homepage-basic_nav-header-signin") 70 | time.sleep(5) 71 | user_field = browser.find_element("id","username") 72 | pw_field = browser.find_element("id","password") 73 | login_button = browser.find_element("xpath", 74 | '//*[@id="organic-div"]/form/div[3]/button') 75 | print(user_field, pw_field, login_button) 76 | # enter your linkedin username and password below 77 | username="linkedin@username.com" 78 | password="linkedin_password" 79 | user_field.send_keys(username) 80 | user_field.send_keys(Keys.TAB) 81 | time.sleep(2) 82 | pw_field.send_keys(password) 83 | time.sleep(2) 84 | login_button.click() 85 | time.sleep(3) 86 | except: 87 | raise Exception("Could not login!") 88 | 89 | except Exception as e: 90 | prRed(e) 91 | finally: 92 | browser.quit() 93 | 94 | 95 | checkPython() 96 | checkPip() 97 | checkSelenium() 98 | checkDotenv() 99 | checkSeleniumLinkedin() 100 | 101 | 102 | 103 | print("Test Execution Successfully Completed!") -------------------------------------------------------------------------------- /Docker/app/utils.py: -------------------------------------------------------------------------------- 1 | import math,constants 2 | from typing import List 3 | import time 4 | 5 | def prRed(prt): 6 | print(f"\033[91m{prt}\033[00m") 7 | 8 | def prGreen(prt): 9 | print(f"\033[92m{prt}\033[00m") 10 | 11 | def prYellow(prt): 12 | print(f"\033[93m{prt}\033[00m") 13 | 14 | def getUrlDataFile(): 15 | urlData = "" 16 | try: 17 | file = open('data/urlData.txt', 'r') 18 | urlData = file.readlines() 19 | except FileNotFoundError: 20 | text = "FileNotFound:urlData.txt file is not found. Please run ./jobPreferances/createUrl.py first and make sure you have urlData.txt in /data folder generated." 21 | prRed(text) 22 | return urlData 23 | 24 | def jobsToPages(numOfJobs: str) -> int: 25 | number_of_pages = 1 26 | 27 | if (' ' in numOfJobs): 28 | spaceIndex = numOfJobs.index(' ') 29 | totalJobs = (numOfJobs[0:spaceIndex]) 30 | totalJobs_int = int(totalJobs.replace(',', '')) 31 | number_of_pages = math.ceil(totalJobs_int/constants.jobsPerPage) 32 | if (number_of_pages > 40 ): number_of_pages = 40 33 | 34 | else: 35 | number_of_pages = int(numOfJobs) 36 | 37 | return number_of_pages 38 | 39 | def urlToKeywords(url: str) -> List[str]: 40 | keyword = url[url.index("keywords=")+9:url.index("&location") ] 41 | location = url[url.index("location=")+9:url.index("&f_E") ] 42 | return [keyword,location] 43 | 44 | def writeResults(text: str): 45 | timeStr = time.strftime("%Y%m%d") 46 | fileName = "Applied Jobs DATA - " +timeStr + ".txt" 47 | try: 48 | with open("data/" +fileName) as file: 49 | lines = [] 50 | for line in file: 51 | if "----" not in line: 52 | lines.append(line) 53 | 54 | with open("data/" +fileName, 'w') as f: 55 | f.write("---- Applied Jobs Data ---- created at: " +timeStr+ "\n" ) 56 | f.write("---- Number | Job Title | Company | Location | Work Place | Posted Date | Applications | Result " +"\n" ) 57 | for line in lines: 58 | f.write(line) 59 | f.write(text+ "\n") 60 | 61 | except: 62 | with open("data/" +fileName, 'w') as f: 63 | f.write("---- Applied Jobs Data ---- created at: " +timeStr+ "\n" ) 64 | f.write("---- Job Title | Company | Location | Work Place | Posted Date | Applications | Result " +"\n" ) 65 | 66 | f.write(text+ "\n") 67 | 68 | -------------------------------------------------------------------------------- /Docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | selenium: 5 | image: seleniarm/standalone-chromium 6 | ports: 7 | - 4444:4444 8 | restart: always 9 | 10 | app: 11 | build: 12 | context: . 13 | volumes: 14 | - ./app:/app 15 | command: sh -c "python3 bot.py" 16 | depends_on: 17 | - selenium 18 | shm_size: "2dgb" 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | _____________________________________________________ 4 | 5 | 6 | LINKEDIN APPLY BOT SOFTWARE LICENSE & EULA 7 | 8 | ______________________________________________________ 9 | 10 | 11 | SOFTWARE LICENSING: 12 | 13 | LINKEDIN APPLY BOT is covered under a proprietary based license. 14 | 15 | LICENSE TERMS: 16 | 17 | LINKEDIN APPLY BOT for personal use only. 18 | 19 | 20 | LINKEDIN APPLY BOT for commercial use. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinkedIn Application Bot 🤖 2 | 3 | ![linkedineasyapplygif](https://user-images.githubusercontent.com/34207598/128695728-6efcb457-0f75-42e2-987a-f7a0c239a235.gif) 4 | 5 | A python bot to apply all Linkedin Easy Apply jobs based on your preferences. 6 | 7 | - Two options are avalible to use this bot, either with entering password or without, fully secure no credentials are stored. 8 | - Export all results and offers as txt file 9 | - Fully customizable job preferences 10 | - Can be used for many job search websites such as Linkedin, Glassdoor, AngelCo, Greenhouse, Monster, GLobalLogic and Djinni. 11 | 12 | To modify, use, get documentation or for you enquiries kindly contact me via:
13 | **amin@boulouma.com** 14 | 15 | ## Donation and Support 🥳 16 | 17 | With your support I build, update and work on this project. You can also purchase additional packages, tutorials and materials explaining how this bot is working.
18 | 19 | There are several features and simplifications I'd like to add to this project. For that I need your support to cover costs. Your support is keeping this project alive. 20 | 21 | [**Donate & support!**](https://commerce.coinbase.com/checkout/576ee011-ba40-47d5-9672-ef7ad29b1e6c) 22 | 23 | ## Purchase additional materials and guides 😍 24 | 25 | You can currently, purchase full in depth detailed tutorial explaining how this bot is working, one hour booking session where i step by step build and run the bot on your machine or 5 videos 26 | showing how this can be used. To buy, support this project and help me add more features.
27 | 28 | - [**Purchase working videos for this bot**](https://commerce.coinbase.com/checkout/3958599d-3938-4fb3-86f4-b100c2d7e850) 29 | - [**Purchase online call tech support to install the bot for Windows**](https://commerce.coinbase.com/checkout/638f5582-a750-4374-86ea-82d0445cbe90) 30 | - [**Purchase online call tech support to install the bot for Linux**](https://commerce.coinbase.com/checkout/3ec705fe-2898-4ae8-9f90-73cd1270392f) 31 | - [**Purchase online call tech support to install the bot for Mac OS**](https://commerce.coinbase.com/checkout/cf76021c-53be-42bc-8ae1-2dc75fcd9647) 32 | - [**Purchase documentation of this bot for Windows**](https://commerce.coinbase.com/checkout/ac4212d1-ecb0-4734-8946-f4a9e5c09f45) 33 | - [**Purchase documentation of this bot for Linux**](https://commerce.coinbase.com/checkout/69a1f1b8-3282-4ab6-9383-6ce28aab3274) 34 | - [**Purchase documentation of this bot for Mac OS**](https://commerce.coinbase.com/checkout/c7069064-02ac-4c3b-b980-ae7623bc8139) 35 | 36 | ## Installation 🔌 37 | 38 | - clone the repo `git clone https://github.com/aminblm/linkedin-application-bot` 39 | - Make sure Python and pip is installed 40 | - Install dependencies with `pip3 install -r requirements.yaml` 41 | - Either create firefox Profile and put its path on line 8 of config.py or enter your linkedin credentials line 11 and 12 of config.py. 42 | - Modify config.py according to your demands. 43 | - Run `python3 linkedin.py` 44 | - Check Applied Jobs DATA .txt file is generate under /data folder 45 | 46 | ## Features 💡 47 | 48 | - Ability to filter jobs, by easy apply, by location (Worldwide, Europe, Poland, etc.), by keyword (python, react, node), by experience, position, job type and date posted. 49 | - Apply based on your salary preferance (works best for job offers from States) 50 | - Automatically apply single page jobs in which you need to send your up-to-date CV and contact. 51 | - Automatically apply more than one page long offers with the requirements saved in LinkedIn like experience, legal rights, resume etc. 52 | - Output the results in a data txt file where you can later work on. 53 | - Print the links for the jobs that the bot couldn’t apply for because of extra requirements. (User can manually apply them to optimize the bot) 54 | - Put time breaks in between functions to prevent threshold. 55 | - Automatically apply for jobs. 56 | - Automatically run in the background. 57 | - Compatible with Firefox and Chrome. 58 | - Runs based on your preferences. 59 | - Optional follow or not follow company upon successful application. 60 | - Much more! 61 | 62 | ## Tests 🔦 63 | 64 | There is a specific test folder for you to test the dependencies, the bot and if everything is set up correctly. To do that I recommend, 65 | running below codes, 66 | 67 | 1. Go to the tests folder run `python3 setupTests.py` this will output if Python,pip,selenium,dotenv and Firefox are installed correctly on your system. 68 | 2. Run `python3 seleniumTest.py` this will output if the Selenium and gecko driver is able to retrieve data from a website. If it returns an error make sure you have correctly installed selenium and gecko driver 69 | 3. Run `python3 linkedinTest.py` this will try to log in automatically to your Linkedin account based on the path you defined in the .env file. If its giving an error make sure the path exists and you created firefox profile, logged in manually to your Linkedin account once. 70 | Here is the result you should get after running test files, 71 | ![test1](https://user-images.githubusercontent.com/34207598/189535308-c2c546de-caec-4460-823d-dd5ca208c480.png) 72 | 73 | ## How to Set up (long old way) 🛠 74 | 75 | This tutorial briefly explains how to set up LinkedIn Easy Apply jobs bot. With few modifications you can make your own bot or try my other bots for other platforms. 76 | 77 | 1. Install Firefox or Chrome. I was using Firefox for this so I will continue the usage of it on Firefox browser. Process would be similar on Chrome too. 78 | 2. Install Python. 79 | 3. Download [Geckodriver](https://github.com/mozilla/geckodriver/releases) put it in Python’s installation folder. 80 | 4. Install pip, python get-pip.py 81 | 5. Install selenium pip install selenium 82 | 6. Clone the code 83 | 7. Create a profile on Firefox, about:profiles 84 | 8. Launch new profile, go Linkedin.com and log in your account 85 | 9. Copy the root folder of your new profile, to do that type about:profiles on your Firefox search bar, copy the root folder C:\---\your-profile-name. 86 | 10. Paste the root folder on the `config.py` if the `firefoxProfileRootDir` file 87 | 11. Modify/adapt the code and run in `config.py` to preferences. 88 | 12. After each run check the jobs that the bot didn’t apply automatically, apply them manually by saving your preferences 89 | 13. Next time the bot will apply for more jobs based on your saved preferences on Linkedin. 90 | 14. Feel free to contact me for any update/request or question. 91 | 92 | ## Demo 🖥 93 | 94 | ![banner](https://github.com/aminblm/linkedin-application-bot/assets/25132838/b0dda2f0-b531-48af-b769-fc1370d88fdb) 95 | ![1](https://github.com/aminblm/linkedin-application-bot/assets/25132838/1caeeff1-7f70-423a-ae51-ae97ba00bc99) 96 | ![2](https://github.com/aminblm/linkedin-application-bot/assets/25132838/3cb59d82-b167-40ad-8fef-d8e1430bf6c1) 97 | 98 | ## Future Implementations 99 | 100 | - Headless browser experience (run the bot without launching the browser) 101 | - More robustness of the bot for different fields 102 | - Blacklist offers in Linkedin 103 | - Output not completed fields in Linkedin 104 | - Add support to other major job seeking websites (Glassdoor, AngelCo, Greenhouse, Monster, GLobalLogic, djinni) 105 | - AngelCo - https://angel.co/l/2xRADV 106 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # General bot settings 2 | 3 | # browser you want the bot to run ex: ["Firefox"], ["Chrome"] choose one only 4 | browser = ["Firefox"] 5 | # Optional! run browser in headless mode, no browser screen will be shown it will work in background. 6 | headless = True 7 | # Optional! for Firefox enter profile dir to run the bot without logging in your account each time 8 | firefoxProfileRootDir = r"" 9 | # If you left above field empty enter your Linkedin password and username below 10 | # Linkedin credits 11 | email = "" 12 | password = "" 13 | 14 | # These settings are for running Linkedin job apply bot 15 | LinkedinBotProPasswrod = "" 16 | # location you want to search the jobs - ex : ["Poland", "Singapore", "New York City Metropolitan Area", "Monroe County"] 17 | # continent locations:["Europe", "Asia", "Australia", "NorthAmerica", "SouthAmerica", "Africa", "Australia"] 18 | location = ["European Economic Area"] 19 | # keywords related with your job search 20 | keywords = ["lead developer", "chief technical officer", "cto", "python"] 21 | # keywords = ["programming"] 22 | #job experience Level - ex: ["Internship", "Entry level" , "Associate" , "Mid-Senior level" , "Director" , "Executive"] 23 | experienceLevels = ["Mid-Senior level" , "Director" , "Executive"] 24 | #job posted date - ex: ["Any Time", "Past Month" , "Past Week" , "Past 24 hours"] - select only one 25 | datePosted = ["Past 24 hours"] 26 | # datePosted = ["Past 24 hours"] 27 | #job type - ex: ["Full-time", "Part-time" , "Contract" , "Temporary", "Volunteer", "Intership", "Other"] 28 | jobType = ["Full-time", "Part-time" , "Contract"] 29 | #remote - ex: ["On-site" , "Remote" , "Hybrid"] 30 | remote = ["On-site" , "Remote" , "Hybrid"] 31 | #salary - ex:["$40,000+", "$60,000+", "$80,000+", "$100,000+", "$120,000+", "$140,000+", "$160,000+", "$180,000+", "$200,000+" ] - select only one 32 | salary = [""] 33 | #sort - ex:["Recent"] or ["Relevent"] - select only one 34 | sort = ["Recent"] 35 | #Blacklist companies you dont want to apply - ex: ["Apple","Google"] 36 | blacklist = ["EPAM Anywhere"] 37 | #Blaclist keywords in title - ex:["manager", ".Net"] 38 | blackListTitles = [""] 39 | #Only Apply these companies - ex: ["Apple","Google"] - leave empty for all companies 40 | onlyApply = [""] 41 | #Only Apply titles having these keywords - ex:["web", "remote"] - leave empty for all companies 42 | onlyApplyTitles = [""] 43 | #Follow companies after sucessfull application True - yes, False - no 44 | followCompanies = False 45 | # your country code for the phone number - ex: fr 46 | country_code = "fr" 47 | # Your phone number without identifier - ex: 123456789 48 | phone_number = "" 49 | 50 | 51 | # These settings are for running AngelCO job apply bot 52 | AngelCoBotPassword = "" 53 | # AngelCO credits 54 | AngelCoEmail = "" 55 | AngelCoPassword = "" 56 | # jobTitle ex: ["Frontend Engineer", "Marketing"] 57 | angelCoJobTitle = ["Frontend Engineer"] 58 | # location ex: ["Poland"] 59 | angelCoLocation = ["Poland"] 60 | 61 | # These settings are for running GlobalLogic job apply bot 62 | GlobalLogicBotPassword = "" 63 | # AngelCO credits 64 | GlobalLogicEmail = "" 65 | GlobalLogicPassword = "" 66 | # Functions ex: ["Administration", "Business Development", "Business Solutions", "Content Engineering", 67 | # Delivery Enablement", Engineering, Finance, IT Infrastructure, Legal, Marketing, People Development, 68 | # Process Management, Product Support, Quality Assurance,Sales, Sales Enablement,Technology, Usability and Design] 69 | GlobalLogicFunctions = ["Engineering"] 70 | # Global logic experience: ["0-1 years", "1-3 years", "3-5 years", "5-10 years", "10-15 years","15+ years"] 71 | GlobalLogicExperience = ["0-1 years", "1-3 years"] 72 | # Global logic location filter: ["Argentina", "Chile", "Crotia", "Germany", "India","Japan", "Poland" 73 | # Romania, Sweden, Switzerland,Ukraine, United States] 74 | GlobalLogicLocation = ["poland"] 75 | # Freelance yes or no 76 | GlobalLogicFreelance = ["no"] 77 | # Remote work yes or no 78 | GlobalLogicRemoteWork = ["yes"] 79 | # Optional! Keyword:["javascript", "react", "angular", ""] 80 | GlobalLogicKeyword = ["react"] 81 | # Global Logic Job apply settinngs 82 | FirstName = "O" 83 | LastName = "D" 84 | Email = "amin@boulouma.com" 85 | LinkedInProfileURL = "www.google.com" 86 | Phone = "" #OPTIONAL 87 | Location = "" #OPTIONAL 88 | HowDidYouHeard = "" #OPTIONAL 89 | ConsiderMeForFutureOffers = True #true = yes, false = no -------------------------------------------------------------------------------- /constants.py: -------------------------------------------------------------------------------- 1 | linkJobUrl = "https://www.linkedin.com/jobs/search/" 2 | angelCoUrl = "https://angel.co/login" 3 | globalLogicUrl = "https://www.globallogic.com/career-search-page/" 4 | 5 | jobsPerPage = 25 6 | 7 | fast = 2 8 | medium = 3 9 | slow = 5 10 | 11 | botSpeed = slow 12 | 13 | # TO DO ADD OTHER PRINT CONSTANTS 14 | -------------------------------------------------------------------------------- /globalLogic.py: -------------------------------------------------------------------------------- 1 | from pytransform import pyarmor_runtime 2 | pyarmor_runtime() 3 | __pyarmor__(__name__, __file__, b'\x50\x59\x41\x52\x4d\x4f\x52\x00\x00\x03\x0a\x00\x6f\x0d\x0d\x0a\x09\x34\xe0\x02\x00\x00\x00\x00\x01\x00\x00\x00\x40\x00\x00\x00\x31\x1d\x00\x00\x00\x00\x00\x18\xd3\x9a\xb3\xe3\xbb\xde\x00\x3f\xe4\xac\xef\x23\x9e\x36\x59\x6d\x00\x00\x00\x00\x00\x00\x00\x00\x98\x97\xcc\x81\xbf\x7f\x86\x03\x5b\xbb\x83\xb9\x7e\x94\x7d\xc0\x6e\xc3\xfb\x93\xe4\x81\xa3\x30\x23\x4d\x70\xc3\x41\xa9\x8e\x1f\x03\xb4\x05\x7e\x45\x62\xc0\x60\x83\x37\x0f\x31\xbf\x6d\x1c\xa0\xfb\x3b\x31\x7d\x4e\x25\xb7\x87\x69\x3a\x1d\xb4\x2a\x65\x80\xa2\x3f\x1e\x35\xe7\x5d\xa3\x1d\x8b\x68\xba\x3e\x54\x82\x5f\x5e\xbb\xe2\x62\xd7\x51\x20\x1f\x52\x46\xab\x8e\x84\x89\x81\xda\x55\x84\x4c\x77\x19\x2f\x39\xaf\x03\x09\x4f\xaa\x46\x30\x0e\x1d\x3a\x3e\x38\x9a\x1b\xc6\x42\x59\xaf\xb5\x79\xee\xe9\x7d\xaa\x6c\xc5\xef\x56\x39\x0c\x2d\xe7\x83\x22\xba\x9c\xd3\x8b\x0e\x9a\xbb\x7d\xca\x2b\xf2\x58\x4d\xcc\xf9\xeb\x8f\xa1\x22\x19\xaf\xe5\x6d\xec\xf5\x91\x0d\x4f\xa0\x48\x59\x08\x18\x61\xec\x3c\xef\x82\xd9\xd3\xb2\x89\xa9\xba\x57\x08\xa9\x7f\x3d\x94\x2a\xf4\x10\x2b\xf2\x81\xf2\x83\x8c\x2e\x33\x0a\xc9\x62\xdc\xd4\x10\xb0\xae\x05\x2e\x62\x54\x99\x26\x88\x52\x20\xb4\x44\x56\x04\x09\xda\x06\x2f\x7c\xf8\x15\xaf\x69\xae\xb9\x65\x7e\x88\x29\x74\x3d\x31\x9b\x26\xb0\x4b\xad\x9c\x22\x7c\x0e\x0e\x80\x62\xa8\x6b\x70\x67\xa8\x8e\x9e\x9e\x3e\xd1\x69\xf8\x52\x88\xba\x18\xaf\x82\x0a\xf7\xd7\xbd\x42\x29\xb8\x00\xad\x7b\x14\xa0\xc9\x89\x22\x92\xa9\x55\x1e\xfd\xa3\x17\x2b\x41\xed\xca\xbe\x31\x9e\x37\xc5\xdf\xe2\xb9\x82\x48\x66\x54\xc6\xb2\xc8\xc3\x64\x46\xe4\x44\x4a\x14\x27\xa6\x14\x43\x7b\xde\x36\xa3\xbb\x7f\x7d\xef\x9c\x18\x8a\x11\x44\x04\xa2\x80\x60\x07\xfe\xf4\x82\x1f\x53\x45\xa6\xd6\xe3\x6a\x57\xa5\x61\xfb\x02\x64\x53\x6c\x75\x61\xed\x12\x28\x6f\x22\xde\x50\xff\xe2\x59\x20\x6f\xbc\x87\xe9\x03\x49\xda\xc5\x0f\x45\x63\x24\xc4\xad\x26\xbc\x3c\xaa\x27\xd0\xa1\x87\x4e\xbe\x37\x58\x59\xbb\x68\x91\xef\x2c\x74\x8e\x9c\xa6\xd6\xc5\x49\x10\x4b\x07\x0a\x99\x69\x24\xc6\x3b\x1c\x7d\x62\x68\x7d\xb4\x5e\x15\xda\x3d\xe3\x9c\xa7\x52\xe9\x24\xf1\xba\xf9\xaf\xff\x2a\xa6\x3c\xde\x84\xa3\x8c\x28\x16\x32\x0c\x59\xc8\x4b\x82\x3a\x32\x4f\x6d\x03\xba\x76\xb9\x86\x82\x66\xea\x90\x4f\xbc\x22\x93\x94\x4d\xc9\x4d\xae\x17\x7e\xfa\x08\xc5\xb6\x3e\x1f\x6c\x3b\x72\x6c\x7a\x5e\xa7\x9b\x37\x93\xce\x63\x8e\x95\x5a\x00\x5b\x64\x8d\x9e\x7b\x11\x3a\xae\x81\xc6\x26\xe8\xfa\x55\x9a\x55\x3c\xa4\xc9\x30\xd2\xa6\x3e\x1c\xe2\xc9\xcf\xb0\x26\xa2\xfc\x04\x14\x99\xb1\xc3\xb7\x0a\x2d\x6e\xf1\x19\x26\xd8\x61\xed\x67\x76\xab\xc2\x49\xcf\x44\xf7\x5e\xb7\x7e\x26\x37\x7a\xab\x73\xef\x1e\xec\x82\x16\x8b\xb2\xbb\xb2\x4f\xd5\x07\xc8\x42\x6d\xca\x84\x75\xa4\x32\xbb\xc3\x4b\x7d\xb0\x5f\xe9\x3c\xe7\xec\x62\x42\x85\x9b\x1a\xf5\x4a\xce\x10\x8f\xde\x5c\x84\x44\x53\x16\xfd\x8e\x11\x79\xac\x30\xe1\x43\x50\x1d\xb6\xb4\xfc\x5c\xe7\x1b\x71\x88\xe2\xa7\xc8\x09\x73\x8a\x49\xb0\xfe\xa9\x1b\xa9\x46\xc0\x45\xbb\x61\x62\x3b\xae\x7b\x90\x6e\x6f\x8d\xc4\x9c\x42\x1f\x63\x5b\xee\x43\x83\x2e\x04\x4c\x7d\xa4\x98\x7f\x34\xf6\xa5\xc4\xea\x40\xdb\x85\x1c\x42\x71\x7f\xfc\x55\x9c\x4d\x5b\x48\xe0\xc7\x1d\x3e\xf4\xd7\x9c\xf9\x0a\xf9\x92\xe6\x88\x7a\x8c\x4d\x59\xf7\x93\xf5\x0e\x69\x7d\x3b\x5a\x0a\x03\x63\xa0\x04\x49\xe9\x79\x80\x34\xf9\x8c\x6b\x07\x55\xfc\xbb\x8c\xdc\x5d\x26\x98\x56\x5c\xe8\xe1\x38\xaa\x03\x2d\x00\x07\x75\x0c\x6e\x9a\xbe\x6b\xb1\x8a\xc3\xa6\xfc\xde\xc8\x2a\xd9\x52\xc1\x34\xe6\x7c\x79\xd1\x96\x35\xf2\xb5\x27\x21\x7b\xe6\xea\x31\x38\xc5\x73\x01\x1e\x58\xcc\x3a\x7e\xd7\x95\x5e\xab\x83\x4b\x49\x25\x6d\x54\x07\xa2\x5a\x14\xfb\x85\x93\x07\xbb\x39\xe6\x34\x8c\x36\x13\xe1\xff\xa5\xf6\x08\x18\xc5\xf0\x13\x72\xcc\xbb\xa9\x2f\xbd\x98\x1f\x27\x10\x23\x11\xe9\x22\x78\xa0\x09\x8b\x7d\x47\x6f\xf7\xf2\x09\x59\xa5\xf4\x18\xef\x3b\x53\x3e\x42\x06\x27\x25\x44\x37\x20\x13\x2b\xa4\x49\xe3\xf5\x04\x6d\x2b\x93\xec\xcf\x7f\xeb\xa2\x9f\x17\xac\x9d\xe8\xb5\x19\x5a\x75\x41\x22\xc7\x13\x02\x60\x9c\xa4\xa1\xfb\x2f\xd9\xd3\x38\x9c\x86\x0e\xbf\x81\xff\xda\xb8\xe3\xe8\xfd\xa0\xeb\x44\x4d\x6f\x03\xec\x3b\x32\x75\x38\xd5\x4d\x19\x69\x40\xeb\x81\xc6\x2a\x4f\x77\x95\xe7\x19\xa0\xfc\x41\x86\xab\xad\x1a\x6b\x44\x33\x7d\x06\x1c\x0e\xf5\x3d\x69\xf0\xa9\x5d\x3f\x04\x8a\x2b\x41\x31\x65\xd2\x67\x80\xf8\xc1\x62\x04\x42\x62\x2e\x23\x02\xc3\xfe\x91\x9e\x1f\x28\xfe\x09\x11\x95\x96\x81\x52\xef\xfc\xcc\xac\x67\x7a\xad\xba\x98\xfe\x41\x44\x13\x6c\x76\x64\x4e\x9e\x53\xb1\xb7\xfc\xd4\x7f\xbd\xe1\x0b\x7d\x2d\x91\xbe\xf6\xf9\x1b\x75\x15\x3e\x85\xbb\xa9\x17\xc0\xb1\x49\xa7\x25\xf9\x83\x83\xcb\x82\xbd\x54\x18\x4e\x68\xb4\xa8\x17\x7a\xb0\x07\xe2\x42\x89\x16\xe7\xf8\xbb\x62\xcb\x64\x5c\x43\x0d\xbd\x06\x11\x24\x4d\x53\xe9\xbe\x4d\x72\xaf\xa2\x22\x48\x99\x5b\x22\x23\xd8\x29\x08\x09\xea\x7a\xe9\xe6\x94\xde\x39\xaf\xfc\x8c\x8b\x45\x84\x6e\xfa\x18\x98\x0c\x39\x16\x8f\x78\x99\x39\xc9\x8e\x3b\x06\x65\x64\xe0\xab\x02\x1e\x33\x20\xb4\x16\x7e\x35\x71\x7b\x6e\xdf\x82\x8f\x86\xbf\x5b\x1d\xfd\xbd\x8c\x0a\xe3\x33\x8b\x67\x31\x31\x20\x07\xe4\xea\xec\x93\x41\x7e\x1e\xb1\xd2\x9e\xbe\x8b\x27\xf9\x00\xb3\x21\x2f\xea\xc2\x26\xb4\xef\x0c\x6e\x93\xf3\x28\x7b\x0f\x11\x93\x9f\xd4\xe0\xa8\xb7\xb7\xf9\xee\x07\x6c\x6a\xc5\x43\x4a\xb6\xe9\x7e\x8b\xa2\x1b\x19\x58\x1e\x1a\x8a\xad\x56\x93\xcb\xac\xe9\xda\x3d\x9a\xc5\x1b\x55\xc5\x55\x1a\x3d\x05\xbc\xb8\x12\x8d\xd0\x64\x7a\xc9\x1c\xf4\x7b\x59\x4f\x09\xaa\x8c\x56\xa2\x56\x7f\xd3\x56\xc6\xe0\x71\xf2\x71\x8a\xa8\xe4\xe9\xe7\xc0\x8c\xb2\x83\xac\x88\x94\x21\x72\x9e\x41\xb8\x32\x3f\xb1\x12\xe1\xf4\x36\x77\x4c\x2e\x46\xdb\x42\x37\x08\x10\xa9\x04\x56\x2f\x14\x8b\x05\x5d\x06\xb1\xd5\x4f\x05\xc3\xbf\xe7\x87\x59\xec\x81\xaa\xd6\x80\x34\x96\x46\xda\xf9\x03\x32\x58\xf6\x9a\x64\x43\xc9\x18\xe5\xc9\x00\x5c\x54\x3e\x88\x42\x41\x88\x36\xca\xf9\x67\x0e\x42\x77\x9d\x4b\x92\x53\xc3\xec\x2f\x76\x54\xf2\x36\xbc\xbc\x08\xcf\xbf\x74\xb3\x3b\x2d\xec\xe7\x38\xea\x1b\x37\x03\xd3\x59\x0a\xb1\x0e\x8d\x55\x2f\xd2\x42\x95\x23\x81\x99\x73\xac\xe4\xcb\xb1\x75\xf4\xfc\xf9\xc5\x08\x55\x02\x19\x6d\xd9\x14\x36\x9e\x01\x87\x4e\x67\xd8\xa0\xde\xdb\x33\x19\xf5\x04\x0d\x6c\xac\x1c\x49\x00\xf3\x8c\x95\x4f\xce\x38\x06\x42\xa9\x7e\x4b\x72\x1a\x8b\xca\xc8\xb9\x92\xa5\x1a\x00\x26\xbe\xd8\x0a\xac\xb3\x48\x61\x7c\x05\x4c\xa5\xe0\x26\x4c\x79\xe9\xc3\x66\x93\x14\xdd\xb9\x48\x16\x42\x97\xe1\xe2\x5f\x84\xa9\xc7\x80\xa1\x0b\x97\x51\x16\x60\x9a\xdb\x93\x5e\xaa\x77\xe9\xeb\x6c\xfa\x98\x44\xdd\x75\xee\x22\x5e\x57\x9a\x72\xb9\x95\xc7\x3c\x80\x88\xc3\xa0\xe0\xd1\x5c\x1c\xac\x63\x60\x63\xc1\x0c\xc7\x7a\xab\xf3\x07\x69\x44\x41\xe8\xc9\x62\x19\x4b\x28\x8a\x19\x85\xfe\xac\xc9\x88\xec\xdc\x19\x8e\x30\x28\x3d\x57\x87\x58\xe1\x40\x31\xd5\x18\xf9\x06\xa5\x37\x75\x76\x73\x47\x32\x54\x10\xf1\x66\xda\x35\x20\xba\x88\x0b\x5c\x8a\x6c\x56\x25\x57\x6d\xba\xa9\x1d\xa7\xe9\x25\x5b\xe3\xe1\xdd\x76\x5d\x81\xa3\x92\xac\x14\x35\x5f\x9f\x71\xa2\x07\x17\x68\x25\xed\xc1\xa6\x1c\x27\xc3\xec\xdd\x9d\x7d\x45\xc7\xbc\xa9\x44\x0c\xe2\x6e\xa4\x75\xe8\xf4\x9e\x6e\x0e\x2e\xb4\x57\xd4\xaf\xfe\x18\x05\x0a\x2d\xf8\x5a\x3b\x05\xc6\x6a\xd1\x60\x87\x1e\x2e\xe1\x3b\x6b\xae\xc9\x02\xc3\x93\xd9\xda\x5d\x80\xb2\x76\xea\xb0\x26\x40\x71\x72\xae\x7e\x7a\x2b\x9b\x32\x88\x9c\xa1\x45\x7d\xa6\x8c\x87\x65\xce\xb7\xba\x07\xc5\x08\xae\xdd\x11\x6b\x07\x71\x7b\xd3\xbf\xb1\x46\xcf\x4c\x91\x14\x32\xe1\x7f\xa0\x6c\xa4\x81\x74\x35\xc1\xbd\x94\x05\x33\xc3\x3a\x03\x1b\x0b\x82\xe3\x44\x96\x19\x27\x1e\xfe\xe3\x3b\x2b\x62\x20\x16\x64\x27\xcb\x10\x26\x41\xeb\xb3\x8b\x64\xec\x71\x8e\x8a\x04\xe5\x3c\x2d\xf6\x50\x36\xf1\x00\xf0\xfe\xb4\x36\xb9\x63\x97\x6b\x5b\xe3\xff\x81\xe3\x47\x07\x8c\x35\x81\xc6\x2a\x1f\x22\xe7\xac\x2a\x3a\x78\xf7\xda\xa2\x0b\xe7\x50\xc6\x26\x31\x17\x1a\x30\xfe\xe5\x59\xe7\xb4\x90\xab\x33\xc2\xfa\xaf\xd3\x9c\xc1\xa4\x8a\xa1\x9a\x8e\xb2\x6e\x6c\xae\x72\xd4\x69\x5d\xea\x13\xee\xf7\x45\x22\x44\xb5\x37\xc8\xbe\x69\x30\xf3\x05\x2d\xf5\x3e\xfb\x2c\xee\x9b\x26\x03\xde\x60\x3e\xe2\x5f\x49\x37\xbe\x9f\xb3\xd7\x24\xe8\xeb\x43\xb5\x2c\x1d\x31\x47\x4d\xdf\xba\xfe\x5b\xf1\x04\xf0\xd2\xd2\x82\x7b\x94\x4d\xa4\xa3\x72\x40\xbc\x08\x7e\xca\x95\x4f\x95\x72\x98\x2d\x43\xce\x27\x89\x6c\xd5\x5e\x3e\x0b\x9f\x02\x20\x54\xca\x39\x6c\xa6\xa0\x07\xb6\x2f\x9b\xfc\x8c\xd9\xd1\x01\x3b\x5b\x2f\x69\xe7\x56\x2d\x49\xbe\x3c\xce\xcb\xdb\x7e\x25\x08\x95\x75\x65\xbc\x2c\x89\xfc\xc9\x03\xb6\x91\xf2\x50\x6a\xf2\xf1\x4d\x2c\x1e\xb2\x2e\x23\x68\x97\xbd\x90\x65\x38\xd0\x5a\x6d\x8e\xf8\x00\xde\xd8\xfc\x52\xaa\xc7\xb2\x86\xd8\x28\x3a\xaf\x11\xda\x2a\xc3\x57\x4d\x0b\x23\x10\x65\x4f\x23\x69\xa1\xea\x49\x01\xe8\xb5\xee\xa0\x19\x28\x33\xb5\xf1\x3a\x0c\xd8\x0a\xaa\x29\x8b\x2e\x05\xd7\x9f\xd0\x91\x8c\x95\xbc\x8a\x83\xe3\x83\xa0\x3a\xe4\xbb\xd2\xdc\xbd\xb9\x81\x92\x6a\xe8\x4d\x27\xf0\xb1\x38\x58\xed\x17\xf2\xc1\x70\x28\x7b\x5d\x45\x42\x41\x2e\xff\x8d\x27\x63\x96\x8e\xec\xc0\x88\xb4\xa4\x1b\x56\x83\xd7\x7e\x5d\xec\x2f\x09\xd0\x10\x57\xd4\x61\xf3\xc1\x42\xb1\x2f\x96\x9b\x49\x2c\x2a\x77\x69\x59\xa2\xa1\x0a\x03\xc0\x5a\xa7\x29\x07\xbc\xe6\x27\x09\xb8\x9a\xae\x46\x95\x48\x2d\x16\x26\x57\x48\x2b\x71\x6a\xb2\xb1\xab\x04\xe4\x7e\xa1\x34\x7e\xca\x8d\xe7\x61\x49\x09\xf0\x0c\x1b\xaa\x4b\x00\x05\x9c\x92\x50\xd9\x54\x18\x9e\xa1\x62\xd0\xd7\xce\x5a\x59\x73\xaa\x8e\x79\x04\x75\x7b\xee\x98\x49\x5b\x31\x5f\x0a\xee\x9b\x8c\x9a\x2f\x9e\x42\x1d\x1e\x75\x1c\xef\x4d\xcc\x5b\xac\xcf\x50\x39\xd7\x78\xc4\x63\x8f\xbf\x24\x24\x75\x21\xaa\xe4\x0e\xf9\xe6\x9a\x44\x9b\xad\xc8\xe0\x84\x39\x5e\xbc\x59\xf0\x79\x86\x2a\x5b\x02\x4c\xff\x89\x54\xd4\x9e\xe1\x91\xc7\xef\x3e\xe4\xd3\x3a\xd7\x32\xdb\xa0\x40\x6b\x44\x19\xe1\xa3\xfd\xc7\xb2\xf4\xd0\xe5\x1a\xdb\xc8\x44\x2b\x48\xb2\x46\xd8\x20\x37\x6e\xd0\x45\x65\x0d\xca\x37\x69\x9b\xc2\xaa\x10\xf5\x8e\x36\x24\x11\xb8\x10\x6d\x47\x0d\x8a\xb3\xa4\xf1\xe5\x84\x0d\x05\xe5\x53\x21\x29\x9b\x42\xde\x60\x2b\x6b\xd5\xdc\x9a\xb6\x46\x1e\xa2\x4a\xc7\xff\x67\x7a\xd4\xfe\x16\x18\x69\xf3\x71\x29\x86\x64\x06\x35\xf7\xf6\x49\xa2\x90\x83\x61\xe0\x75\x5d\x81\xf9\x94\x72\x17\x64\xbe\xa4\xaa\x1b\x81\x14\xf3\x51\xbd\xb2\xbc\x41\x53\x1a\x15\x54\x93\x01\x0c\xb1\x13\x41\x5d\xbc\x99\x52\x0b\xa6\x7f\x68\x0f\x6f\x0f\xef\x6c\xea\x82\x09\xa3\xf8\xc1\xff\x5b\xd4\x3a\xe4\x6b\xe8\x69\x9d\xbd\xa2\xb6\x50\x40\x97\x24\x72\x17\xcd\xd4\x9e\x0e\xfb\xd8\xb1\x2c\x19\xd8\x93\x2e\xb8\x76\x38\x38\x78\xce\x60\xac\xa4\x60\x7f\x05\x90\x16\xf8\xdc\xb0\x6c\x3a\x1f\xa9\x97\xde\xfc\x26\xde\x68\x49\x5e\x21\xf1\x9b\xc1\xf0\x21\x11\x94\x42\x68\x9a\x7b\x71\x54\xf1\x2f\x1a\xc3\xb4\xa0\x2d\xd8\x81\x83\x08\x23\x66\xa1\xdc\xf0\xd0\x5f\x14\x45\x71\x02\xa1\x6d\xdb\xfe\x2e\x32\xda\xca\x0d\xbe\x4d\x76\x06\x64\xef\xf9\x78\x48\xc1\xcf\x73\x93\xea\x85\xf0\xf5\xde\xb7\xf1\x67\x41\x33\x7c\x34\x05\x3d\xc0\x63\x71\x2c\xff\x4e\x07\x35\xbb\x3b\x47\xbf\xa9\x75\x1d\xf0\xd5\x56\x37\x55\xb7\xdb\x10\xca\x94\x0e\xcd\x6d\x71\xdf\x04\x5c\xed\x02\x21\xac\x8f\xfb\x1b\x47\xf0\xb2\x79\x2c\x02\x9e\x1a\xa5\xe5\x9b\xc9\x1d\x62\xe8\xde\xb0\xad\xca\x57\x8f\x2a\x07\xd4\x38\x19\x8d\x49\xfd\xcf\x11\xc6\x51\x55\xde\xa0\x04\x00\x2f\xa2\xd9\x7b\x0b\x33\xdf\xff\xf2\x2d\x63\xfd\x9c\xca\xc0\xaa\x24\x4c\x82\xea\xf2\xd9\x3f\x6c\x9b\x4b\x85\xc2\xf5\xb1\xfa\x2a\xb6\x22\x28\x0f\xe7\xb5\x3c\xb7\xc0\x4a\x40\xf6\xf9\x97\x0a\xb1\x0f\x9d\xb8\x64\xff\xbb\x91\x88\x0c\x01\x90\xc4\x0f\x69\x55\xa8\x72\x41\xf7\x26\x18\xf7\x0a\x52\x7d\x07\x3e\xe5\x17\x28\xd8\xdc\xea\x50\x7a\xe8\x1a\xd2\x65\x1f\x42\xd4\xaf\x41\xbd\x53\x30\x0c\x67\x52\x7d\xdc\x4d\x39\xdf\xc3\x4a\x9d\xc1\x49\x89\xde\xbc\x65\x64\x42\x64\x52\x38\xce\x9c\xef\x44\xb7\x84\x14\x3c\xf7\xbf\x67\x78\x55\xf3\x30\xd9\x0a\x57\x7c\x1f\xa6\x65\x11\xc7\xe1\xa1\xe8\xa3\xcf\x0c\x88\xf2\xd6\x4b\x4d\x93\x40\x4f\x46\xa0\x02\xc0\x76\x86\xaf\x5e\xe8\x68\x49\x04\x02\xf9\xc9\x00\xd4\xce\xcd\x12\x53\xb6\x3f\x69\xc9\x84\x67\x81\xa4\xcf\x4a\x3c\x79\xa6\x3f\xf1\xf2\x82\xa5\x64\x99\xf2\xa9\xbd\x37\xf1\x45\xd0\x8c\x63\x8d\x76\x9b\x08\x41\x36\x2a\x33\x05\x03\x00\x67\x2c\x3a\x79\x3f\xe5\xd1\xf2\x90\x45\x2c\xa7\x08\x87\x2a\x1a\xd7\x25\xc5\x6f\x6c\x83\xe3\x04\xd5\xdc\x3b\xd7\xd0\xb7\xe9\xec\x76\xab\xe5\x5d\x15\x52\xaa\xc7\xd2\x1a\x97\x76\xf9\x99\x2e\x0c\x72\xff\x0e\xf1\x91\xab\x18\xe4\xc5\x5e\x7a\x17\x3e\x77\x0b\x2a\x25\xae\x2f\x2f\x08\x23\x70\x63\x43\xe2\xba\x50\xa4\x8e\xd3\x13\x28\xf2\xb1\x73\x34\x97\x7b\x85\x81\x45\x05\x0f\x7f\x5a\x19\x7a\x73\xa4\x2b\x9a\x77\x65\xd7\xc3\x95\x17\xd3\x6b\x3d\x38\x79\x88\xd3\xaf\xb1\x9a\x67\x0e\x19\x18\xb1\x5e\x3e\x68\x95\xf4\x5a\x12\x91\x29\xe0\xe6\xdd\xd0\x9e\x1b\xef\x7d\x1f\x56\x6d\x20\x8e\xa2\xce\xdb\xb8\x79\x65\xef\x84\xb7\x60\x1a\xea\x64\xfe\x60\x33\x4c\x07\xe6\xa5\x4d\x5b\x02\x23\x77\xdf\x88\xa6\x0f\xbc\x3a\x65\x7e\xcc\xd8\x45\x18\xfe\x35\xd2\x72\xa4\xac\x9e\x69\x36\xc6\xc8\x59\xd7\x56\x2a\x2e\x5c\x86\x21\xc5\x47\x08\x53\x70\x3b\xc2\x85\x83\xa9\x57\x27\xa6\x17\x31\x97\x98\x04\xa7\x42\x13\x57\x41\xe2\x1d\xf3\x86\x77\xfd\x2f\x6b\x08\x66\x0a\x08\xd6\x04\xbf\xf3\xb8\x4e\x64\x3e\x80\x99\x35\xf8\xfc\xf4\x69\x18\x90\xac\xe1\x71\xd0\x2f\xb9\x45\xb8\x81\x90\x3a\x5e\xd2\x8f\x01\xfa\x3b\xa8\x35\x8c\x2d\xef\x14\x03\x23\x9a\xae\xe4\xc3\x67\x79\xf6\x31\x4a\x3e\xc7\xcb\xbc\x2e\xc1\x46\x76\x29\xd6\x88\x93\xea\xc1\x3e\x1c\xe1\x55\x0a\x7c\xc2\xea\x71\x40\xd9\xd1\x97\x13\x8d\x58\x66\x0f\xd8\xb6\x64\x37\x86\x8d\x9d\x08\xff\xdd\x8e\xd6\x26\x79\xfe\x9a\xb8\x59\x73\x78\xee\x97\x78\x4b\xab\x2e\xc6\xbf\xde\x11\xca\x2f\x1e\x28\x90\x54\xc8\x05\x49\x90\xad\xf7\x3f\xf3\x76\x34\xe1\xfe\xbb\xad\x23\x5c\x19\xf0\x0f\x31\xdd\xf6\x8e\x86\x96\x54\xca\xd3\x32\x10\xca\xd9\x4c\xe7\x73\xf2\xb1\x98\x5e\xa6\xb8\xff\x3f\xb4\x19\xcd\xd2\x1b\x74\xe0\xbb\xa1\x3a\xfc\x9f\x2d\x98\x5b\x1f\x67\x85\xd7\xbe\x34\x93\x5b\x12\xbb\xd3\x20\x3f\x4f\x02\xab\xed\xdd\x1f\x4d\xc5\x5c\xa2\x4b\x79\x24\x13\x6d\xf1\x85\xeb\xda\xc2\xc1\x59\xc6\x72\x5b\x80\x78\x77\x53\x96\x92\xa3\xab\x35\x60\x29\x43\x8a\x13\xa5\x95\xb7\xd6\xb9\xce\x1b\x88\xf0\x98\xa6\x07\xbd\x27\x19\x12\xca\x76\x53\xc7\x31\xfa\xbb\x79\x6d\x63\xa3\xdc\xf3\x2e\x2f\xbb\xa6\x0f\x35\x07\x11\x6d\xd4\x60\xe8\x31\xe9\xac\x82\x97\x3c\x2d\xf3\x2c\x99\x72\xf1\x69\x4d\xea\x21\xd7\xa2\x3b\x9e\x3d\x0e\x6b\x8b\x77\x54\x12\xb4\xc6\x93\x61\x0c\x58\x19\x6f\xe3\x20\xf2\x97\x9d\x16\x6c\x03\x91\x59\x46\x31\xfe\x03\xc8\x03\x54\x78\xbd\x96\x99\x12\x6d\x58\x35\x32\x2c\x61\xa0\x11\x19\x51\xaf\x33\xe4\x4d\x6c\xd8\x79\x16\x61\x15\x27\xe9\xeb\x44\x57\x99\x4d\xdf\x5b\xed\xba\xeb\xef\x6e\x18\xfc\x0d\x5c\x17\x69\xc7\x79\x21\xca\xea\xd4\xf5\x17\x85\x63\x82\x14\x52\x82\x52\x8e\x54\xb3\x9f\x85\x66\xdc\xa1\x28\xf4\xfd\x4f\x30\xc7\x6b\x5d\xe6\x79\xdb\x3c\xd8\x54\xa0\x1c\x60\x7d\x3b\xbe\xb5\x38\xe5\x0c\x96\xbe\x8c\xc4\x4a\x4e\xe2\x58\xad\xd4\x38\x86\x16\x5d\x66\x91\xef\xb3\x3a\x27\xd7\x84\xde\xc5\xb8\xa4\x16\x6b\xf6\xbc\xe7\x0b\xa2\x32\xeb\x96\x0f\x36\x6c\x12\xb4\xb5\xd8\x29\xdc\x4f\x81\xc0\x71\xc0\x23\xba\xee\xd3\xe0\x77\x8d\x6f\x3d\xf6\xe6\xc6\x31\x5a\x05\xd4\x05\xbd\x3b\x24\xb6\x6a\x16\x5b\xf1\x80\x45\xa5\xc0\x1e\x33\x91\x9c\x69\x13\xda\x90\xaf\x2a\x55\x58\xc0\xc6\xd8\xf2\x9c\x29\xf3\xea\x46\x15\xc5\xc3\x94\xe0\xf1\xa3\xc0\x41\xb6\x69\x23\xbf\x33\xff\xa2\x22\x68\x6d\xb8\x41\xcb\xa3\x7a\xc1\xdb\x95\xb0\xae\x1a\x04\x68\x0a\x57\xf9\xe5\x48\xc6\x10\x10\xd1\x53\x2f\x14\xc7\x23\x57\xa0\x3e\x39\xf0\xc1\x33\x4f\x38\x92\x6b\x17\xd4\x52\xa1\x35\x33\x69\xc9\x8f\xd3\xb9\x31\x6f\x89\x25\x3c\x59\x20\x55\xdf\xbf\xf5\xea\x79\x04\x0f\x40\x87\x24\x8d\x0a\x48\x68\x8e\xc6\x64\x1a\x99\x88\xca\x4b\x42\xf9\xa6\xf2\x28\x1b\x52\xb0\x55\x44\x31\x3a\xdd\x0a\x28\x3b\x31\xf1\xe2\xd0\xa2\x68\x8e\xcc\xd3\x0d\x0b\xd7\x9d\x63\x33\xe0\x81\x56\x92\x6e\xc6\x79\x2c\x5f\x87\x8f\x23\x98\x07\xa6\xa4\xb4\x9e\x87\x69\xd2\x63\x93\x87\xb2\xbb\x84\xcb\xc9\x60\xb9\x81\x15\xbb\xe6\xfa\xfb\x20\x23\xd3\xc9\xd1\xa7\xd0\x2d\xe5\x96\x46\x55\xcf\x6f\xc6\x70\x5c\x04\xdd\xfa\xf5\x49\x70\xb1\x47\x89\xe4\xe4\xa1\xbc\x08\xf2\x91\x60\xd2\x8e\xf3\xd8\x86\x42\x1b\x7a\x9b\x19\x33\x56\x88\xa3\xcf\xd2\x0a\xb2\x15\x52\xac\xb3\x1e\x62\x56\xcc\xe2\x05\x82\x82\x76\x1c\x51\xb5\xaf\x0c\x87\x0b\xc5\xd8\x9f\xf5\xdd\x0a\x12\x1e\x06\xa6\x00\x93\x66\xfb\xdc\x67\x10\xfe\x0f\xd0\xd8\x2e\x64\xe1\xbd\x61\x2d\x1d\xa2\xe3\x47\x45\xff\xd7\x4a\x04\x0e\x73\x6c\xc7\xd1\x16\xe5\x63\x15\x99\xc5\xc6\xb5\x3e\x14\x25\x73\x90\xfb\x60\x2e\x11\xa3\xcf\x82\x95\x53\x63\x66\x81\xaa\xd2\xc6\x9c\x0f\xe6\x88\xe0\xd0\x80\xdb\x8c\xd8\x87\x11\xcc\x83\x1e\x3a\x13\xbe\xed\x7e\xb6\x21\xc3\x13\x18\xf9\x8d\x13\x2a\x40\xbe\xf2\x1e\xe2\x3a\x1f\xda\xdc\x78\x1c\xee\x4d\x2a\x76\x67\x8c\x6a\x20\xa1\x24\x79\xd1\x9b\xe1\x0c\x81\x39\xeb\xf3\xc9\x63\xd0\x6d\x50\x96\x4d\x38\xc1\x29\x8f\xa6\x09\x92\xab\x28\x45\x13\x0b\x58\xc5\x17\xc1\xfd\x81\x24\xc4\x48\x02\x80\xe3\x4f\xfe\x01\xcc\x1e\xea\x0c\x6a\x8e\x14\x32\x8b\xbf\x30\x1c\x32\xa0\x32\x1e\x20\xba\x98\xeb\xa7\x1f\x0c\xc7\xeb\x92\xaf\x3d\xc9\x99\xde\x7d\x00\x65\x89\xb2\x1b\x6b\x02\x76\xbc\x9d\x3b\x4b\x1c\x0d\xc9\xd5\xf9\xa4\x4e\x6f\x4c\x4b\xcd\xfe\x83\x14\x5c\xcc\x1e\x01\xd7\x28\xbb\xee\x85\xdf\x5c\x34\x98\x72\x36\xdd\x25\x9f\xde\xda\xf3\xa2\x89\xf4\xb4\xf4\x4f\xeb\x0c\x07\xdd\x21\x28\xca\x8f\xdc\xbe\xe4\xde\xf8\x1f\x22\x7e\x87\x81\x1d\xc0\x61\x12\x4a\x5c\x79\x53\xb6\x68\xeb\x9a\x77\xc6\x28\xf5\xc6\x39\xc6\xc1\xe4\x8b\x0b\x21\x93\x33\x19\x41\x58\x0d\x42\x5c\xdb\x1b\x53\x0f\x3b\x7c\x9a\x3d\xc5\x65\x1c\xd9\x12\x95\xb6\xca\x9e\xb9\xcf\x27\xf3\x82\x15\x2f\x6c\xee\x06\xdc\x6d\x8e\x81\x0d\x31\x2a\xbf\x5e\x64\x19\xb3\xf1\x49\x57\x60\x77\xd9\xbd\xea\x25\x95\x29\xb9\x59\xfc\x3f\x7b\x11\x5a\xd7\xe4\x8c\xa2\x1c\xb9\x53\x7c\x3a\x47\x40\xc1\x99\x0a\xa4\x30\xc1\x43\xad\x6b\x1f\x4b\x6b\x59\x82\xcf\xf1\x23\xed\x24\x53\x44\x18\x74\xa4\xc6\x2b\x89\xa8\x70\xd3\x03\xb3\xba\x57\xe6\x7d\xe1\xc2\xdc\x2b\x7a\x9a\x51\xdf\xeb\x00\x17\x88\x50\x3d\x6e\x0d\x98\x8d\x67\x1d\xbb\xb1\xd9\x88\x7a\x96\xb0\x94\x01\x0e\x97\x9a\x2c\xbf\xb2\x85\xf2\xbd\xc5\xf3\x1b\xf1\xea\xc3\x96\x29\xf1\x8f\x96\xa6\x0c\x3d\x96\x14\x0d\x4d\xbd\xf8\x5a\x67\xe2\x29\x1a\x23\x30\x25\x78\x64\xb3\x0c\x7c\x9f\x31\x0b\x14\x32\x05\x56\x6c\xf4\x11\x56\xf6\xa3\xb5\xab\xc3\x3c\xa1\xf1\x3d\x9d\x39\x2f\x1f\x90\x0d\x37\xd1\x28\xf0\x5d\x94\x06\x5d\xca\x86\x6f\x25\x1b\x41\x30\x40\x90\x83\x4d\x30\xa0\x56\x66\xf3\xce\xd7\x47\x24\x6f\x43\xe1\xe2\x39\xb0\xa8\x53\x57\xe7\x66\x87\x2e\x8a\xf3\x33\xef\x9d\x71\xd7\xe7\x91\x59\x9d\x1e\x3d\x14\x45\xfc\x3b\x78\x12\x1a\x4b\xf7\x3b\x5f\x71\x50\x21\x47\xea\x0c\x92\x8b\xd8\x52\x07\x79\xfd\x93\xbb\x81\x8a\x04\xb7\xa7\xb2\xcd\xa5\xf4\x49\x2f\xbe\xa5\x8b\x78\x79\x92\x2c\x58\xea\x5a\x2f\xde\xff\xcc\x75\xac\x53\x96\x5e\x9a\x67\x47\x8b\x97\x09\x87\x7e\xa5\x71\x64\x18\x4b\x76\xf2\x66\xb6\x94\xe9\x4d\xcb\xdb\xb6\xd6\xd0\xa1\x69\x37\x61\x98\x74\x40\x1e\xbb\xa5\xbd\xb6\x16\x5e\xf1\x48\xef\xbe\x43\x32\xa6\x9b\xdf\xca\x15\xb1\xc2\x1c\x1d\x48\x48\xb3\x2f\xfc\x1d\x4e\xf1\xde\x50\x81\xd4\xcb\xa1\xdd\x93\x8e\x95\x1d\xe6\x03\x45\xd4\xaf\x08\x5a\x61\x9f\xc3\x7f\xa7\x6f\x45\x0d\x5e\x40\x13\x78\x84\x63\x7f\x2b\x96\x30\xde\xcd\xb9\xb1\xd6\xf7\xb6\xc3\xe4\x9c\xd9\x63\x21\x01\x59\xda\x81\x34\x74\x78\x59\x3e\xe6\x8f\x58\x97\x08\x3d\x4e\x57\x8b\xd9\x34\x82\xee\xc2\x3d\x02\x5d\x21\x65\x12\x44\xf0\x0b\x11\xc2\xfc\xa9\xec\xd5\xed\x14\x60\x58\x8f\x7b\xea\xcd\xaa\x41\x73\x88\xa7\x94\x40\xb5\xd7\x6b\xfa\x50\xb2\xca\x52\x9d\xe5\x43\x55\x47\x17\xb4\xdf\x45\x3f\x87\x6a\x2d\x52\xb0\xa2\x3e\x09\x5e\x18\x8e\x58\xab\x0b\xf7\x62\x92\xc1\x52\xec\x70\xfc\x9b\x6d\x41\x82\x0a\x70\x10\x28\x26\xb3\x61\xa7\x0b\x18\xbc\x92\xaa\xde\xf5\x8d\x68\x03\x08\x58\x04\x62\x3e\x51\x4f\xa8\x5e\xa0\xcb\xb2\x57\x7f\x42\x8e\xe5\x0e\x8f\xa1\x1d\xe3\x10\xe5\x93\x72\xb2\x3b\xd7\x0a\x1d\x02\xfe\x44\x53\x18\x03\x7d\x0b\xb0\x82\x3a\xe7\x18\x16\x44\x1e\xa2\xcd\x02\xeb\xaa\x2f\xc7\xd9\x2f\xfd\x1a\xad\x63\x9e\xeb\x22\xaf\x99\x51\xc7\xad\xb6\x94\x13\x67\x38\xd4\x12\x8e\x82\x19\x06\x13\xbe\x84\x1c\xb7\x2a\x7d\x55\x2b\xea\xec\x53\xbb\x27\x16\x43\x55\x76\xbc\xef\x3a\xa1\x1d\x8e\xa8\x7e\x8c\xef\x80\xe1\x19\x40\x18\x04\x6a\x4a\xe9\xd2\x14\xb8\x43\xca\x3c\xbe\x28\x46\xfc\x22\x1f\x71\x6f\xa0\x4d\xfc\x1a\xcc\x11\x6a\xad\xf3\x25\x21\xd8\xdd\xdd\x3f\x1f\xa6\x44\xcf\x02\xd8\xd1\x94\x9a\x36\x15\xe1\xf7\xe3\xc0\xcd\xad\xc9\x1c\x36\xc1\x8a\xec\x9d\x9a\xc0\x84\x78\x8d\xe6\x7e\x54\x58\x29\x47\x74\xc1\x29\x69\x03\xf6\x40\x21\x2d\xee\x46\x4e\x11\x77\xc0\xdd\xcf\x84\x27\xde\x1e\x0f\xee\x3e\xf4\xeb\x94\x04\x47\x28\x4a\x3e\x02\x14\x6a\xce\xa0\x15\x3d\xc4\x3a\x96\x62\x53\x9c\x25\xa9\xdd\x8b\x4b\x4a\xf0\xfe\x2f\xaf\xb7\x10\x06\xbd\x9c\x85\x99\x5b\x61\x80\x98\x8c\x6a\x61\x15\x98\x1d\xcb\x75\xf9\xf2\x39\x2b\x17\xc8\x6d\x1f\x75\x31\x19\xc3\xcd\x39\x58\x19\x7d\xe7\x8c\x25\xb3\x57\x77\x9c\x4f\x78\x88\xa3\x48\x4f\xbf\x8d\x83\xba\x68\x18\xb1\x27\xcf\xf2\x37\x88\x06\x85\x42\x2e\x12\x77\x5e\xf2\xa9\x5b\xcf\x63\xd1\xa9\x5f\x71\xee\x05\x40\x28\xfd\x7b\xa4\x4a\xe7\x2b\x41\xb3\xa8\x41\xc0\xcd\x8e\x65\x77\x48\x46\x42\xdb\xc5\x81\x1e\x9e\xad\x61\xa4\xff\xae\x72\x2f\x1e\x16\x3c\xd4\x2b\xa8\x51\x92\x6c\x82\xa7\x69\x57\x16\xa0\x99\x83\xd7\xb3\xe7\x86\x1d\xee\xa6\xcc\x3e\xa2\x94\x44\xc6\xc3\xaa\x4e\x1d\x20\x36\xaa\xa4\x4f\xe4\x36\x0c\x1f\x6e\xfd\xc7\xc5\x28\x27\xe8\x4d\x3b\x19\x6a\x67\x21\xd6\x8d\xf2\xd1\x17\x90\x58\xd6\xed\x2f\x5c\xa1\xdb\x95\x0e\xd3\xfd\x29\xe4\x6f\xd7\x3c\x05\xe2\x83\x98\xf4\x26\xfb\x5c\xe9\xbb\xbb\x91\x47\x45\x66\xea\x4e\xe5\xed\xf1\x36\x38\xc2\x7a\xaa\x7d\x26\x94\x58\xba\x93\x9c\x50\x0a\x93\xf4\xed\xff\x48\xbf\xec\x69\xef\x25\x4b\x86\x10\xc8\x2c\xc2\xa0\xef\xc0\x95\xa0\xab\x9f\x75\xc4\xc6\xd7\xce\x98\xda\xd0\x39\xb0\x8b\x6d\x55\xc4\xbf\x06\xf7\xa6\xda\x45\x05\x1d\x54\xe6\xbe\x73\x7d\xc0\x06\xb6\x3c\xac\x2f\xa4\x86\x40\x32\x1b\x6b\x93\x5a\xc2\xef\xad\xeb\xb8\x0d\xb6\xa1\xca\xa0\xae\x5d\x7e\xd5\x0f\xbb\x1e\x62\x8f\x05\x58\x6c\x57\xc2\xcf\x09\xf2\x07\xb7\x11\x93\xad\x2b\x58\x45\x29\x5d\x2b\x7b\x28\x1e\x90\x5e\xfb\x8a\xcd\xa4\xd5\xb1\xed\x37\x05\xee\xa3\xa5\x52\x73\xc3\xdf\x00\xf0\xe3\x86\xe7\xee\x44\x84\x68\x5c\xf2\x73\x25\x59\x69\xb5\x36\x85\x46\xb2\x49\x91\x60\x55\x8d\x67\x09\x2c\xd9\x36\xb5\x63\xdb\xf6\x8b\xe8\xa9\x34\xe5\x9a\xbe\xe5\x31\x0b\xc1\xe3\x6c\xcc\x7b\x5d\xd7\x59\xbf\x7a\x86\x1f\xfa\x04\xf0\xbd\x9b\xae\x59\x8e\x4f\x56\x89\x4b\x7d\xa0\x99\xbc\xcb\xa7\xb0\x65\x5a\x16\x88\xac\xbd\x2a\x61\x81\x49\x17\x9f\x2e\xa1\x48\x79\x84\x59\x85\x2b\xe7\xb8\xbd\xab\xcd\x48\x47\x24\x79\xab\xef\xff\xbc\x6d\x8c\x14\x9a\xfb\x29\x19\xf6\xb4\xb7\xc2\x7c\xd0\x46\x57\xc3\xa1\xa6\x1b\xa6\x75\xc1\xeb\xb0\xa4\x85\x06\x1e\xaa\x2d\x7e\xae\x2e\xb6\x79\x35\x73\xc6\x8a\xa6\x70\x21\xe1\x62\x62\x07\xaa\x11\xb0\x02\x6e\x70\xf9\x65\x2b\x8c\x58\x02\x01\x5a\x08\x28\x10\x28\xd2\x7d\x9a\x77\xb4\x99\xea\x48\xd9\x95\xcf\x1c\x12\x75\x80\x0d\x68\xd8\x79\xc8\x73\xeb\x1f\xc1\x9d\x5c\x13\xf9\xb3\xc8\xad\xb2\xa4\x36\xdb\x26\x84\x1a\x8f\x9e\x45\xe4\xb4\xf5\xdb\xc5\x19\xe2\x6f\x3c\x9c\x72\xb3\xae\xea\xa5\x37\x89\x52\xdc\x89\x08\xa1\xfc\xff\x68\x44\x87\x58\xd1\x2f\x86\x97\xa2\x80\xdb\xbf\xe3\xfc\x0a\x5d\x7c\x4b\x7f\x6d\x34\xa4\x44\x32\x0f\x94\xb7\xd5\x88\xbf\x32\xd9\xb6\xa3\x62\x33\xba\x3c\x47\x64\x02\x54\x2f\x62\xcf\x4c\x3b\x20\x64\x3a\x5d\x7d\xc0\x3d\x83\x20\x64\xe9\x6e\x44\x0f\xbd\xf5\xa1\x3a\x5e\x8a\x5e\xf5\x8b\xc6\x8c\xc9\x83\xed\x8d\x43\xe5\x64\x9d\xe2\x47\xdf\x90\x59\x21\x84\x0b\x3b\xab\x67\xba\x08\xe4\x56\x9f\x48\xaa\xe3\x32\x28\xf8\x95\x89\xc4\xc0\xeb\x9c\x85\x67\xfc\x5f\x64\xe0\xc2\x6d\x0b\x74\x1d\x93\xc6\x9f\xbb\x4e\x81\x6e\xbe\x91\xf6\x22\xf5\x72\x16\x7c\x11\xd5\x0d\x4c\x0e\x25\xe3\x16\xe5\x94\x24\xca\x17\x5a\x28\x10\xde\xe2\xfe\xe9\x46\x0d\x9e\xf0\xab\x25\x3f\xbb\x59\x8e\x20\x60\xcf\x61\x27\xb9\x3d\x8e\xc1\x95\xc1\xaa\x30\x74\x53\xa3\x22\x16\xd4\xa5\x8f\x44\x11\x12\x78\xde\xb4\x7e\x6c\xc5\x70\x23\xd4\x9c\x79\x78\x37\xa9\x1b\xb0\x25\x96\x10\x7d\xe6\x15\x0d\x7e\x42\x9f\xed\xfe\x21\x33\x91\xad\x03\x6a\xd0\xe2\x15\x20\x98\xff\x87\xf4\xd7\xab\xec\x92\x90\x8f\xb3\x71\xc1\x89\x01\xd1\x3c\x51\xf1\xcc\xd7\xd1\x68\x3b\x33\x1d\x09\xca\x00\x1a\xbd\xd9\x43\x50\x83\x2a\xb6\x5a\x6d\xf9\x51\xce\x67\x59\x04\xba\xc1\x2f\x5b\xbc\x65\x04\xb6\x46\xbd\xe4\x29\x79\x09\x75\x94\x70\x4f\xa9\xb5\x5e\xaf\xcb\x49\x83\x67\xd1\xf9\xeb\xf6\x40\x1c\x5e\x51\xb6\x16\xdd\xb8\xed\x6f\x24\x45\x8b\xcb\x18\xb6\x34\x27\xdd\xd5\x87\x6e\xb0\xb0\x3e\x9e\x1b\xee\xd1\x43\x2b\xbb\xc9\x4c\x26\x75\x9c\xd7\xc5\x4a\xe6\x1e\x6d\x50\x06\x4c\xa8\x93\xbe\x34\x91\x62\x42\xf7\x8f\xcd\x01\xa5\xf3\x83\x4f\x9e\xd0\x41\x49\x5a\x94\xb0\xfa\x5c\x12\xfa\x5d\x6c\x04\x02\x9e\xa1\xb8\x20\xab\xc0\xe2\x18\x0b\xf0\xfc\x49\xfd\xf1\xd6\x81\x2f\xa3\x28\x13\x7e\x39\xbb\x7c\xca\x07\x6a\x0c\xd9\x6b\xc9\xf7\x9f\xce\xee\x8c\x33\x21\x44\xf6\xb4\xab\xc3\x5f\x3e\xc1\x80\x01\x4a\x2b\x53\xee\x40\x8f\xb7\x7a\xe6\x0a\x0f\xce\xa7\x9c\xa5\xf2\x47\xc9\x54\x4a\x7d\x81\xb0\xba\x96\x39\x27\x7b\x53\xfb\x22\x20\xb7\x41\x1e\x2d\x99\xa6\x2f\x12\x3b\xb1\x3e\x9f\x29\x4f\x74\xed\x68\xf6\x16\x37\x0c\x45\x38\x20\x58\x3b\x04\x75\xed\xa8\x90\x94\xdb\xd6\xf9\x80\x62\xd9\x79\xae\x70\x95\x4d\x0a\x73\xfc\xa9\x83\x06\x5c\x08\xd6\x47\xec\xe2\x75\x92\xa3\xf4\x3e\xd1\x5a\xde\x6b\x08\xbd\x80\x5c\x1c\x96\xb4\x2f\xf5\xda\x14\x81\x61\xc7\x5e\x22\xfb\x2b\xa0\x49\x69\x0e\xf9\x03\x3d\x1d\xb5\xfe\x2f\x6c\xd7\xbf\x55\x0b\x4b\xd8\xe8\x4d\x89\x31\x79\xd7\xb7\xe8\xe5\x31\x54\x5e\x42\xcb\x22\xde\x7f\x2f\x84\x03\x9c\xe1\x3e\x1c\xe9\xca\x0a\xc1\x44\x5e\x89\x1a\x3e\x33\x80\x76\x1f\xb0\x7a\x65\xf9\xa1\xe6\xe6\x8d\xac\x93\x24\x4f\x61\xca\xec\x70\xaa\x90\xb4\x66\x4b\xf7\x84\xbd\x46\xf1\x69\xa8\x61\x59\xc4\x29\x86\xfc\x82\x2f\x85\x1f\xb0\x70\x7e\xc0\x63\x15\x7a\xc6\xe1\x11\x64\x32\xbf\x2d\xf8\xd3\xaa\xd1\xa8\x51\xc7\x7f\xb7\x6b\x20\x3f\xe7\x28\x44\x8c\xd5\xc8\x1d\x0c\x4a\xae\xa5\x55\x58\xa7\x26\x83\xcb\x3a\x17\x80\x21\x8c\xec\x95\x6d\xb4\xf2\x6a\xa0\x92\x76\x12\x2e\x87\x76\xc9\x51\xf8\x04\xd5\x96\x9d\x56\x83\x05\xc1\xef\x58\x52\x22\x80\x50\xb3\x8a\xf0\x34\x59\x15\xb6\x99\xa2\x7d\x28\xe1\xa7\xbe\xb3\x32\xa9\xd5\xd9\xb4\x99\x8b\xb5\x32\x4c\x4c\xe1\xd1\x33\x14\x6a\x08\x97\xff\xba\xfc\xbc\x74\xb8\x6c\xc3\x31\x1b\x6b\x79\x57\xa1\x56\x5d\x6d\x4b\x19\x19\x51\x1b\x85\x75\x45\xfd\x59\xff\xfd\xe1\xb5\x7b\x6e\xde\xca\xb5\x61\x93\xb5\x02\x85\x24\x72\x8a\xad\xde\xb1\x41\x83\x7f\xea\xef\xf2\x82\x00\xe5\x39\xf8\x31\xf0\xc1\xd6\xc0\xf3\xdb\x8c\x23\x11\x26\x60\xa4\x5a\x76\x33\xaa\x62\xf0\x04\x2c\x99\x75\x94\xa7\xd9\x97\x04\x65\xb0\x3c\xa0\x47\x6b\x92\x27\x32\x8c\x3f\x60\xd2\xd1\x4f\xc8\x45\xb0\x5a\x46\x98\x2a\xb2\x73\x41\x2a\x53\xf0\x55\x12\x18\x5a\x11\x92\x87\x01\x08\x46\x7d\xfd\xda\x4f\x3e\x7d\x89\xed\x4f\x35\x62\x6a\xc9\x14\xde\x69\x16\xc9\x5a\xca\x3a\x78\x5f\x96\x19\x70\x02\x59\x43\x3d\x07\x05\xba\x1c\xbb\x9e\x0f\xc3\x0d\xfa\x4f\xe6\x96\x1c\x20\x97\xfa\xeb\xe5\x33\x47\xd6\xa2\x27\x8d\xa9\xab\x5b\xbf\xd9\x09\x89\x05\xe6\xa6\x39\xeb\x6f\x76\x98\xbc\x1a\xd7\x53\x30\xd4\x42\x5a\x0b\xc3\x96\xa8\x87\x4a\x32\x0b\x87\xb5\x60\xe4\xe9\x12\x9a\x70\x96\xcb\xb5\xce\x04\xaa\xb7\xfa\x11\x64\x5a\xf7\x92\xaf\x37\x6e\xd6\xf1\xc8\x46\x1d\x8e\x5a\x27\x1f\xde\x68\xa8\x1c\x30\xc1\xd2\x5c\xe0\x30\x26\x7f\x53\x4a\x7d\x5a\x81\x3e\xf8\x70\x9a\xc4\x73\x32\x43\xd4\x3b\x80\x6f\x7e\xd7\xb5\x19\xfb\xab\x51\x12\xff\x60\x72\x3a\x11\x89\x15\x99\x9c\x9d\xec\x72\x5f\xf4\xa5\xcb\xf3\xa6\xc6\x15\xf2\xe7\x7c\xaa\xce\x02\x5c\xa5\x20\x49\xb8\xe4\xd1\x72\x5a\x20\xcc\xc0\x4e\x88\x0f\x7b\xba\x8b\x0a\xf8\xc9\x37\x31\x71\xa2\x20\xe5\x4e\x2e\xbd\x5b\xe3\xd5\x31\xc5\x2c\xb0\xd0\x17\xc3\x6c\x71\x02\x02\xb2\xa0\x38\x28\xbb\x76\x7d\xc0\x70\x13\xc6\x0b\x3a\x1a\x53\x6c\x68\x57\x3a\x6b\x34\x31\x8e\xcd\x2e\x9b\xdd\xcd\x14\x17\xf8\x54\xc1\x84\xc8\x29\x62\x9f\x3d\x02\xb6\xfd\x63\x23\xa7\x39\x3f\x38\xef\x06\xe6\xfc\x72\x6c\x3d\x97\x21\x15\xf4\x04\xe5\x69\xae\x9d\xe2\x56\xb2\xbe\x24\xe4\x90\xb5\x12\x35\xf3\xb1\x00\xf7\x27\x71\xca\xb3\x72\xed\x55\xec\x22\x79\x22\xc5\x32\x85\x84\x60\xa7\x7a\x43\xa7\xd5\x82\x45\x58\x9d\x4b\xba\x3e\x85\x92\x0e\x12\x24\xc7\x8f\xdf\x7f\x9f\x97\xc7\x52\x8a\x51\x8b\x90\x20\x4e\xe0\x39\x7a\x13\x0b\xaf\xac\x2a\x40\x25\x8a\x52\x25\xfc\x6a\x2c\xeb\xbf\x28\x25\x79\x2a\xef\x7c\x78\x3f\xee\xfb\x91\xde\x24\x63\x13\x14\x8e\x4e\x5f\xe0\x2b\xd6\x69\x2b\x84\x5a\x2b\xc6\xbb\x13\x43\xd2\xbc\x29\x95\x6d\x3d\x34\xd7\x95\xf1\x06\xf3\xcc\x26\x91\x53\x19\x2d\xe2\xc1\x5a\x3a\x0b\x89\x32\x2c\x31\x4e\x72\x81\x5d\x48\x39\x70\x39\xfa\xaa\x58\x8f\x64\x93\xa6\xcd\x05\x92\xad\xbe\x6b\x03\x66\xc3\xba\xc7\x55\x35\x41\xc4\xd2\x53\xd0\xef\x02\xe8\xdb\x81\xc8\xb7\x3d\xfb\xce\x62\x25\x68\x2a\x4e\xc3\x84\xd2\x53\x49\xf1\xc5\xfe\x6b\x4d\x5c\xdc\xfc\x77\xcb\xee\x84\x91\x36\xe8\xa7\xf4\xa1\x44\x92\x35\x3b\x53\x5b\x82\x62\xf8\xa1\x7d\x00\x9e\xc1\x59\x71\xa0\x77\xec\x59\x10\x70\x7d\x51\xcd\x39\xd1\x29\x93\x64\xdc\x94\x37\x66\xec\x1e\xe6\x54\x82\x07\xa4\x7e\x3b\xc5\x37\x6f\x7d\xf8\xbb\x96\x42\x73\xf6\x86\x00\xfd\x94\xb3\x20\xb4\x7c\x78\xfb\xcf\xb7\x15\xeb\xee\xa1\x46\xd7\x48\x52\x90\x41\x3e\x03\x16\x03\xc0\xcf\x5a\x6c\x73\x2c\xa2\x23\x26\xf1\x03\x9f\x4e\x1d\x56\x7c\x72\x9c\x45\x85\xb7\x34\x6d\xb1\xd4\x91\x8d\xd2\xf0\x17\xb4\x6d\x5c\x5c\xc7\x62\xda\x51\x5f\x28\x88\x15\x1f\xa7\x5f\xd3\xff\x61\xf1\xc2\xa6\xcf\x4e\x07\xa6\x73\xe5\xa0\xf4\x4c\x40\x66\xeb\x94\xe2\xe0\x82\x06\xbd\x70\xca\x21\x14\xa9\x84\x7a\x47\x37\x68\xb0\x65\x0f\x1d\x3e\x76\x25\xd7\xbb\xcf\x61\x26\x12\x98\xbe\x16\x6b\xdc\x42\xce\x93\x12\x1b\x7b\xa2\xf7\xbc\x26\x49\x18\x08\xab\x02\x1b\x6d\xb1\x10\x2a\xbd\x98\xf7\x2f\x98\x89\xe6\x0b\x6b\x5b\xe4\xa6\x8c\x2b\x6d\xa5\xb2\xa4\xde\x52\xf6\x1c\x6e\xe2\x28\x85\xab\x71\x5c\x0c\xd6\xeb\xd7\x0e\xb1\x14\x5c\x04\x89\x7f\x17\xc9\x61\x29\xb0\xd3\xd1\x24\x40\x21\xc0\xc8\xe5\xd8\xd2\x37\xb8\xf5\x56\x40\x2a\xdf\x33\xe9\x4b\x41\x8c\xde\xbf\x43\x2b\xf6\xe9\x0a\x16\x97\xc8\xa0\x2c\x80\xa1\xe1\x31\x26\xcf\xef\xec\x55\xa2\xae\x0c\xd4\x4e\xb8\xfc\x31\xf2\x86\xe8\x14\x26\x95\x63\xe8\x95\x65\x64\x4b\xfd\xf4\x7f\x7a\xa9\x01\x23\xe2\x7d\x88\x1f\xfa\x93\x6f\x73\x8c\x22\x6a\xaa\xe1\x12\x63\x01\xb3\x98\x51\xb8\x34\x93\x1b\x7a\x68\xea\xf8\x78\xc3\xd3\x2f\x36\xb7\x4a\x40\xa9\x36\x8b\xfe\x4f\x45\x11\xd1\xaf\x75\xbd\x61\xa7\x19\xc5\xe8\xfb\x0e\xf3\xb2\x93\xa2\xc7\x38\x7d\xc9\x66\x06\xc3\xfd\x75\x47\x00\xb8\xa5\x4a\xaa\xd5\x18\x06\x96\x3a\xab\xe8\xbb\x89\x73\xd3\x70\xe3\xd5\x7c\x64\xd9\xb3\x7a\x53\x7b\xb4\x87\x7e\x16\x9d\x9d\x7d\xf1\x2f\xa0\x1a\x7d\xf1\x9b\xd8\x32\x01\x85\x5f\xbd\xb4\x8c\x9a\x78\xe3\x94\xcf\xa6\x13\xbd\xbc\x72\x82\xc0\xf2\xf9\xbf\x8f\x61\x66\xff\xc5\x79\x8a\xe7\x2c\x6d\xc9\xd9\x84\x3d\xe9\x4b\xd8\xbe\x1b\x97\x40\x65\x17\xe7\x5c\x11\x04\xd6\xca\x91\x1b\xa3\xfc\x28\x94\x25\xe9\x73\x8a\x4e\xc4\x99\x7a\x21\xd3\xe2\x28\x36\xd9\x0c\xad\xbf\x40\x57\x68\x40\xa0\x45\xfa\x69\x94\xef\x1c\x2d\x0b\x3e\x49\x37\x9a\x59\xb4\x24\x95\x11\x16\x6b\x53\xd2\xbc\x1a\x05\x70\xd7\x9b\x45\x7b\xc9\xc8\xcb\x40\xb8\x94\xd4\xb9\x46\xdb\xa5\xbf\x81\x86\x9e\x43\x7e\x43\xf7\x15\xf1\x52\xce\xb3\xa4\x5d\xcb\x66\x23\xc8\x67\x28\x7e\x48\xca\xcf\x30\x75\x6d\xa5\x59\x62\xfd\x7f\xcb\xdf\x33\xd4\x98\x6a\xc3\xdd\x85\x31\xa8\xd1\xfa\x43\xa1\x9c\x22\x1a\xb7\xd0\xc3\x0c\xb5\xd1\x15\x1f\x7a\x6e\x2e\xac\xc0\xf7\x1b\xc5\x53\xfd\x24\xac\x0d\x9e\x37\xaa\x0f\x2d\xa9\xa1\x31\x36\xd6\x1f\x01\xfe\xe7\xa0\xfc\x00\x23\xc0\x69\x88\x36\x41\xa5\xa8\x4b\x22\xa9\xcc\x18\x54\x72\x32\x98\x81\x94\x31\x9b\x0b\xef\x22\xb1\x0e\x7a\x48\xbb\x61\x49\xb4\x62\xf8\x5b\xb5\x2b\x8b\xf1\xd3', 2) -------------------------------------------------------------------------------- /linkedin.py: -------------------------------------------------------------------------------- 1 | import time,math,random,os 2 | import utils,constants,config 3 | import platform 4 | 5 | from selenium import webdriver 6 | from selenium.webdriver.common.by import By 7 | from utils import prRed,prYellow,prGreen 8 | 9 | from selenium.webdriver.firefox.service import Service 10 | from selenium.webdriver.firefox.options import Options 11 | 12 | class Linkedin: 13 | def __init__(self): 14 | browser = config.browser[0].lower() 15 | linkedinEmail = config.email 16 | if (browser == "firefox"): 17 | if (len(linkedinEmail)>0): 18 | print(platform.system()) 19 | if (platform.system == "Linux"): 20 | prYellow("On Linux you need to define profile path to run the bot with Firefox. Go about:profiles find root directory of your profile paste in line 8 of config file next to firefoxProfileRootDir ") 21 | exit() 22 | else: 23 | self.driver = webdriver.Firefox() 24 | self.driver.get("https://www.linkedin.com/login?trk=guest_homepage-basic_nav-header-signin") 25 | prYellow("Trying to log in linkedin.") 26 | try: 27 | self.driver.find_element("id","username").send_keys(linkedinEmail) 28 | self.driver.find_element("id","password").send_keys(config.password) 29 | time.sleep(5) 30 | self.driver.find_element("xpath",'//*[@id="organic-div"]/form/div[3]/button').click() 31 | except Exception as e: 32 | prRed(e) 33 | else: 34 | self.driver = webdriver.Firefox() 35 | elif (browser == "chrome"): 36 | self.driver = webdriver.Chrome() 37 | self.driver.get("https://www.linkedin.com/login?trk=guest_homepage-basic_nav-header-signin") 38 | prYellow("Trying to log in linkedin.") 39 | try: 40 | self.driver.find_element("id","username").send_keys(linkedinEmail) 41 | time.sleep(5) 42 | self.driver.find_element("id","password").send_keys(config.password) 43 | time.sleep(5) 44 | self.driver.find_element("xpath",'//*[@id="organic-div"]/form/div[3]/button').click() 45 | except: 46 | prRed("Couldnt log in Linkedin by using chrome please try again for Firefox by creating a firefox profile.") 47 | 48 | # driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) 49 | # webdriver.Chrome(ChromeDriverManager().install()) 50 | # webdriver.Firefox(options=utils.browserOptions()) 51 | 52 | def generateUrls(self): 53 | if not os.path.exists('data'): 54 | os.makedirs('data') 55 | try: 56 | with open('data/urlData.txt', 'w',encoding="utf-8" ) as file: 57 | linkedinJobLinks = utils.LinkedinUrlGenerate().generateUrlLinks() 58 | for url in linkedinJobLinks: 59 | file.write(url+ "\n") 60 | prGreen("Urls are created successfully, now the bot will visit those urls.") 61 | except: 62 | prRed("Couldnt generate url, make sure you have /data folder and modified config.py file for your preferances.") 63 | 64 | def linkJobApply(self): 65 | self.generateUrls() 66 | countApplied = 0 67 | countJobs = 0 68 | 69 | urlData = utils.getUrlDataFile() 70 | 71 | for url in urlData: 72 | self.driver.get(url) 73 | try: 74 | totalJobs = self.driver.find_element(By.XPATH,'//small').text 75 | except: 76 | print("No Matching Jobs Found") 77 | continue 78 | totalPages = utils.jobsToPages(totalJobs) 79 | 80 | urlWords = utils.urlToKeywords(url) 81 | lineToWrite = "\n Category: " + urlWords[0] + ", Location: " +urlWords[1] + ", Applying " +str(totalJobs)+ " jobs." 82 | self.displayWriteResults(lineToWrite) 83 | 84 | for page in range(totalPages): 85 | currentPageJobs = constants.jobsPerPage * page 86 | url = url +"&start="+ str(currentPageJobs) 87 | self.driver.get(url) 88 | time.sleep(random.uniform(1, constants.botSpeed)) 89 | 90 | offersPerPage = self.driver.find_elements(By.XPATH,'//li[@data-occludable-job-id]') 91 | 92 | offerIds = [] 93 | for offer in offersPerPage: 94 | offerId = offer.get_attribute("data-occludable-job-id") 95 | offerIds.append(int(offerId.split(":")[-1])) 96 | 97 | for jobID in offerIds: 98 | offerPage = 'https://www.linkedin.com/jobs/view/' + str(jobID) 99 | self.driver.get(offerPage) 100 | time.sleep(random.uniform(1, constants.botSpeed)) 101 | 102 | countJobs += 1 103 | 104 | jobProperties = self.getJobProperties(countJobs) 105 | 106 | button = self.easyApplyButton() 107 | 108 | if button is not False: 109 | button.click() 110 | time.sleep(random.uniform(1, constants.botSpeed)) 111 | countApplied += 1 112 | try: 113 | self.driver.find_element(By.CSS_SELECTOR, "button[aria-label='Submit application']").click() 114 | time.sleep(random.uniform(1, constants.botSpeed)) 115 | 116 | lineToWrite = jobProperties + " | " + "* 🥳 Just Applied to this job: " +str(offerPage) 117 | self.displayWriteResults(lineToWrite) 118 | 119 | except: 120 | try: 121 | self.driver.find_element(By.CSS_SELECTOR,"button[aria-label='Continue to next step']").click() 122 | time.sleep(random.uniform(1, constants.botSpeed)) 123 | comPercentage = self.driver.find_element(By.XPATH,'html/body/div[3]/div/div/div[2]/div/div/span').text 124 | percenNumber = int(comPercentage[0:comPercentage.index("%")]) 125 | result = self.applyProcess(percenNumber,offerPage) 126 | lineToWrite = jobProperties + " | " + result 127 | self.displayWriteResults(lineToWrite) 128 | 129 | except Exception as e: 130 | try: 131 | self.driver.find_element(By.CSS_SELECTOR,"option[value='urn:li:country:" + config.country_code + "']").click() 132 | time.sleep(random.uniform(1, constants.botSpeed)) 133 | self.driver.find_element(By.CSS_SELECTOR, 'input').send_keys(config.phone_number); 134 | time.sleep(random.uniform(1, constants.botSpeed)) 135 | self.driver.find_element(By.CSS_SELECTOR,"button[aria-label='Continue to next step']").click() 136 | time.sleep(random.uniform(1, constants.botSpeed)) 137 | comPercentage = self.driver.find_element(By.XPATH,'html/body/div[3]/div/div/div[2]/div/div/span').text 138 | percenNumber = int(comPercentage[0:comPercentage.index("%")]) 139 | result = self.applyProcess(percenNumber,offerPage) 140 | lineToWrite = jobProperties + " | " + result 141 | self.displayWriteResults(lineToWrite) 142 | except Exception as e: 143 | lineToWrite = jobProperties + " | " + "* 🥵 Cannot apply to this Job! " +str(offerPage) 144 | self.displayWriteResults(lineToWrite) 145 | else: 146 | lineToWrite = jobProperties + " | " + "* 🥳 Already applied! Job: " +str(offerPage) 147 | self.displayWriteResults(lineToWrite) 148 | 149 | 150 | prYellow("Category: " + urlWords[0] + "," +urlWords[1]+ " applied: " + str(countApplied) + 151 | " jobs out of " + str(countJobs) + ".") 152 | 153 | # utils.donate(self) 154 | 155 | def getJobProperties(self, count): 156 | textToWrite = "" 157 | jobTitle = "" 158 | jobCompany = "" 159 | jobLocation = "" 160 | jobWOrkPlace = "" 161 | jobPostedDate = "" 162 | jobApplications = "" 163 | 164 | try: 165 | jobTitle = self.driver.find_element(By.XPATH,"//h1[contains(@class, 'job-title')]").get_attribute("innerHTML").strip() 166 | except Exception as e: 167 | prYellow("Warning in getting jobTitle: " +str(e)[0:50]) 168 | jobTitle = "" 169 | try: 170 | jobCompany = self.driver.find_element(By.XPATH,"//a[contains(@class, 'ember-view t-black t-normal')]").get_attribute("innerHTML").strip() 171 | except Exception as e: 172 | prYellow("Warning in getting jobCompany: " +str(e)[0:50]) 173 | jobCompany = "" 174 | try: 175 | jobLocation = self.driver.find_element(By.XPATH,"//span[contains(@class, 'bullet')]").get_attribute("innerHTML").strip() 176 | except Exception as e: 177 | prYellow("Warning in getting jobLocation: " +str(e)[0:50]) 178 | jobLocation = "" 179 | try: 180 | jobWOrkPlace = self.driver.find_element(By.XPATH,"//span[contains(@class, 'workplace-type')]").get_attribute("innerHTML").strip() 181 | except Exception as e: 182 | prYellow("Warning in getting jobWorkPlace: " +str(e)[0:50]) 183 | jobWOrkPlace = "" 184 | try: 185 | jobPostedDate = self.driver.find_element(By.XPATH,"//span[contains(@class, 'posted-date')]").get_attribute("innerHTML").strip() 186 | except Exception as e: 187 | prYellow("Warning in getting jobPostedDate: " +str(e)[0:50]) 188 | jobPostedDate = "" 189 | try: 190 | jobApplications= self.driver.find_element(By.XPATH,"//span[contains(@class, 'applicant-count')]").get_attribute("innerHTML").strip() 191 | except Exception as e: 192 | prYellow("Warning in getting jobApplications: " +str(e)[0:50]) 193 | jobApplications = "" 194 | 195 | textToWrite = str(count)+ " | " +jobTitle+ " | " +jobCompany+ " | " +jobLocation+ " | " +jobWOrkPlace+ " | " +jobPostedDate+ " | " +jobApplications 196 | return textToWrite 197 | 198 | def easyApplyButton(self): 199 | try: 200 | button = self.driver.find_element(By.XPATH, 201 | '//button[contains(@class, "jobs-apply-button")]') 202 | EasyApplyButton = button 203 | except: 204 | EasyApplyButton = False 205 | 206 | return EasyApplyButton 207 | 208 | def applyProcess(self, percentage, offerPage): 209 | applyPages = math.floor(100 / percentage) 210 | result = "" 211 | try: 212 | for pages in range(applyPages-2): 213 | self.driver.find_element(By.CSS_SELECTOR,"button[aria-label='Continue to next step']").click() 214 | time.sleep(random.uniform(1, constants.botSpeed)) 215 | 216 | self.driver.find_element(By.CSS_SELECTOR,"button[aria-label='Review your application']").click() 217 | time.sleep(random.uniform(1, constants.botSpeed)) 218 | 219 | if config.followCompanies is False: 220 | self.driver.find_element(By.CSS_SELECTOR,"label[for='follow-company-checkbox']").click() 221 | time.sleep(random.uniform(1, constants.botSpeed)) 222 | 223 | self.driver.find_element(By.CSS_SELECTOR,"button[aria-label='Submit application']").click() 224 | time.sleep(random.uniform(1, constants.botSpeed)) 225 | 226 | result = "* 🥳 Just Applied to this job: " +str(offerPage) 227 | except: 228 | result = "* 🥵 " +str(applyPages)+ " Pages, couldn't apply to this job! Extra info needed. Link: " +str(offerPage) 229 | return result 230 | 231 | def displayWriteResults(self,lineToWrite: str): 232 | try: 233 | print(lineToWrite) 234 | utils.writeResults(lineToWrite) 235 | except Exception as e: 236 | prRed("Error in DisplayWriteResults: " +str(e)) 237 | 238 | 239 | start = time.time() 240 | while True: 241 | try: 242 | Linkedin().linkJobApply() 243 | except Exception as e: 244 | prRed("Error in main: " +str(e)) 245 | # close firefox driver 246 | end = time.time() 247 | prYellow("---Took: " + str(round((time.time() - start)/60)) + " minute(s).") 248 | Linkedin().driver.quit() 249 | -------------------------------------------------------------------------------- /requirements.yaml: -------------------------------------------------------------------------------- 1 | selenium 2 | webdriver_manager -------------------------------------------------------------------------------- /simple.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.by import By 3 | 4 | driver = webdriver.Firefox() 5 | 6 | driver.get("https://www.selenium.dev/selenium/web/web-form.html") 7 | 8 | title = driver.title 9 | 10 | driver.implicitly_wait(0.5) 11 | 12 | text_box = driver.find_element(by=By.NAME, value="my-text") 13 | submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button") 14 | 15 | text_box.send_keys("Selenium") 16 | submit_button.click() 17 | 18 | message = driver.find_element(by=By.ID, value="message") 19 | text = message.text 20 | 21 | driver.quit() -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import os,time,sys 2 | 3 | from selenium import webdriver 4 | from selenium.webdriver.firefox.options import Options 5 | 6 | from utils import prGreen,prRed,prYellow 7 | 8 | 9 | prYellow("ℹ️ This script will check if the bot can automatically log in Linkedin for you.") 10 | 11 | def checkPython(): 12 | try: 13 | if(sys.version): 14 | prGreen("✅ Python is succesfully installed!") 15 | else: 16 | prRed("❌ Python is not installed please install Python first: https://www.python.org/downloads/") 17 | except Exception as e: 18 | prRed(e) 19 | 20 | def checkPip(): 21 | try: 22 | import pip 23 | prGreen("✅ Pip is succesfully installed!") 24 | except ImportError: 25 | prRed("❌ Pip not present. Install pip: https://pip.pypa.io/en/stable/installation/") 26 | 27 | def checkSelenium(): 28 | try: 29 | import selenium 30 | prGreen("✅ Selenium is succesfully installed!") 31 | except ImportError: 32 | prRed("❌ Selenium not present. Install Selenium: https://pypi.org/project/selenium/") 33 | 34 | def checkFirefox(): 35 | try: 36 | import subprocess 37 | output = subprocess.check_output(['firefox', '--version']) 38 | if(output): 39 | prGreen("✅ Firefox is succesfully installed!") 40 | else: 41 | prRed("❌ Firefox not present. Install firefox: https://www.mozilla.org/en-US/firefox/") 42 | 43 | except ImportError as e: 44 | prRed(e) 45 | 46 | def checkSeleniumLinkedin(): 47 | 48 | options = Options() 49 | #firefoxProfileRootDir = os.getenv('firefoxProfileRootDir') 50 | 51 | options.add_argument("--start-maximized") 52 | options.add_argument("--ignore-certificate-errors") 53 | options.add_argument('--no-sandbox') 54 | options.add_argument("--disable-extensions") 55 | options.add_argument("--disable-blink-features") 56 | options.add_argument("--disable-blink-features=AutomationControlled") 57 | #options.add_argument("-profile") 58 | #options.add_argument(firefoxProfileRootDir) 59 | #options.headless = True 60 | 61 | browser = webdriver.Firefox(options=options) 62 | 63 | try: 64 | browser.get('https://www.ongundemirag.com') 65 | if(browser.title.index("Ongun")>-1): 66 | prGreen("✅ Selenium and geckodriver is working succesfully!") 67 | else: 68 | prRed("❌ Please check if Selenium and geckodriver is installed") 69 | except Exception as e: 70 | prRed(e) 71 | 72 | try: 73 | browser.get('https://www.linkedin.com/feed/') 74 | time.sleep(3) 75 | if "Feed" in browser.title: 76 | prGreen('✅ Successfully you are logged in to Linkedin, you can now run main bot script!') 77 | else: 78 | prRed('❌ You are not automatically logged in, please set up your Firefox Account correctly.') 79 | except Exception as e: 80 | prRed(e) 81 | finally: 82 | browser.quit() 83 | 84 | 85 | 86 | checkPython() 87 | checkPip() 88 | checkSelenium() 89 | checkFirefox() 90 | checkSeleniumLinkedin() 91 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import math,constants,config 2 | from typing import List 3 | import time 4 | 5 | from selenium.webdriver.firefox.options import Options 6 | 7 | def browserOptions(): 8 | options = Options() 9 | firefoxProfileRootDir = config.firefoxProfileRootDir 10 | options.add_argument("--start-maximized") 11 | options.add_argument("--ignore-certificate-errors") 12 | options.add_argument('--no-sandbox') 13 | options.add_argument("--disable-extensions") 14 | options.add_argument('--disable-gpu') 15 | if(config.headless): 16 | options.add_argument("--headless") 17 | 18 | options.add_argument("--disable-blink-features") 19 | options.add_argument("--disable-blink-features=AutomationControlled") 20 | options.add_argument("--incognito") 21 | options.add_argument("-profile") 22 | options.add_argument(firefoxProfileRootDir) 23 | 24 | return options 25 | 26 | def prRed(prt): 27 | print(f"\033[91m{prt}\033[00m") 28 | 29 | def prGreen(prt): 30 | print(f"\033[92m{prt}\033[00m") 31 | 32 | def prYellow(prt): 33 | print(f"\033[93m{prt}\033[00m") 34 | 35 | def getUrlDataFile(): 36 | urlData = "" 37 | try: 38 | file = open('data/urlData.txt', 'r') 39 | urlData = file.readlines() 40 | except FileNotFoundError: 41 | text = "FileNotFound:urlData.txt file is not found. Please run ./data folder exists and check config.py values of yours. Then run the bot again" 42 | prRed(text) 43 | return urlData 44 | 45 | def jobsToPages(numOfJobs: str) -> int: 46 | number_of_pages = 1 47 | 48 | if (' ' in numOfJobs): 49 | spaceIndex = numOfJobs.index(' ') 50 | totalJobs = (numOfJobs[0:spaceIndex]) 51 | totalJobs_int = int(totalJobs.replace(',', '')) 52 | number_of_pages = math.ceil(totalJobs_int/constants.jobsPerPage) 53 | if (number_of_pages > 40 ): number_of_pages = 40 54 | 55 | else: 56 | number_of_pages = int(numOfJobs) 57 | 58 | return number_of_pages 59 | 60 | def urlToKeywords(url: str) -> List[str]: 61 | keywordUrl = url[url.index("keywords=")+9:] 62 | keyword = keywordUrl[0:keywordUrl.index("&") ] 63 | locationUrl = url[url.index("location=")+9:] 64 | location = locationUrl[0:locationUrl.index("&") ] 65 | return [keyword,location] 66 | 67 | def writeResults(text: str): 68 | timeStr = time.strftime("%Y%m%d") 69 | fileName = "Applied Jobs DATA - " +timeStr + ".txt" 70 | try: 71 | with open("data/" +fileName, encoding="utf-8" ) as file: 72 | lines = [] 73 | for line in file: 74 | if "----" not in line: 75 | lines.append(line) 76 | 77 | with open("data/" +fileName, 'w' ,encoding="utf-8") as f: 78 | f.write("---- Applied Jobs Data ---- created at: " +timeStr+ "\n" ) 79 | f.write("---- Number | Job Title | Company | Location | Work Place | Posted Date | Applications | Result " +"\n" ) 80 | for line in lines: 81 | f.write(line) 82 | f.write(text+ "\n") 83 | 84 | except: 85 | with open("data/" +fileName, 'w', encoding="utf-8") as f: 86 | f.write("---- Applied Jobs Data ---- created at: " +timeStr+ "\n" ) 87 | f.write("---- Number | Job Title | Company | Location | Work Place | Posted Date | Applications | Result " +"\n" ) 88 | 89 | f.write(text+ "\n") 90 | 91 | def printInfoMes(bot:str): 92 | prYellow("ℹ️ " +bot+ " is starting soon... ") 93 | 94 | def donate(self): 95 | prYellow('If you like the project, please support me so that i can make more such projects, thanks!') 96 | try: 97 | self.driver.get('https://commerce.coinbase.com/checkout/576ee011-ba40-47d5-9672-ef7ad29b1e6c') 98 | except Exception as e: 99 | prRed("Error in donate: " +str(e)) 100 | 101 | class LinkedinUrlGenerate: 102 | def generateUrlLinks(self): 103 | path = [] 104 | for location in config.location: 105 | for keyword in config.keywords: 106 | url = constants.linkJobUrl + "?f_AL=true&keywords=" +keyword+self.jobType()+self.remote()+self.checkJobLocation(location)+self.jobExp()+self.datePosted()+self.salary()+self.sortBy() 107 | path.append(url) 108 | return path 109 | 110 | def checkJobLocation(self,job): 111 | jobLoc = "&location=" +job 112 | match job.casefold(): 113 | case "asia": 114 | jobLoc += "&geoId=102393603" 115 | case "europe": 116 | jobLoc += "&geoId=100506914" 117 | case "northamerica": 118 | jobLoc += "&geoId=102221843&" 119 | case "southamerica": 120 | jobLoc += "&geoId=104514572" 121 | case "australia": 122 | jobLoc += "&geoId=101452733" 123 | case "africa": 124 | jobLoc += "&geoId=103537801" 125 | 126 | return jobLoc 127 | 128 | def jobExp(self): 129 | jobtExpArray = config.experienceLevels 130 | firstJobExp = jobtExpArray[0] 131 | jobExp = "" 132 | match firstJobExp: 133 | case "Internship": 134 | jobExp = "&f_E=1" 135 | case "Entry level": 136 | jobExp = "&f_E=2" 137 | case "Associate": 138 | jobExp = "&f_E=3" 139 | case "Mid-Senior level": 140 | jobExp = "&f_E=4" 141 | case "Director": 142 | jobExp = "&f_E=5" 143 | case "Executive": 144 | jobExp = "&f_E=6" 145 | for index in range (1,len(jobtExpArray)): 146 | match jobtExpArray[index]: 147 | case "Internship": 148 | jobExp += "%2C1" 149 | case "Entry level": 150 | jobExp +="%2C2" 151 | case "Associate": 152 | jobExp +="%2C3" 153 | case "Mid-Senior level": 154 | jobExp += "%2C4" 155 | case "Director": 156 | jobExp += "%2C5" 157 | case "Executive": 158 | jobExp +="%2C6" 159 | 160 | return jobExp 161 | 162 | def datePosted(self): 163 | datePosted = "" 164 | match config.datePosted[0]: 165 | case "Any Time": 166 | datePosted = "" 167 | case "Past Month": 168 | datePosted = "&f_TPR=r2592000&" 169 | case "Past Week": 170 | datePosted = "&f_TPR=r604800&" 171 | case "Past 24 hours": 172 | datePosted = "&f_TPR=r86400&" 173 | return datePosted 174 | 175 | def jobType(self): 176 | jobTypeArray = config.jobType 177 | firstjobType = jobTypeArray[0] 178 | jobType = "" 179 | match firstjobType: 180 | case "Full-time": 181 | jobType = "&f_JT=F" 182 | case "Part-time": 183 | jobType = "&f_JT=P" 184 | case "Contract": 185 | jobType = "&f_JT=C" 186 | case "Temporary": 187 | jobType = "&f_JT=T" 188 | case "Volunteer": 189 | jobType = "&f_JT=V" 190 | case "Intership": 191 | jobType = "&f_JT=I" 192 | case "Other": 193 | jobType = "&f_JT=O" 194 | for index in range (1,len(jobTypeArray)): 195 | match jobTypeArray[index]: 196 | case "Full-time": 197 | jobType += "%2CF" 198 | case "Part-time": 199 | jobType +="%2CP" 200 | case "Contract": 201 | jobType +="%2CC" 202 | case "Temporary": 203 | jobType += "%2CT" 204 | case "Volunteer": 205 | jobType += "%2CV" 206 | case "Intership": 207 | jobType +="%2CI" 208 | case "Other": 209 | jobType +="%2CO" 210 | jobType += "&" 211 | return jobType 212 | 213 | def remote(self): 214 | remoteArray = config.remote 215 | firstJobRemote = remoteArray[0] 216 | jobRemote = "" 217 | match firstJobRemote: 218 | case "On-site": 219 | jobRemote = "f_WT=1" 220 | case "Remote": 221 | jobRemote = "f_WT=2" 222 | case "Hybrid": 223 | jobRemote = "f_WT=3" 224 | for index in range (1,len(remoteArray)): 225 | match remoteArray[index]: 226 | case "On-site": 227 | jobRemote += "%2C1" 228 | case "Remote": 229 | jobRemote += "%2C2" 230 | case "Hybrid": 231 | jobRemote += "%2C3" 232 | 233 | return jobRemote 234 | 235 | def salary(self): 236 | salary = "" 237 | match config.salary[0]: 238 | case "$40,000+": 239 | salary = "f_SB2=1&" 240 | case "$60,000+": 241 | salary = "f_SB2=2&" 242 | case "$80,000+": 243 | salary = "f_SB2=3&" 244 | case "$100,000+": 245 | salary = "f_SB2=4&" 246 | case "$120,000+": 247 | salary = "f_SB2=5&" 248 | case "$140,000+": 249 | salary = "f_SB2=6&" 250 | case "$160,000+": 251 | salary = "f_SB2=7&" 252 | case "$180,000+": 253 | salary = "f_SB2=8&" 254 | case "$200,000+": 255 | salary = "f_SB2=9&" 256 | return salary 257 | 258 | def sortBy(self): 259 | sortBy = "" 260 | match config.sort[0]: 261 | case "Recent": 262 | sortBy = "sortBy=DD" 263 | case "Relevent": 264 | sortBy = "sortBy=R" 265 | return sortBy 266 | --------------------------------------------------------------------------------