You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.9 KiB
Python
77 lines
2.9 KiB
Python
"""Arora Group Jobs adapter — Load More button, keyword post-filter."""
|
|
from __future__ import annotations
|
|
|
|
from loguru import logger
|
|
|
|
from gimme_job.adapters.base import ManifestDrivenAdapter
|
|
from gimme_job.adapters.registry import register
|
|
from gimme_job.models.dto import JobPostingCandidate, RawJobCard
|
|
|
|
_KEYWORDS = ["dentist", "orthodontic", "orthodontist"]
|
|
_MAX_LOAD_MORE = 3 # clicks in addition to the initial load
|
|
|
|
|
|
@register("aroragroup")
|
|
class AroraGroupAdapter(ManifestDrivenAdapter):
|
|
_BASE_URL = "https://jobs.aroragroup.com"
|
|
|
|
def collect_cards(self, page, manifest):
|
|
"""Trigger AJAX job load, click 'Load More' up to N times, then filter by keywords."""
|
|
# Trigger initial job list load via the page's JS function
|
|
try:
|
|
page.evaluate("doloadJBSearchList(1)")
|
|
except Exception:
|
|
pass
|
|
|
|
# Wait for at least one title to be populated
|
|
try:
|
|
page.wait_for_selector(".POST_TITLE:not(:empty)", timeout=15000, state="attached")
|
|
except Exception:
|
|
logger.debug("[aroragroup] Job titles did not populate — no results or load failed")
|
|
return []
|
|
|
|
for i in range(_MAX_LOAD_MORE):
|
|
btn = page.query_selector("button#loadMore")
|
|
if not btn or not btn.is_visible():
|
|
logger.debug(f"[aroragroup] Load More button gone after {i} extra loads")
|
|
break
|
|
|
|
current_count = len(page.query_selector_all(".POST_TITLE:not(:empty)"))
|
|
btn.click()
|
|
|
|
try:
|
|
page.wait_for_function(
|
|
f"document.querySelectorAll('.POST_TITLE:not(:empty)').length > {current_count}",
|
|
timeout=15000,
|
|
)
|
|
logger.debug(f"[aroragroup] Load More {i + 1}/{_MAX_LOAD_MORE}: loaded more cards")
|
|
except Exception:
|
|
logger.debug(f"[aroragroup] Load More {i + 1}: no new cards appeared — stopping")
|
|
break
|
|
|
|
all_cards = super().collect_cards(page, manifest)
|
|
|
|
# Filter by keywords in title
|
|
filtered = [c for c in all_cards if self._matches_keywords(c.title)]
|
|
logger.debug(
|
|
f"[aroragroup] Keyword filter: {len(filtered)}/{len(all_cards)} cards matched"
|
|
)
|
|
return filtered
|
|
|
|
def paginate(self, page, page_index: int, config) -> bool:
|
|
"""Pagination is handled inside collect_cards — always return False."""
|
|
return False
|
|
|
|
def normalize(self, raw: RawJobCard) -> JobPostingCandidate:
|
|
candidate = super().normalize(raw)
|
|
if candidate.job_url and candidate.job_url.startswith("/"):
|
|
candidate.job_url = self._BASE_URL + candidate.job_url
|
|
return candidate
|
|
|
|
@staticmethod
|
|
def _matches_keywords(title: str | None) -> bool:
|
|
if not title:
|
|
return False
|
|
title_lower = title.lower()
|
|
return any(kw in title_lower for kw in _KEYWORDS)
|