lint
This commit is contained in:
parent
9cff8bf6ee
commit
3c09856232
@ -16,7 +16,6 @@ class LinkedInAuthenticator:
|
||||
self.password = password
|
||||
|
||||
def start(self):
|
||||
"""Start the Chrome browser and attempt to log in to LinkedIn."""
|
||||
print("Starting Chrome browser to log in to LinkedIn.")
|
||||
self.driver.get('https://www.linkedin.com')
|
||||
self.wait_for_page_load()
|
||||
@ -24,7 +23,6 @@ class LinkedInAuthenticator:
|
||||
self.handle_login()
|
||||
|
||||
def handle_login(self):
|
||||
"""Handle the LinkedIn login process."""
|
||||
print("Navigating to the LinkedIn login page...")
|
||||
self.driver.get("https://www.linkedin.com/login")
|
||||
try:
|
||||
@ -36,7 +34,6 @@ class LinkedInAuthenticator:
|
||||
self.handle_security_check()
|
||||
|
||||
def enter_credentials(self):
|
||||
"""Enter the user's email and password into the login form."""
|
||||
try:
|
||||
email_field = WebDriverWait(self.driver, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "username"))
|
||||
@ -48,7 +45,6 @@ class LinkedInAuthenticator:
|
||||
print("Login form not found. Aborting login.")
|
||||
|
||||
def submit_login_form(self):
|
||||
"""Submit the LinkedIn login form."""
|
||||
try:
|
||||
login_button = self.driver.find_element(By.XPATH, '//button[@type="submit"]')
|
||||
login_button.click()
|
||||
@ -56,7 +52,6 @@ class LinkedInAuthenticator:
|
||||
print("Login button not found. Please verify the page structure.")
|
||||
|
||||
def handle_security_check(self):
|
||||
"""Handle LinkedIn security checks if triggered."""
|
||||
try:
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.url_contains('https://www.linkedin.com/checkpoint/challengesV2/')
|
||||
@ -70,7 +65,6 @@ class LinkedInAuthenticator:
|
||||
print("Security check not completed. Please try again later.")
|
||||
|
||||
def is_logged_in(self):
|
||||
"""Check if the user is already logged in to LinkedIn."""
|
||||
self.driver.get('https://www.linkedin.com/feed')
|
||||
try:
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
@ -85,7 +79,6 @@ class LinkedInAuthenticator:
|
||||
return False
|
||||
|
||||
def wait_for_page_load(self, timeout=10):
|
||||
"""Wait for the page to fully load."""
|
||||
try:
|
||||
WebDriverWait(self.driver, timeout).until(
|
||||
lambda d: d.execute_script('return document.readyState') == 'complete'
|
||||
|
@ -1,4 +1,5 @@
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
@ -27,6 +28,31 @@ class LinkedInEasyApplier:
|
||||
self.set_old_answers = set_old_answers
|
||||
self.gpt_answerer = gpt_answerer
|
||||
self.resume_generator_manager = resume_generator_manager
|
||||
self.questions_data = []
|
||||
|
||||
|
||||
def _load_questions_from_json(self) -> List[dict]:
|
||||
output_file = 'answers.json'
|
||||
try:
|
||||
# Leggi i dati esistenti dal file
|
||||
try:
|
||||
with open(output_file, 'r') as f:
|
||||
try:
|
||||
all_data = json.load(f)
|
||||
if not isinstance(all_data, list):
|
||||
raise ValueError("JSON file format is incorrect. Expected a list of questions.")
|
||||
except json.JSONDecodeError:
|
||||
# Se il file è vuoto o non contiene JSON valido, inizializza come lista vuota
|
||||
all_data = []
|
||||
except FileNotFoundError:
|
||||
# Se il file non esiste, inizializza come lista vuota
|
||||
all_data = []
|
||||
|
||||
return all_data
|
||||
except Exception:
|
||||
tb_str = traceback.format_exc()
|
||||
raise Exception(f"Error loading questions data from JSON file: \nTraceback:\n{tb_str}")
|
||||
|
||||
|
||||
def job_apply(self, job: Any):
|
||||
self.driver.get(job.link)
|
||||
@ -191,7 +217,6 @@ class LinkedInEasyApplier:
|
||||
def _fill_additional_questions(self) -> None:
|
||||
form_sections = self.driver.find_elements(By.CLASS_NAME, 'jobs-easy-apply-form-section__grouping')
|
||||
for section in form_sections:
|
||||
outer_html = section.get_attribute('outerHTML')
|
||||
self._process_form_section(section)
|
||||
|
||||
|
||||
@ -222,6 +247,7 @@ class LinkedInEasyApplier:
|
||||
options = [radio.text.lower() for radio in radios]
|
||||
answer = self.gpt_answerer.answer_question_from_options(question_text, options)
|
||||
self._select_radio(radios, answer)
|
||||
self._save_questions_to_json({'type': 'radio', 'question': question_text, 'answer': answer})
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -232,8 +258,14 @@ class LinkedInEasyApplier:
|
||||
text_field = text_fields[0]
|
||||
question_text = section.find_element(By.TAG_NAME, 'label').text.lower()
|
||||
is_numeric = self._is_numeric_field(text_field)
|
||||
answer = self.gpt_answerer.answer_question_numeric(question_text) if is_numeric else self.gpt_answerer.answer_question_textual_wide_range(question_text)
|
||||
if is_numeric:
|
||||
answer = self.gpt_answerer.answer_question_numeric(question_text)
|
||||
question_type = 'numeric'
|
||||
else:
|
||||
answer = self.gpt_answerer.answer_question_textual_wide_range(question_text)
|
||||
question_type = 'textbox'
|
||||
self._enter_text(text_field, answer)
|
||||
self._save_questions_to_json({'type': question_type, 'question': question_text, 'answer': answer})
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -243,6 +275,7 @@ class LinkedInEasyApplier:
|
||||
date_field = date_fields[0]
|
||||
answer_date = self.gpt_answerer.answer_question_date()
|
||||
self._enter_text(date_field, answer_date.strftime("%Y-%m-%d"))
|
||||
self._save_questions_to_json({'type': 'date', 'question': section.text.lower(), 'answer': answer_date.strftime("%Y-%m-%d")})
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -256,6 +289,7 @@ class LinkedInEasyApplier:
|
||||
options = [option.text for option in select.options]
|
||||
answer = self.gpt_answerer.answer_question_from_options(question_text, options)
|
||||
self._select_dropdown_option(dropdown, answer)
|
||||
self._save_questions_to_json({'type': 'dropdown', 'question': question_text, 'answer': answer})
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
@ -281,3 +315,36 @@ class LinkedInEasyApplier:
|
||||
def _select_dropdown_option(self, element: WebElement, text: str) -> None:
|
||||
select = Select(element)
|
||||
select.select_by_visible_text(text)
|
||||
|
||||
def _save_questions_to_json(self, question_data: dict) -> None:
|
||||
output_file = 'answers.json'
|
||||
question_data['question'] = self._sanitize_text(question_data['question'])
|
||||
try:
|
||||
try:
|
||||
with open(output_file, 'r') as f:
|
||||
try:
|
||||
all_data = json.load(f)
|
||||
if not isinstance(all_data, list):
|
||||
raise ValueError("JSON file format is incorrect. Expected a list of questions.")
|
||||
except json.JSONDecodeError:
|
||||
all_data = []
|
||||
except FileNotFoundError:
|
||||
all_data = []
|
||||
all_data.append(question_data)
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(all_data, f, indent=4)
|
||||
except Exception:
|
||||
tb_str = traceback.format_exc()
|
||||
raise Exception(f"Error saving questions data to JSON file: \nTraceback:\n{tb_str}")
|
||||
|
||||
|
||||
|
||||
def _sanitize_text(self, text: str) -> str:
|
||||
sanitized_text = text.lower()
|
||||
sanitized_text = sanitized_text.strip()
|
||||
sanitized_text = sanitized_text.replace('"', '')
|
||||
sanitized_text = sanitized_text.replace('\\', '')
|
||||
sanitized_text = re.sub(r'[\x00-\x1F\x7F]', '', sanitized_text)
|
||||
sanitized_text = sanitized_text.replace('\n', ' ').replace('\r', '')
|
||||
sanitized_text = sanitized_text.rstrip(',')
|
||||
return sanitized_text
|
3
main.py
3
main.py
@ -37,8 +37,7 @@ class ConfigValidator:
|
||||
except FileNotFoundError:
|
||||
raise ConfigError(f"File not found: {yaml_path}")
|
||||
|
||||
|
||||
|
||||
|
||||
def validate_config(config_yaml_path: Path) -> dict:
|
||||
parameters = ConfigValidator.validate_yaml_file(config_yaml_path)
|
||||
required_keys = {
|
||||
|
20
strings.py
20
strings.py
@ -290,12 +290,12 @@ Read the following resume carefully and answer the specific questions regarding
|
||||
2. **Indirect Experience and Academic Background:**
|
||||
- **Relevant Projects:** Consider the types of projects the candidate has worked on and the time spent on each project. Advanced projects suggest deeper skills. For example, a project involving MQTT packet parsing suggests MQTT and possibly IoT skills.
|
||||
- **Roles and Responsibilities:** Evaluate the roles and responsibilities held. If a role suggests knowledge of specific technologies or skills, provide a number based on that experience.
|
||||
- **Type of University and Studies:** Also consider the type of university and the duration of studies. Prestigious universities and advanced coursework may indicate solid theoretical knowledge. However, give less weight to academic skills compared to practical experience and projects. For example, a degree from a high-level university should influence answers to technical questions minimally.
|
||||
- **Type of University and Studies:** Also consider the type of university and the duration of studies.
|
||||
|
||||
3. **Inference Over Default Response:** Always strive to infer experience based on the available information. If direct experience cannot be confirmed, use related skills, projects, and academic background to estimate a plausible number of years. Avoid defaulting to 0 if you can infer any relevant experience.
|
||||
|
||||
4. **Handling Experience Estimates:**
|
||||
- **For Low Experience (up to 5 years):** It is acceptable to provide inferred experience a lot. Use related skills and projects to estimate these numbers reasonably. Aim to keep the values as high as possible and avoid using "0" as a response unless absolutely necessary.
|
||||
- **For Low Experience (up to 5 years):** It is acceptable to provide inferred experience a lot. Aim to keep the values as high as possible and avoid using "0" as a response unless absolutely necessary.
|
||||
- **For High Experience:** For high levels of experience, ensure the number provided is as certain as possible and based on clear evidence from the resume. Avoid making inferences for high experience levels unless the evidence is strong.
|
||||
|
||||
|
||||
@ -306,7 +306,7 @@ Read the following resume carefully and answer the specific questions regarding
|
||||
```
|
||||
## Curriculum
|
||||
|
||||
I am a software engineer with 3 years of experience in Swift and Python. I have worked on projects including an i work 2 years with MQTT protocol.
|
||||
I had a degree in computer science. I have worked 2 years with MQTT protocol.
|
||||
|
||||
## Question
|
||||
|
||||
@ -314,6 +314,20 @@ How many years of experience do you have with IoT?
|
||||
|
||||
## Answer
|
||||
|
||||
2
|
||||
```
|
||||
## Example 1
|
||||
```
|
||||
## Curriculum
|
||||
|
||||
I had a degree in computer science.
|
||||
|
||||
## Question
|
||||
|
||||
How many years of experience do you have with Bash?
|
||||
|
||||
## Answer
|
||||
|
||||
2
|
||||
```
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user