From 1f7004696117aef9af9717ab9bbe2d1f857bcef9 Mon Sep 17 00:00:00 2001 From: 1 Date: Sat, 31 Aug 2024 17:18:18 +0300 Subject: [PATCH 1/4] Readme upd to ease troubleshooting and fixing --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3258335..15fe7b8 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ LinkedIn_AIHawk steps in as a game-changing solution to these challenges. It's n ## Installation **Please watch this video to set up your LinkedIn_AIHawk: [How to set up LinkedIn_AIHawk](https://youtu.be/gdW9wogHEUM) - https://youtu.be/gdW9wogHEUM** - +0. **Confirmed succesfull runs OSs & Python**: Python 3.10, 3.11.9(64b), 3.12.5(64b) . Windows 10, Ubuntu 22 1. **Download and Install Python:** Ensure you have the last Python version installed. If not, download and install it from Python's official website. For detailed instructions, refer to the tutorials: @@ -507,11 +507,16 @@ TODO ): ## Troubleshooting +- **Carefully read logs and output :** Most of the errors are verbosely reflected just watch the output and try to find the root couse. +- **If nothing works by unknown reason:** Use tested OS. Reboot and/or update OS. Use new clean venv. Try update Python to the tested version. - **ChromeDriver Issues:** Ensure ChromeDriver is compatible with your installed Chrome version. - **Missing Files:** Verify that all necessary files are present in the data folder. -- **Invalid YAML:** Check your YAML files for syntax errors. - - If you encounter any issues, you can open an issue on [GitHub](https://github.com/feder-cr/linkedIn_auto_jobs_applier_with_AI/issues). I'll be more than happy to assist you! +- **Invalid YAML:** Check your YAML files for syntax errors . Try to use external YAML validators e.g. https://www.yamllint.com/ +- **OpenAI endpoint isues**: Try to check possible limits\blocking at their side + +If you encounter any issues, you can open an issue on [GitHub](https://github.com/feder-cr/linkedIn_auto_jobs_applier_with_AI/issues). + Please add valuable details to the subject and to the description. If you need new feature then please reflect this. + I'll be more than happy to assist you! ## Conclusion From 9fc3274b9afe23dad1294612db8226b236e8bf26 Mon Sep 17 00:00:00 2001 From: Manu Altieri Date: Sat, 31 Aug 2024 19:31:31 +0200 Subject: [PATCH 2/4] Adding linkedin-api.py to search jobs without use selenium. --- src/linkedin-api.py | 168 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/linkedin-api.py diff --git a/src/linkedin-api.py b/src/linkedin-api.py new file mode 100644 index 0000000..f1395f8 --- /dev/null +++ b/src/linkedin-api.py @@ -0,0 +1,168 @@ +from typing import Dict, List +from linkedin_api import Linkedin +from typing import Optional, Union, Literal +from urllib.parse import urlencode + +class LinkedInEvolvedAPI(Linkedin): + def __init__(self, username, password): + super().__init__(username, password) + + def search_jobs( + self, + keywords: Optional[str] = None, + companies: Optional[List[str]] = None, + experience: Optional[ + List[ + Union[ + Literal["1"], + Literal["2"], + Literal["3"], + Literal["4"], + Literal["5"], + Literal["6"], + ] + ] + ] = None, + job_type: Optional[ + List[ + Union[ + Literal["F"], + Literal["C"], + Literal["P"], + Literal["T"], + Literal["I"], + Literal["V"], + Literal["O"], + ] + ] + ] = None, + job_title: Optional[List[str]] = None, + industries: Optional[List[str]] = None, + location_name: Optional[str] = None, + remote: Optional[List[Union[Literal["1"], Literal["2"], Literal["3"]]]] = None, + listed_at=24 * 60 * 60, + distance: Optional[int] = None, + easy_apply: Optional[bool] = True, + limit=-1, + offset=0, + **kwargs, + ) -> List[Dict]: + """Perform a LinkedIn search for jobs. + + :param keywords: Search keywords (str) + :type keywords: str, optional + :param companies: A list of company URN IDs (str) + :type companies: list, optional + :param experience: A list of experience levels, one or many of "1", "2", "3", "4", "5" and "6" (internship, entry level, associate, mid-senior level, director and executive, respectively) + :type experience: list, optional + :param job_type: A list of job types , one or many of "F", "C", "P", "T", "I", "V", "O" (full-time, contract, part-time, temporary, internship, volunteer and "other", respectively) + :type job_type: list, optional + :param job_title: A list of title URN IDs (str) + :type job_title: list, optional + :param industries: A list of industry URN IDs (str) + :type industries: list, optional + :param location_name: Name of the location to search within. Example: "Kyiv City, Ukraine" + :type location_name: str, optional + :param remote: Filter for remote jobs, onsite or hybrid. onsite:"1", remote:"2", hybrid:"3" + :type remote: list, optional + :param listed_at: maximum number of seconds passed since job posting. 86400 will filter job postings posted in last 24 hours. + :type listed_at: int/str, optional. Default value is equal to 24 hours. + :param distance: maximum distance from location in miles + :type distance: int/str, optional. If not specified, None or 0, the default value of 25 miles applied. + :param easy_apply: filter for jobs that are easy to apply to + :type easy_apply: bool, optional. Default value is True. + :param limit: maximum number of results obtained from API queries. -1 means maximum which is defined by constants and is equal to 1000 now. + :type limit: int, optional, default -1 + :param offset: indicates how many search results shall be skipped + :type offset: int, optional + :return: List of jobs + :rtype: list + """ + count = Linkedin._MAX_SEARCH_COUNT + if limit is None: + limit = -1 + + query: Dict[str, Union[str, Dict[str, str]]] = { + "origin": "JOB_SEARCH_PAGE_QUERY_EXPANSION" + } + if keywords: + query["keywords"] = "KEYWORD_PLACEHOLDER" + if location_name: + query["locationFallback"] = "LOCATION_PLACEHOLDER" + + query["selectedFilters"] = {} + if companies: + query["selectedFilters"]["company"] = f"List({','.join(companies)})" + if experience: + query["selectedFilters"]["experience"] = f"List({','.join(experience)})" + if job_type: + query["selectedFilters"]["jobType"] = f"List({','.join(job_type)})" + if job_title: + query["selectedFilters"]["title"] = f"List({','.join(job_title)})" + if industries: + query["selectedFilters"]["industry"] = f"List({','.join(industries)})" + if distance: + query["selectedFilters"]["distance"] = f"List({distance})" + if remote: + query["selectedFilters"]["workplaceType"] = f"List({','.join(remote)})" + if easy_apply: + query["selectedFilters"]["easyApply"] = "List(true)" + + query["selectedFilters"]["timePostedRange"] = f"List(r{listed_at})" + query["spellCorrectionEnabled"] = "true" + + query_string = ( + str(query) + .replace(" ", "") + .replace("'", "") + .replace("KEYWORD_PLACEHOLDER", keywords or "") + .replace("LOCATION_PLACEHOLDER", location_name or "") + .replace("{", "(") + .replace("}", ")") + ) + results = [] + while True: + if limit > -1 and limit - len(results) < count: + count = limit - len(results) + default_params = { + "decorationId": "com.linkedin.voyager.dash.deco.jobs.search.JobSearchCardsCollection-174", + "count": count, + "q": "jobSearch", + "query": query_string, + "start": len(results) + offset, + } + + res = self._fetch( + f"/voyagerJobsDashJobCards?{urlencode(default_params, safe='(),:')}", + headers={"accept": "application/vnd.linkedin.normalized+json+2.1"}, + ) + data = res.json() + + elements = data.get("included", []) + new_data = [] + for e in elements: + trackingUrn = e.get("trackingUrn") + if trackingUrn: + trackingUrn = trackingUrn.split(":")[-1] + e["job_id"] = trackingUrn + if e.get("$type") == "com.linkedin.voyager.dash.jobs.JobPosting": + new_data.append(e) + + if not new_data: + break + results.extend(new_data) + if ( + (-1 < limit <= len(results)) + or len(results) / count >= Linkedin._MAX_REPEATED_REQUESTS + ) or len(elements) == 0: + break + + self.logger.debug(f"results grew to {len(results)}") + + return results + + + + + + \ No newline at end of file From bac05ad04cbae9bfe9429aa8b2b0e403cc18b08d Mon Sep 17 00:00:00 2001 From: Manu Altieri Date: Sat, 31 Aug 2024 19:39:44 +0200 Subject: [PATCH 3/4] Adding linkedin-api.py to search jobs without use selenium (requirements) --- requirements.txt | Bin 674 -> 698 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index aef4baed9ae147969488a70f26fd5aae9edacb36..341ed8e0d589527317d1b1884894f4ad7e2a7733 100644 GIT binary patch delta 32 jcmZ3)x{GzgA|{C(hD?S$hHQpZh7>SMmm!g%0LTIWkiG|q delta 7 OcmdnRx`=hdA|?O}&jPyu From 9ed0c3ea6385d16177703fb3fe9ed45d9fb5cc5d Mon Sep 17 00:00:00 2001 From: Earl Perry Date: Sun, 1 Sep 2024 09:01:52 -0400 Subject: [PATCH 4/4] Instead of adding a documentation section, improved trouble shooting guide, with current issues, solutions, and addtional resources --- README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 15fe7b8..adb4eb1 100644 --- a/README.md +++ b/README.md @@ -501,19 +501,84 @@ Using this folder as a guide can be particularly helpful for: python main.py --resume /path/to/your/resume.pdf ``` -## Documentation -TODO ): +### Troubleshooting Common Issues -## Troubleshooting +#### 1. OpenAI API Rate Limit Errors + +**Error Message:** + +openai.RateLimitError: Error code: 429 - {'error': {'message': 'You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors.', 'type': 'insufficient_quota', 'param': None, 'code': 'insufficient_quota'}} + +**Solution:** +- Check your OpenAI API billing settings at https://platform.openai.com/account/billing +- Ensure you have added a valid payment method to your OpenAI account +- Note that ChatGPT Plus subscription is different from API access +- If you've recently added funds or upgraded, wait 12-24 hours for changes to take effect +- Free tier has a 3 RPM limit; spend at least $5 on API usage to increase + +#### 2. LinkedIn Easy Apply Button Not Found + +**Error Message:** + +Exception: No clickable 'Easy Apply' button found + +**Solution:** +- Ensure that you're logged into LinkedIn properly +- Check if the job listings you're targeting actually have the "Easy Apply" option +- Verify that your search parameters in the `config.yaml` file are correct and returning jobs with the "Easy Apply" button +- Try increasing the wait time for page loading in the script to ensure all elements are loaded before searching for the button + +#### 3. Incorrect Information in Job Applications + +**Issue:** Bot provides inaccurate data for experience, CTC, and notice period + +**Solution:** +- Update prompts for professional experience specificity +- Add fields in `config.yaml` for current CTC, expected CTC, and notice period +- Modify bot logic to use these new config fields + +#### 4. YAML Configuration Errors + +**Error Message:** + +yaml.scanner.ScannerError: while scanning a simple key + +**Solution:** +- Copy example `config.yaml` and modify gradually +- Ensure proper YAML indentation and spacing +- Use a YAML validator tool +- Avoid unnecessary special characters or quotes + +#### 5. Bot Logs In But Doesn't Apply to Jobs + +**Issue:** Bot searches for jobs but continues scrolling without applying + +**Solution:** +- Check for security checks or CAPTCHAs +- Verify `config.yaml` job search parameters +- Ensure your LinkedIn profile meets job requirements +- Review console output for error messages + +### General Troubleshooting Tips + +- Use the latest version of the script +- Verify all dependencies are installed and updated +- Check internet connection stability +- Use VPNs cautiously to avoid triggering LinkedIn security +- Clear browser cache and cookies if issues persist + +For further assistance, please create an issue on the [GitHub repository](https://github.com/feder-cr/LinkedIn_AIHawk_automatic_job_application/issues) with detailed information about your problem, including error messages and your configuration (with sensitive information removed). + +### Additional Resources + +- [Video Tutorial: How to set up LinkedIn_AIHawk](https://youtu.be/gdW9wogHEUM) +- [OpenAI API Documentation](https://platform.openai.com/docs/) +- [LinkedIn Developer Documentation](https://developer.linkedin.com/) +- [Lang Chain Developer Documentation](https://python.langchain.com/v0.2/docs/integrations/components/) + +Remember to always use LinkedIn_AIHawk responsibly and in compliance with LinkedIn's terms of service. -- **Carefully read logs and output :** Most of the errors are verbosely reflected just watch the output and try to find the root couse. -- **If nothing works by unknown reason:** Use tested OS. Reboot and/or update OS. Use new clean venv. Try update Python to the tested version. -- **ChromeDriver Issues:** Ensure ChromeDriver is compatible with your installed Chrome version. -- **Missing Files:** Verify that all necessary files are present in the data folder. -- **Invalid YAML:** Check your YAML files for syntax errors . Try to use external YAML validators e.g. https://www.yamllint.com/ -- **OpenAI endpoint isues**: Try to check possible limits\blocking at their side - If you encounter any issues, you can open an issue on [GitHub](https://github.com/feder-cr/linkedIn_auto_jobs_applier_with_AI/issues). Please add valuable details to the subject and to the description. If you need new feature then please reflect this. I'll be more than happy to assist you!