fix: return the result columns when a search finds no jobs (#418) · speedyapply/JobSpy@093e221 · GitHub
Skip to content

Commit 093e221

Browse files
authored
fix: return the result columns when a search finds no jobs (#418)
1 parent 015c31b commit 093e221

15 files changed

Lines changed: 218 additions & 224 deletions

File tree

‎jobspy/__init__.py‎

Lines changed: 24 additions & 49 deletions

‎jobspy/bayt/__init__.py‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
TLSRotating,
3030
check_status,
3131
create_session,
32-
format_description,
32+
description_fields,
3333
utc_date,
3434
)
3535

@@ -180,7 +180,7 @@ def _fetch_hybrid_ids(self) -> set[str] | None:
180180
def _timestamp(job: Tag) -> int | None:
181181
posted = job.select_one("[data-automation-jobactivedate]")
182182
stamp = posted.get("data-automation-jobactivedate", "") if posted else ""
183-
return int(stamp) if isinstance(stamp, str) and stamp.isdigit() else None
183+
return int(stamp) if isinstance(stamp, str) and stamp.isdecimal() else None
184184

185185
def _process_job(self, job: Tag) -> JobPost | None:
186186
link = job.select_one("h2 a[href]")
@@ -225,7 +225,7 @@ def _process_job(self, job: Tag) -> JobPost | None:
225225
job_post = JobPost(
226226
id=f"bayt-{job_id}",
227227
title=link.get_text(strip=True),
228-
company_name=(company.get_text(strip=True) or None) if company else None,
228+
company=(company.get_text(strip=True) or None) if company else None,
229229
company_url=(
230230
urljoin(self.base_url, str(company_link["href"]))
231231
if company_link
@@ -251,9 +251,9 @@ def _process_job(self, job: Tag) -> JobPost | None:
251251
),
252252
None,
253253
),
254-
compensation=(
255-
self._parse_salary(salary.get_text(" ", strip=True)) if salary else None
256-
),
254+
**self._parse_salary(
255+
salary.get_text(" ", strip=True) if salary else ""
256+
).model_dump(),
257257
)
258258
if self.scraper_input.fetch_description:
259259
details = self._fetch_details(job_id, job_url)
@@ -262,14 +262,14 @@ def _process_job(self, job: Tag) -> JobPost | None:
262262
return job_post
263263

264264
@staticmethod
265-
def _parse_salary(text: str) -> Compensation | None:
265+
def _parse_salary(text: str) -> Compensation:
266266
""" "AED 29,380 - AED 33,053" / "$3,000 - $4,000"; monthly, as job pages say"""
267267
match = re.fullmatch(
268268
r"([A-Z]{3}|\$) ?([\d,]+(?:\.\d+)?) - (?:[A-Z]{3}|\$)? ?([\d,]+(?:\.\d+)?)",
269269
text,
270270
)
271271
if not match:
272-
return None
272+
return Compensation()
273273
currency, low, high = match.groups()
274274
return Compensation(
275275
interval=CompensationInterval.MONTHLY,
@@ -304,15 +304,14 @@ def row(name: str) -> list[str]:
304304
tag = soup.select_one(f'[data-automation-id="id_{name}"]')
305305
return [part.strip() for part in tag.get_text().split("·")] if tag else []
306306

307-
description, emails = format_description(
307+
fields = description_fields(
308308
posting.get("description"), self.scraper_input.description_format
309309
)
310310
job_type = job_type_labels.get(next(iter(row("type_level_experience")), ""))
311311
company = row("company_employees_industry")
312312
openings = re.match(r"\d+", "".join(row("number_of_vacancies")))
313313
return {
314-
"description": description,
315-
"emails": emails,
314+
**fields,
316315
"job_type": [job_type] if job_type else None,
317316
"is_remote": row("remote_working") == ["Remote"],
318317
"vacancy_count": int(openings[0]) if openings else None,

‎jobspy/bdjobs/__init__.py‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
RequestsRotating,
3030
check_status,
3131
create_session,
32-
format_description,
32+
description_fields,
3333
too_old,
3434
)
3535

@@ -133,13 +133,13 @@ def _process_job(self, raw: dict[str, object]) -> JobPost | None:
133133
return JobPost(
134134
id=f"bd-{job_id}",
135135
title=job.jobTitle,
136-
company_name=job.companyName,
136+
company=job.companyName,
137137
location=Location(city=city or None, country="Bangladesh"),
138138
job_url=f"{self.base_url}/h/details/{job_id}",
139139
date_posted=posted.date(),
140140
job_type=self._parse_job_type(job.JobType),
141141
is_remote=is_remote,
142-
compensation=self._parse_salary(job.Salary),
142+
**self._parse_salary(job.Salary).model_dump(),
143143
company_logo=job.logoUrl or None,
144144
vacancy_count=job.Vacancies,
145145
experience_range=job.experience if job.experience != "NA" else None,
@@ -151,10 +151,10 @@ def _parse_job_type(text: str) -> list[JobType] | None:
151151
return [job_type_labels[t] for t in labels if t in job_type_labels] or None
152152

153153
@staticmethod
154-
def _parse_salary(text: str) -> Compensation | None:
154+
def _parse_salary(text: str) -> Compensation:
155155
match = re.fullmatch(r"Tk\. (\d+)(?: - (\d+))? \(Monthly\)", text)
156156
if not match:
157-
return None
157+
return Compensation()
158158
low, high = match.groups()
159159
return Compensation(
160160
interval=CompensationInterval.MONTHLY,
@@ -175,7 +175,7 @@ def _fetch_details(self, job_id: str) -> dict[str, object]:
175175
self.log.warning(f"job {job_id}: {result.message}")
176176
return {}
177177
details = result.data[0]
178-
description, emails = format_description(
178+
fields = description_fields(
179179
"".join(
180180
f"<h4>{heading}</h4>{getattr(details, field)}"
181181
for heading, field in description_sections
@@ -199,8 +199,7 @@ def _fetch_details(self, job_id: str) -> dict[str, object]:
199199
if host == "bdjobs.com" or host.endswith(".bdjobs.com"):
200200
apply_url = None
201201
return {
202-
"description": description,
203-
"emails": emails,
202+
**fields,
204203
"skills": skills.split(", ") if skills else None,
205204
"job_url_direct": apply_url,
206205
"company_url": company_url,

‎jobspy/glassdoor/__init__.py‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
TLSRotating,
3636
check_status,
3737
create_session,
38-
format_description,
38+
description_fields,
3939
get_enum_from_job_type,
4040
)
4141

@@ -200,7 +200,7 @@ def _process_job(self, raw: dict[str, object]) -> JobPost | None:
200200
return JobPost(
201201
id=f"gd-{job_id}",
202202
title=job.jobTitleText,
203-
company_name=header.employerNameFromSearch,
203+
company=header.employerNameFromSearch,
204204
company_url=(
205205
f"{self.base_url}/Overview/W-EI_IE{company_id}.htm"
206206
if company_id
@@ -213,7 +213,7 @@ def _process_job(self, raw: dict[str, object]) -> JobPost | None:
213213
job_type=job_types or None,
214214
is_remote="WORK_FROM_HOME" in (header.remoteWorkTypes or [])
215215
or header.locationName == "Remote",
216-
compensation=self._parse_salary(header),
216+
**self._parse_salary(header).model_dump(),
217217
listing_type=header.adOrderSponsorshipLevel.lower(),
218218
company_rating=header.rating or None,
219219
company_industry=company.industryName,
@@ -225,10 +225,10 @@ def _process_job(self, raw: dict[str, object]) -> JobPost | None:
225225
)
226226

227227
@staticmethod
228-
def _parse_salary(header: Header) -> Compensation | None:
228+
def _parse_salary(header: Header) -> Compensation:
229229
pay = header.payPeriodAdjustedPay
230230
if not pay:
231-
return None
231+
return Compensation()
232232
return Compensation(
233233
interval=pay_intervals.get(header.payPeriod or ""),
234234
min_amount=round(pay.p10, 2),
@@ -264,14 +264,10 @@ def _fetch_details(self, job_ids: list[str]) -> dict[str, dict[str, object]]:
264264
check_status(response)
265265
for alias, view in response.json()[0]["data"].items():
266266
if view:
267-
description, emails = format_description(
267+
details[f"gd-{alias[1:]}"] = description_fields(
268268
view["job"]["description"],
269269
self.scraper_input.description_format,
270270
)
271-
details[f"gd-{alias[1:]}"] = {
272-
"description": description,
273-
"emails": emails,
274-
}
275271
except Exception as e:
276272
self.log.warning(f"job details: {e}")
277273
return details

‎jobspy/google/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def _parse_job(self, job_info: list[Any]) -> JobPost | None:
199199
job_post = JobPost(
200200
id=f"go-{job_info[28]}",
201201
title=title,
202-
company_name=company_name,
202+
company=company_name,
203203
location=Location(
204204
city=city, state=state, country=country[0] if country else None
205205
),

‎jobspy/hellowork/__init__.py‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
TLSRotating,
3434
check_status,
3535
create_session,
36-
format_description,
36+
description_fields,
3737
utc_date,
3838
)
3939

@@ -166,7 +166,7 @@ def _process_job(self, card: Tag) -> JobPost | None:
166166
for tag in contract.parent.find_all("div")
167167
if (compensation := self._parse_salary(tag.get_text(strip=True)))
168168
),
169-
None,
169+
Compensation(),
170170
)
171171
logo = card.select_one('img[src*="/img/entreprises/"]')
172172
location = card.select_one("div[data-cy=localisationCard]")
@@ -176,15 +176,15 @@ def _process_job(self, card: Tag) -> JobPost | None:
176176
job_post = JobPost(
177177
id=f"hw-{job_id}",
178178
title=title,
179-
company_name="".join(company) or None,
179+
company="".join(company) or None,
180180
location=self._parse_location(location.get_text(strip=True)),
181181
job_url=f"{self.base_url}{link['href']}",
182182
date_posted=(
183183
utc_date(time.time() - hours * 3600) if hours is not None else None
184184
),
185-
job_type=job_types,
185+
job_type=job_types or None,
186186
is_remote="Télétravail complet" in label,
187-
compensation=salary,
187+
**salary.model_dump(),
188188
company_logo=str(logo["src"]) if logo else None,
189189
)
190190
if self.scraper_input.fetch_description:
@@ -252,10 +252,7 @@ def _fetch_details(self, job_id: str, job_url: str) -> dict[str, object]:
252252
for button in section.find_all("button"):
253253
button.decompose()
254254
html = str(section) if section else None
255-
description, emails = format_description(
256-
html, self.scraper_input.description_format
257-
)
258-
details: dict[str, object] = {"description": description, "emails": emails}
255+
details = description_fields(html, self.scraper_input.description_format)
259256
if posting.datePosted:
260257
posted = datetime.fromisoformat(posting.datePosted.rstrip("Z"))
261258
posted = posted.replace(tzinfo=ZoneInfo(paris_time))

‎jobspy/indeed/__init__.py‎

Lines changed: 5 additions & 9 deletions

0 commit comments

Comments
 (0)