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.
38 lines
1.5 KiB
Python
38 lines
1.5 KiB
Python
"""LinkedIn Jobs adapter — scroll to load all cards on first page only."""
|
|
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
|
|
|
|
|
|
@register("linkedin")
|
|
class LinkedInAdapter(ManifestDrivenAdapter):
|
|
|
|
def collect_cards(self, page, manifest) -> list[RawJobCard]:
|
|
"""Scroll each card into view to trigger lazy-loading, then extract."""
|
|
self._scroll_to_load(page)
|
|
return super().collect_cards(page, manifest)
|
|
|
|
def normalize(self, raw: RawJobCard) -> JobPostingCandidate:
|
|
return super().normalize(raw)
|
|
|
|
@staticmethod
|
|
def _scroll_to_load(page) -> None:
|
|
"""Scroll each card into view one by one so LinkedIn renders all occluded items."""
|
|
try:
|
|
count = page.evaluate(
|
|
"document.querySelectorAll('li[data-occludable-job-id]').length"
|
|
)
|
|
for i in range(count):
|
|
page.evaluate(f"""() => {{
|
|
const cards = document.querySelectorAll('li[data-occludable-job-id]');
|
|
if (cards[{i}]) cards[{i}].scrollIntoView({{behavior: 'instant', block: 'center'}});
|
|
}}""")
|
|
page.wait_for_timeout(120)
|
|
logger.debug(f"[linkedin] Scrolled through {count} cards")
|
|
except Exception as e:
|
|
logger.debug(f"[linkedin] scroll_to_load failed: {e}")
|