Auto-deploy: 2026-06-05 23:02:41
This commit is contained in:
@@ -44,81 +44,79 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Name: The most reliable way is the profile link
|
// 1. Get all text lines, filter out empty ones
|
||||||
const profileLinks = Array.from(cardEl.querySelectorAll('a[href*="/in/"]'))
|
const rawLines = cardEl.innerText.split('\n').map(s => s.trim()).filter(s => s.length > 1);
|
||||||
.filter(a => a.innerText.trim().length > 2 && !a.innerText.includes('LinkedIn'));
|
|
||||||
|
|
||||||
if (profileLinks.length > 0) {
|
// 2. Filter out known noise (translation extensions, action buttons, connection degrees, etc)
|
||||||
// Remove any injected language tags
|
const lines = rawLines.filter(s => {
|
||||||
let rawName = profileLinks[0].innerText.trim().split('\n')[0];
|
const low = s.toLowerCase();
|
||||||
data.name = rawName.replace(/English \(Australia\)|Auto|Translate/gi, '').trim();
|
// Remove degree connections
|
||||||
} else {
|
if (low.includes('degree connection')) return false;
|
||||||
const nameEl = cardEl.querySelector('.entity-result__title-text, .search-result__title, span[dir="ltr"], h3');
|
if (low.includes('• 1st') || low.includes('• 2nd') || low.includes('• 3rd')) return false;
|
||||||
if (nameEl) data.name = nameEl.innerText.trim().split('\n')[0].replace(/English \(Australia\)|Auto/gi, '').trim();
|
if (['1st', '2nd', '3rd', '3rd+'].includes(low)) return false;
|
||||||
|
// Remove translation artifacts
|
||||||
|
if (low.includes('english (australia)') || low === 'auto' || low === 'translate') return false;
|
||||||
|
// Remove action buttons (exact match to avoid removing headlines like "Connect with me")
|
||||||
|
if (low === 'connect' || low === 'message' || low === 'pending' || low === 'follow' || low === 'view profile') return false;
|
||||||
|
// Remove mutual connections line
|
||||||
|
if (low.includes('mutual connection')) return false;
|
||||||
|
// Remove injected button text from this extension
|
||||||
|
if (low.includes('scan investor')) return false;
|
||||||
|
if (low.includes('تجاهله') || low.includes('تواصل معه') || low.includes('error')) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Assign the cleaned lines
|
||||||
|
// Remove duplicates if the name appears twice (e.g., "Hamza" then "Hamza • 2nd" filtered to "Hamza")
|
||||||
|
let uniqueLines = [];
|
||||||
|
lines.forEach(l => { if (!uniqueLines.includes(l)) uniqueLines.push(l); });
|
||||||
|
|
||||||
|
if (uniqueLines.length > 0) data.name = uniqueLines[0];
|
||||||
|
if (uniqueLines.length > 1) data.headline = uniqueLines[1];
|
||||||
|
if (uniqueLines.length > 2) data.location = uniqueLines[2];
|
||||||
|
|
||||||
|
// Everything else is summary
|
||||||
|
if (uniqueLines.length > 3) {
|
||||||
|
data.summary = uniqueLines.slice(3, 8).join(' | ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Headline
|
|
||||||
const headlineEl = cardEl.querySelector('.entity-result__primary-subtitle, [class*="subtitle"], .linked-area');
|
|
||||||
if (headlineEl) data.headline = headlineEl.innerText.trim();
|
|
||||||
|
|
||||||
// 3. Location
|
|
||||||
const locationEl = cardEl.querySelector('.entity-result__secondary-subtitle, .search-result__info');
|
|
||||||
if (locationEl) data.location = locationEl.innerText.trim();
|
|
||||||
|
|
||||||
// 4. Summary
|
|
||||||
const summaryEl = cardEl.querySelector('.entity-result__summary, .search-result__snippets');
|
|
||||||
if (summaryEl) data.summary = summaryEl.innerText.trim();
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
if (data.name) data.name = data.name.replace(/View .* profile/gi, '').trim();
|
|
||||||
|
|
||||||
if (!data.name) {
|
|
||||||
data.name = 'مستثمر محتمل';
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[LJA] Extraction failed', e);
|
console.error('[LJA] Extraction failed', e);
|
||||||
data.name = 'مستثمر محتمل';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data.name || data.name.length < 2) data.name = 'مستثمر محتمل';
|
||||||
|
if (!data.headline) data.headline = 'لا يوجد مسمى وظيفي';
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Find Cards Logic ──────────────────────────────────────────────────────
|
// ─── Find Cards Logic ──────────────────────────────────────────────────────
|
||||||
function findCards() {
|
function findCards() {
|
||||||
let cards = [];
|
|
||||||
let uniqueCards = new Set();
|
let uniqueCards = new Set();
|
||||||
|
|
||||||
// Method 1: The official LinkedIn search result container class
|
// The most bulletproof way to find a profile card is to find the main Action Button (Connect/Message/Follow)
|
||||||
let containerElements = document.querySelectorAll('.reusable-search__result-container, .search-entity, .entity-result__item');
|
// and then go up the DOM tree until we find the container that holds the whole profile
|
||||||
if (containerElements.length > 0) {
|
let buttons = Array.from(document.querySelectorAll('button')).filter(btn => {
|
||||||
containerElements.forEach(el => uniqueCards.add(el));
|
let txt = btn.innerText.toLowerCase().trim();
|
||||||
console.log('[LJA] Found cards via container classes:', uniqueCards.size);
|
return txt === 'connect' || txt === 'message' || txt === 'pending' || txt === 'follow';
|
||||||
}
|
|
||||||
|
|
||||||
// Method 2: Fallback to finding profile links and going up to the list item
|
|
||||||
if (uniqueCards.size === 0) {
|
|
||||||
let profileLinks = Array.from(document.querySelectorAll('a[href*="/in/"]'))
|
|
||||||
.filter(a => a.innerText.trim().length > 2 && !a.querySelector('img'));
|
|
||||||
|
|
||||||
profileLinks.forEach(link => {
|
|
||||||
// Find the nearest list item or large div container
|
|
||||||
let container = link.closest('li') || link.closest('div.mb1') || link.parentElement.parentElement.parentElement;
|
|
||||||
if (container && container.innerText.length > 20) {
|
|
||||||
uniqueCards.add(container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('[LJA] Found cards via profile links:', uniqueCards.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Set to Array and filter out translation extension dropdowns
|
|
||||||
cards = Array.from(uniqueCards).filter(card => {
|
|
||||||
const txt = card.innerText.toLowerCase();
|
|
||||||
// Must not be a language selector dropdown
|
|
||||||
if (txt.includes('english (australia)') && txt.length < 50) return false;
|
|
||||||
// Should have some decent amount of text
|
|
||||||
return txt.length > 20;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
buttons.forEach(btn => {
|
||||||
|
let container = btn.parentElement;
|
||||||
|
// Go up the DOM tree (max 10 levels) to find the list item
|
||||||
|
for(let i=0; i<10; i++) {
|
||||||
|
if (!container) break;
|
||||||
|
// A valid card container is usually an LI and contains an image
|
||||||
|
if (container.tagName === 'LI' && container.querySelector('img')) {
|
||||||
|
uniqueCards.add(container);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
container = container.parentElement;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cards = Array.from(uniqueCards);
|
||||||
|
console.log('[LJA] Found valid profile cards:', cards.length);
|
||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user