googlejobs: traverse <template> content to find apply URLs

Apply links (Indeed, Glassdoor, Monster, etc.) are pre-rendered inside
a <template> tag within each card's share_el. <template> content is
inert in the rendered DOM — a regular querySelectorAll from outside
returns nothing, which is why the previous fix produced empty URLs.

Iterate share_el's <template> elements and search their .content for
links matching utm_campaign=google_jobs_apply. Verified on the live
Google Jobs page that each card's template contains the correct
external apply URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
I Luk Kim 3 months ago
parent fa748bebf9
commit 37e5b59126

@ -23,22 +23,21 @@ _EXTRACT_JS = """() => {
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.
// Apply URLs (Indeed, Glassdoor, Monster, etc.) live INSIDE a <template>
// tag within share_el. <template> content is inert in the rendered DOM
// querySelectorAll('a[...]') from outside doesn't see them. We must
// traverse template.content explicitly. These are stable direct links
// to the source posting that work regardless of session/location.
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 templates = shareEl.querySelectorAll('template');
for (const t of templates) {
const link = t.content.querySelector('a[href*="utm_campaign=google_jobs_apply"]');
if (link) {
jobUrl = link.getAttribute('href');
break;
}
}
}
const dateSpan = card.querySelector('span[aria-label^="Posted"]');

Loading…
Cancel
Save