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.

66 lines
2.4 KiB
Python

"""Hospital Jobs Online adapter — URL-based pagination with page= parameter."""
from __future__ import annotations
import re
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
@register("hospitaljobsonline")
class HospitalJobsOnlineAdapter(ManifestDrivenAdapter):
_BASE_URL = "https://www.hospitaljobsonline.com"
def _wait_for_results(self, page) -> None:
try:
page.wait_for_selector("div.jobresult", timeout=15000, state="attached")
except Exception:
logger.debug("[hospitaljobsonline] Results wait timed out — may be zero results")
def collect_cards(self, page, manifest):
self._wait_for_results(page)
return super().collect_cards(page, manifest)
def paginate(self, page, page_index: int, config) -> bool:
"""Navigate to next page by incrementing the ?page= URL parameter."""
if page_index >= config.pagination.max_pages - 1:
return False
current_url = page.url
next_page = page_index + 2
if re.search(r"[?&]page=\d+", current_url):
next_url = re.sub(r"(page=)\d+", f"page={next_page}", current_url)
else:
sep = "&" if "?" in current_url else "?"
next_url = f"{current_url}{sep}page={next_page}"
logger.debug(f"[hospitaljobsonline] Paginating to page {next_page}: {next_url}")
page.goto(next_url, timeout=30000)
self._wait_for_results(page)
return True
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
# Parse location text: "1 week ago - Company Name - Location: City, ST"
if candidate.location:
loc = candidate.location
# Extract part after "Location:" if present
m = re.search(r"Location:\s*(.+)$", loc, re.IGNORECASE)
if m:
candidate.location = m.group(1).strip()
else:
# Fallback: take last segment after " - "
parts = [p.strip() for p in loc.split(" - ")]
if len(parts) >= 2:
candidate.location = parts[-1]
return candidate