├── .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 | 
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 | 
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 | 
95 | 
96 | 
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 |
--------------------------------------------------------------------------------