diff --git a/gimme_job/adapters/googlejobs.py b/gimme_job/adapters/googlejobs.py index 0c4c564..d7a8aee 100644 --- a/gimme_job/adapters/googlejobs.py +++ b/gimme_job/adapters/googlejobs.py @@ -17,21 +17,28 @@ _EXTRACT_JS = """() => { const shareEl = card.closest('[data-share-url]'); const shareUrl = shareEl ? shareEl.getAttribute('data-share-url') : ''; - // Build a clean udm=8 deep-link that opens the job detail panel. - // The shareUrl has session-tied tokens (shmd, shmds, shem) that can expire; - // we strip them and use only the htidocid + the new SPA fragment format. - let jobUrl = ''; let htidocid = ''; if (shareUrl) { const docMatch = shareUrl.match(/htidocid=([^&]+)/); - const qMatch = shareUrl.match(/[?&]q=([^&#]+)/); - if (docMatch) { - htidocid = decodeURIComponent(docMatch[1]); - const q = qMatch ? qMatch[1] : 'orthodontist+job'; - jobUrl = 'https://www.google.com/search?q=' + q + '&udm=8' - + '#vhid=vt%3D20/docid%3D' + docMatch[1] - + '&vssid=jobs-detail-viewer'; - } + if (docMatch) htidocid = decodeURIComponent(docMatch[1]); + } + + // Use the first external apply URL (Indeed, Glassdoor, Monster, etc.) + // pre-loaded inside the card's share_el. These are direct links to the + // source posting and work regardless of session/location, unlike + // Google Jobs htidocid deep-links which require the job to be in the + // current search context. + let jobUrl = ''; + if (shareEl) { + const links = Array.from(shareEl.querySelectorAll('a[href^="https://"]')); + const apply = links.find(a => { + const href = a.getAttribute('href') || ''; + return !href.includes('://www.google.com') + && !href.includes('://google.com') + && !href.includes('gstatic.com') + && !href.includes('accounts.google.com'); + }); + if (apply) jobUrl = apply.getAttribute('href'); } const dateSpan = card.querySelector('span[aria-label^="Posted"]');