Spaces:
Running
Running
import requests | |
import json | |
from datetime import datetime | |
import warnings | |
from bs4 import BeautifulSoup | |
from markdownify import markdownify | |
from ai_manager import get_offer_information | |
warnings.filterwarnings("ignore") | |
def get_offer(url): | |
response = requests.get(url, verify=False) | |
if response.status_code == 200: | |
# Extract the text from the response | |
soup = BeautifulSoup(response.text, 'html.parser') | |
match = soup.find('div', {'id': 'the-position-section'}) | |
text = match.text.rstrip().lstrip() | |
return markdownify(text) | |
else: | |
return "" | |
def get_extra_information_from_ai(company, url): | |
offer = get_offer(url) | |
return get_offer_information(company, offer) | |
def get_salary(job): | |
if job["ai_result"]["salary_range"].lower() not in ["", "unknown"]: | |
return job["ai_result"]["salary_range"] | |
return "" | |
def format_should_apply(should_apply): | |
if should_apply: | |
return "⭐ " | |
return "" | |
def get_logo(job): | |
if "{}".format(job["logo_photo_url"]) == "nan": | |
return "https://e7.pngegg.com/pngimages/153/807/png-clipart-timer-clock-computer-icons-unknown-planet-digital-clock-time.png" | |
return job["logo_photo_url"] | |
def format_str_or_list(sum): | |
if isinstance(sum, str): | |
return sum.replace("\n", "<br />") | |
if isinstance(sum, list): | |
return "<ul>" + "".join(f"<li>{item}</li>" for item in sum) + "</ul>" | |
return sum | |
def html_format_job(job): | |
#open box | |
result = ["<div class='job'>"] | |
#logo | |
result.append("<div class='logobox'><img src='{}' alt='Logo' class='logo'></div>".format(job["organization_logo_url"])) | |
#text part | |
result.append("<div style='flex: 5; padding: 10px;'>") | |
result.append("<h3><a href='{}' target='_blank'>{}{}</a></h3>".format(job["URL"], format_should_apply(job["ai_result"]["should_apply"]), job["name"])) | |
result.append("<p>{} ({}) - published at {}</p>".format(job["organization_name"], job["ai_result"]["company_description"], job["published_at"])) | |
result.append("<p><h4>Position: {}</h4>{}</p>".format(get_salary(job), format_str_or_list(job["ai_result"]["position_summary"]))) | |
result.append("<p><h4>Language:</h4>{}</p>".format(format_str_or_list(job["ai_result"]["language_requirements"]))) | |
result.append("<p><h4>Experience:</h4>{}</p>".format(format_str_or_list(job["ai_result"]["experience_requirements"]))) | |
#close text part | |
result.append("</div>") | |
#close box | |
result.append("</div>") | |
return " ".join(result) | |
def filterout_jobs(jobs, job_filter, job_filter_negative): | |
selected_jobs = [] | |
for job in jobs: | |
if not any(item in job["name"].lower() for item in job_filter_negative) and any(item in job["name"].lower() for item in job_filter): | |
job["ai_result"] = get_extra_information_from_ai(job["organization_name"], job["URL"]) | |
if job["ai_result"]["is_an_internship"] == False: | |
selected_jobs.append(job) | |
return selected_jobs | |
def html_format_page(jobs, job_filter, job_filter_negative): | |
selected_jobs = filterout_jobs(jobs, job_filter, job_filter_negative) | |
result = ["<html><head><style>.job{display: flex;width:70%;margin: 5px auto;border: 1px solid;border-radius: 5px;}.logobox{flex: 1;display: flex;align-items: center;justify-content: center;}.logo{width:100px;height:100px}h4{margin: 2px;}</style></head><body>"] | |
if len(selected_jobs) > 0: | |
for job in selected_jobs: | |
result.append(html_format_job(job)) | |
else: | |
result.append("No job found") | |
result.append("</body></html>") | |
return " ".join(result) | |
def get_jobs(search_term): | |
headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0", | |
"Accept": "*/*", | |
"Accept-Language": "en-US,en;q=0.5", | |
"Accept-Encoding": "gzip, deflate, br", | |
"Origin": "https://www.welcometothejungle.com", | |
"Connection": "keep-alive", | |
"Sec-Fetch-Dest": "empty", | |
"Sec-Fetch-Mode": "no-cors", | |
"Sec-Fetch-Site": "cross-site", | |
"content-type": "application/x-www-form-urlencoded", | |
"Referer": "https://www.welcometothejungle.com/", | |
"Pragma": "no-cache", | |
"Cache-Control": "no-cache", | |
"x-algolia-agent": "Algolia for JavaScript (4.14.3); Browser (lite); JS Helper (3.11.2); react (17.0.2); react-instantsearch (6.38.3)", | |
"x-algolia-api-key": "4bd8f6215d0cc52b26430765769e65a0", | |
"x-algolia-application-id": "CSEKHVMS53" | |
} | |
data = """{ | |
"requests":[{ | |
"indexName":"wttj_jobs_production_en", | |
"params":"attributesToHighlight=%5B%22name%22%5D&attributesToRetrieve=%5B%22*%22%5D&clickAnalytics=true&hitsPerPage=50&maxValuesPerFacet=999&analytics=true&enableABTest=true&userToken=d9c8afab-18d1-41dc-b3ab-da2f75bf30e6&analyticsTags=%5B%22page%3Ajobs_index%22%2C%22language%3Aen%22%5D&facets=%5B%22benefits%22%2C%22organization.commitments%22%2C%22contract_type%22%2C%22contract_duration_minimum%22%2C%22contract_duration_maximum%22%2C%22has_contract_duration%22%2C%22education_level%22%2C%22has_education_level%22%2C%22experience_level_minimum%22%2C%22has_experience_level_minimum%22%2C%22organization.nb_employees%22%2C%22organization.labels%22%2C%22salary_yearly_minimum%22%2C%22has_salary_yearly_minimum%22%2C%22salary_currency%22%2C%22followedCompanies%22%2C%22language%22%2C%22new_profession.category_reference%22%2C%22new_profession.sub_category_reference%22%2C%22remote%22%2C%22sectors.parent_reference%22%2C%22sectors.reference%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&page=0&query=#####&aroundLatLng=48.85717%2C2.3414&aroundRadius=20000&aroundPrecision=20000"},{"indexName":"wttj_jobs_production_en_promoted","params":"attributesToHighlight=%5B%22name%22%5D&attributesToRetrieve=%5B%22*%22%5D&clickAnalytics=true&hitsPerPage=200&maxValuesPerFacet=999&analytics=true&enableABTest=true&userToken=d9c8afab-18d1-41dc-b3ab-da2f75bf30e6&analyticsTags=%5B%22page%3Ajobs_index%22%2C%22language%3Aen%22%5D&facets=%5B%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)%20AND%20is_boosted%3Atrue%20AND%20NOT%20reference%3A7e884b19-1ce2-4386-bc6a-643890daf461%20AND%20NOT%20reference%3A1b0237ca-1971-4651-a062-6db5f4c9a6e1%20AND%20NOT%20reference%3Ac27ab821-6822-4156-b4ff-19a9a2940d9d&page=0&query=#####&aroundLatLng=48.85717%2C2.3414&aroundRadius=20000&aroundPrecision=20000"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22benefits%22%2C%22organization.commitments%22%2C%22contract_type%22%2C%22contract_duration_minimum%22%2C%22contract_duration_maximum%22%2C%22has_contract_duration%22%2C%22education_level%22%2C%22has_education_level%22%2C%22experience_level_minimum%22%2C%22has_experience_level_minimum%22%2C%22organization.nb_employees%22%2C%22organization.labels%22%2C%22salary_yearly_minimum%22%2C%22has_salary_yearly_minimum%22%2C%22salary_currency%22%2C%22followedCompanies%22%2C%22language%22%2C%22new_profession.category_reference%22%2C%22new_profession.sub_category_reference%22%2C%22remote%22%2C%22sectors.parent_reference%22%2C%22sectors.reference%22%5D&filters=&hitsPerPage=0"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22benefits%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.commitments%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_type%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_minimum%22%5D&filters=contract_duration_minimum%3A1%20TO%203%20OR%20contract_duration_maximum%3A1%20TO%203%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_minimum%22%5D&filters=contract_duration_minimum%3A4%20TO%206%20OR%20contract_duration_maximum%3A4%20TO%206%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_minimum%22%5D&filters=contract_duration_minimum%3A7%20TO%2012%20OR%20contract_duration_maximum%3A7%20TO%2012%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_minimum%22%5D&filters=contract_duration_minimum%3A13%20TO%2024%20OR%20contract_duration_maximum%3A13%20TO%2024%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_minimum%22%5D&filters=contract_duration_minimum%3A25%20TO%2036%20OR%20contract_duration_maximum%3A25%20TO%2036%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22contract_duration_maximum%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22has_contract_duration%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22education_level%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22has_education_level%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22experience_level_minimum%22%5D&filters=experience_level_minimum%3A0%20TO%201%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22experience_level_minimum%22%5D&filters=experience_level_minimum%3A1%20TO%203%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22experience_level_minimum%22%5D&filters=experience_level_minimum%3A3%20TO%205%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22experience_level_minimum%22%5D&filters=experience_level_minimum%3A5%20TO%2010%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22experience_level_minimum%22%5D&filters=experience_level_minimum%20%3E%3D%2010%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22has_experience_level_minimum%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.nb_employees%22%5D&filters=organization.nb_employees%3A0%20TO%2015%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.nb_employees%22%5D&filters=organization.nb_employees%3A15%20TO%2050%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.nb_employees%22%5D&filters=organization.nb_employees%3A50%20TO%20250%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.nb_employees%22%5D&filters=organization.nb_employees%3A250%20TO%202000%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.nb_employees%22%5D&filters=organization.nb_employees%20%3E%3D%202000%20AND%20(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22organization.labels%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22salary_yearly_minimum%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22has_salary_yearly_minimum%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22salary_currency%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22followedCompanies%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22language%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22new_profession.category_reference%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22new_profession.sub_category_reference%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22remote%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22sectors.parent_reference%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"},{"indexName":"wttj_jobs_production_en","params":"analytics=false&facets=%5B%22sectors.reference%22%5D&filters=(%22offices.country_code%22%3A%22FR%22)%20AND%20(%22contract_type%22%3A%22full_time%22%20OR%20%22contract_type%22%3A%22temporary%22)%20AND%20(experience_level_minimum%3A0%20TO%201%20OR%20experience_level_minimum%3A1%20TO%203%20OR%20has_experience_level_minimum%3D0)&hitsPerPage=0&query=#####"} | |
]} | |
""".replace("#####", search_term.lower().replace(" ", "%20").replace('"', "%22")) | |
url = "https://csekhvms53-2.algolianet.com/1/indexes/*/queries?x-algolia-agent=Algolia^%^20for^%^20JavaScript^%^20(4.20.0)^%^3B^%^20Browser^%^20(lite)^%^3B^%^20JS^%^20Helper^%^20(3.11.2)^%^3B^%^20react^%^20(17.0.2)^%^3B^%^20react-instantsearch^%^20(6.38.3)&x-algolia-api-key=4bd8f6215d0cc52b26430765769e65a0&x-algolia-application-id=CSEKHVMS53&search_origin=jobs_search_client" | |
response = requests.post(url, headers=headers, data=data, verify=False) | |
#parse result | |
jsonResponse = json.loads(response.text) | |
results = jsonResponse["results"] | |
hits = results[0]["hits"] | |
jobs = [] | |
for hit in hits: | |
#get the info | |
job = {} | |
job["name"] = hit["name"] | |
job["slug"] = hit["slug"] | |
if hit["published_at"] != None: | |
try: | |
# Try parsing with fractional seconds | |
published_at = datetime.strptime(hit["published_at"], '%Y-%m-%dT%H:%M:%S.%f%z') | |
except ValueError: | |
# If it fails, try parsing without fractional seconds | |
published_at = datetime.strptime(hit["published_at"], '%Y-%m-%dT%H:%M:%S%z') | |
job["published_at"] = published_at.strftime("%d/%m/%Y %H:%M:%S") | |
else: | |
job["published_at"] = "Unknown" | |
job["organization_name"] = hit["organization"]["name"] | |
if hit["organization"].get("size", None) is not None: | |
job["organization_size"] = hit["organization"]["size"]["en"] | |
else: | |
job["organization_size"] = "" | |
job["organization_logo_url"] = hit["organization"]["logo"]["url"] | |
job["organization_slug"] = hit["organization"]["slug"] | |
job["objectID"] = hit["objectID"] | |
job["URL"] = "https://www.welcometothejungle.com/en/companies/{}/jobs/{}?o={}".format(job["organization_slug"], job["slug"], job["objectID"]) | |
jobs.append(job) | |
return jobs | |
def parse_datetime(dt_str): | |
if dt_str == "Unknown": | |
return datetime.min # Return the minimum possible datetime | |
else: | |
return datetime.strptime(dt_str, "%d/%m/%Y %H:%M:%S") | |
def wtoj_get_html(search_term): | |
unique_objects = get_jobs(search_term) | |
jobs = sorted(unique_objects, key=lambda x: parse_datetime(x["published_at"]), reverse=True) | |
#filter on the job description | |
job_filter = ["marketing", "communication", "community", "business development", "experience", "social media", "brand", "ppc", "seo", "sea", "ads", "user acquisition", "adops", "consultant"] | |
job_filter_negative = ["stage", "stagiaire", "alternant", "alternance", "intern", "internship", "apprenti"] | |
return html_format_page(jobs, job_filter, job_filter_negative) | |