File size: 24,345 Bytes
cd58373
 
 
 
 
 
fd5aa4d
cd58373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8b2b995
 
 
 
 
cd58373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f87b33f
cd58373
 
 
 
 
f87b33f
4b4bc5b
f87b33f
 
cd58373
f87b33f
cd58373
 
 
 
 
 
 
 
 
 
 
 
 
 
f87b33f
 
 
 
 
 
cd58373
 
f87b33f
cd58373
 
 
 
 
 
f87b33f
cd58373
 
 
 
 
 
f87b33f
 
 
 
 
 
 
ab8e00a
 
cd58373
f87b33f
cd58373
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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)