Auto-deploy: 2026-06-05 23:02:41
This commit is contained in:
@@ -44,81 +44,79 @@
|
||||
};
|
||||
|
||||
try {
|
||||
// 1. Name: The most reliable way is the profile link
|
||||
const profileLinks = Array.from(cardEl.querySelectorAll('a[href*="/in/"]'))
|
||||
.filter(a => a.innerText.trim().length > 2 && !a.innerText.includes('LinkedIn'));
|
||||
// 1. Get all text lines, filter out empty ones
|
||||
const rawLines = cardEl.innerText.split('\n').map(s => s.trim()).filter(s => s.length > 1);
|
||||
|
||||
if (profileLinks.length > 0) {
|
||||
// Remove any injected language tags
|
||||
let rawName = profileLinks[0].innerText.trim().split('\n')[0];
|
||||
data.name = rawName.replace(/English \(Australia\)|Auto|Translate/gi, '').trim();
|
||||
} else {
|
||||
const nameEl = cardEl.querySelector('.entity-result__title-text, .search-result__title, span[dir="ltr"], h3');
|
||||
if (nameEl) data.name = nameEl.innerText.trim().split('\n')[0].replace(/English \(Australia\)|Auto/gi, '').trim();
|
||||
// 2. Filter out known noise (translation extensions, action buttons, connection degrees, etc)
|
||||
const lines = rawLines.filter(s => {
|
||||
const low = s.toLowerCase();
|
||||
// Remove degree connections
|
||||
if (low.includes('degree connection')) return false;
|
||||
if (low.includes('• 1st') || low.includes('• 2nd') || low.includes('• 3rd')) return false;
|
||||
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) {
|
||||
console.error('[LJA] Extraction failed', e);
|
||||
data.name = 'مستثمر محتمل';
|
||||
}
|
||||
|
||||
if (!data.name || data.name.length < 2) data.name = 'مستثمر محتمل';
|
||||
if (!data.headline) data.headline = 'لا يوجد مسمى وظيفي';
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// ─── Find Cards Logic ──────────────────────────────────────────────────────
|
||||
function findCards() {
|
||||
let cards = [];
|
||||
let uniqueCards = new Set();
|
||||
|
||||
// Method 1: The official LinkedIn search result container class
|
||||
let containerElements = document.querySelectorAll('.reusable-search__result-container, .search-entity, .entity-result__item');
|
||||
if (containerElements.length > 0) {
|
||||
containerElements.forEach(el => uniqueCards.add(el));
|
||||
console.log('[LJA] Found cards via container classes:', uniqueCards.size);
|
||||
}
|
||||
// The most bulletproof way to find a profile card is to find the main Action Button (Connect/Message/Follow)
|
||||
// and then go up the DOM tree until we find the container that holds the whole profile
|
||||
let buttons = Array.from(document.querySelectorAll('button')).filter(btn => {
|
||||
let txt = btn.innerText.toLowerCase().trim();
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
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;
|
||||
});
|
||||
|
||||
const cards = Array.from(uniqueCards);
|
||||
console.log('[LJA] Found valid profile cards:', cards.length);
|
||||
return cards;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user