"""SRPMIC (Salt River Pima-Maricopa Indian Community) adapter — GovernmentJobs.com."""
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("srpmic")
class SRPMICAdapter(ManifestDrivenAdapter):
def collect_cards(self, page, manifest) -> list[RawJobCard]:
"""Extract job cards via JS from the current results page."""
raw_data = page.evaluate("""() => {
const links = document.querySelectorAll('a[href*="/careers/srpmic/jobs/"]');
return Array.from(links).map(a => {
const li = a.closest('li');
// Details list is the first
directly inside the job card -
const detailsUl = li?.querySelector(':scope > ul');
const details = detailsUl
? Array.from(detailsUl.querySelectorAll('li')).map(l => l.innerText.trim())
: [];
// Posted date is in a direct child element starting with "Posted"
const postedText = Array.from(li?.children || [])
.map(c => c.innerText?.trim())
.find(t => t && t.startsWith('Posted')) || null;
return {
title: a.innerText.trim(),
url: a.href,
location: details[0] || null,
salary: details[1] || null,
posted: postedText
};
}).filter(j => j.title && j.url.includes('/careers/srpmic/jobs/'));
}""")
cards = []
for item in raw_data:
cards.append(RawJobCard(
title=item["title"],
company="Salt River Pima-Maricopa Indian Community",
location=item["location"],
salary_text=item["salary"],
posted_text=item["posted"],
url=item["url"],
))
logger.info(f"[srpmic] Extracted {len(cards)} cards")
return cards
def paginate(self, page, page_index: int, config) -> bool:
"""Navigate to next page using URL ?page=N parameter."""
# Check if Next link is present and enabled
has_next = page.evaluate("""() => {
const links = Array.from(document.querySelectorAll('a'));
const next = links.find(a =>
a.textContent.trim() === 'Next' ||
(a.getAttribute('aria-label') || '').toLowerCase().includes('next page')
);
return !!(next && !next.hasAttribute('disabled') &&
next.getAttribute('aria-disabled') !== 'true');
}""")
if not has_next:
return False
next_page_num = page_index + 2 # page_index 0 → go to page 2
current_url = page.url
if re.search(r'[?&]page=\d+', current_url):
next_url = re.sub(r'(page=)\d+', f'page={next_page_num}', current_url)
elif '?' in current_url:
next_url = current_url + f'&page={next_page_num}'
else:
next_url = current_url + f'?page={next_page_num}'
logger.debug(f"[srpmic] Navigating to page {next_page_num}: {next_url}")
page.goto(next_url, timeout=30000)
try:
page.wait_for_selector(
"a[href*='/careers/srpmic/jobs/']", timeout=15000, state="attached"
)
except Exception:
logger.debug("[srpmic] No jobs found on next page — stopping")
return False
return True
def normalize(self, raw: RawJobCard) -> JobPostingCandidate:
return super().normalize(raw)