- Collecteur Bodacc: scraping léger pour gel des avoirs (personnes) - Collecteur Inforgreffe/Societe.com: données entreprises (SIREN, dirigeants, etc.) - Générateur PDF: rapports formatés HTML pour chaque type dentité
431 lines
13 KiB
JavaScript
431 lines
13 KiB
JavaScript
/**
|
|
* Collecteur Inforgreffe/Societe.com - Informations entreprises
|
|
* Scraping léger avec politesse pour récupérer les données d'entreprises
|
|
*/
|
|
|
|
const fetch = require('node-fetch');
|
|
const { JSDOM } = require('jsdom');
|
|
|
|
const SOCIETE_COM_BASE_URL = 'https://www.societe.com';
|
|
const INFORGREFFE_BASE_URL = 'https://www.inforgreffe.com';
|
|
const USER_AGENT = '4NK-IA-Front/1.0 (Document Analysis Tool)';
|
|
const REQUEST_DELAY_MS = 1500; // 1.5 secondes entre les requêtes
|
|
const REQUEST_TIMEOUT_MS = 12000; // 12 secondes timeout
|
|
|
|
/**
|
|
* Recherche une entreprise sur Societe.com et Inforgreffe
|
|
* @param {string} companyName - Nom de l'entreprise
|
|
* @param {string} siren - SIREN (optionnel)
|
|
* @returns {Promise<Object>} Résultat de la recherche
|
|
*/
|
|
async function searchCompanyInfo(companyName, siren = '') {
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
console.log(`[Inforgreffe] Recherche entreprise: ${companyName} ${siren ? `(SIREN: ${siren})` : ''}`);
|
|
|
|
// Recherche sur Societe.com d'abord (plus accessible)
|
|
const societeComResult = await searchSocieteCom(companyName, siren);
|
|
|
|
// Délai de politesse
|
|
await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
|
|
|
|
// Recherche sur Inforgreffe si SIREN disponible
|
|
let inforgreffeResult = null;
|
|
if (siren) {
|
|
inforgreffeResult = await searchInforgreffe(siren);
|
|
await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
|
|
}
|
|
|
|
// Fusion des résultats
|
|
const mergedResult = mergeCompanyResults(societeComResult, inforgreffeResult, companyName);
|
|
|
|
const duration = Date.now() - startTime;
|
|
console.log(`[Inforgreffe] Recherche terminée en ${duration}ms`);
|
|
|
|
return {
|
|
success: true,
|
|
duration,
|
|
company: mergedResult,
|
|
sources: {
|
|
societeCom: societeComResult,
|
|
inforgreffe: inforgreffeResult
|
|
},
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
console.error(`[Inforgreffe] Erreur recherche:`, error.message);
|
|
|
|
return {
|
|
success: false,
|
|
duration,
|
|
error: error.message,
|
|
company: null,
|
|
sources: {},
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Recherche sur Societe.com
|
|
* @param {string} companyName - Nom de l'entreprise
|
|
* @param {string} siren - SIREN (optionnel)
|
|
* @returns {Promise<Object>} Résultat Societe.com
|
|
*/
|
|
async function searchSocieteCom(companyName, siren = '') {
|
|
try {
|
|
// Construction de l'URL de recherche
|
|
const searchQuery = siren || companyName;
|
|
const searchUrl = `${SOCIETE_COM_BASE_URL}/search?q=${encodeURIComponent(searchQuery)}`;
|
|
|
|
const response = await fetch(searchUrl, {
|
|
method: 'GET',
|
|
headers: {
|
|
'User-Agent': USER_AGENT,
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
'Accept-Language': 'fr-FR,fr;q=0.9,en;q=0.8',
|
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
'Connection': 'keep-alive',
|
|
'Upgrade-Insecure-Requests': '1'
|
|
},
|
|
timeout: REQUEST_TIMEOUT_MS
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const html = await response.text();
|
|
const dom = new JSDOM(html);
|
|
const document = dom.window.document;
|
|
|
|
return extractSocieteComData(document, companyName, siren);
|
|
|
|
} catch (error) {
|
|
console.warn(`[Societe.com] Erreur:`, error.message);
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
data: null
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Recherche sur Inforgreffe
|
|
* @param {string} siren - SIREN de l'entreprise
|
|
* @returns {Promise<Object>} Résultat Inforgreffe
|
|
*/
|
|
async function searchInforgreffe(siren) {
|
|
try {
|
|
// URL de recherche par SIREN
|
|
const searchUrl = `${INFORGREFFE_BASE_URL}/entreprise/${siren}`;
|
|
|
|
const response = await fetch(searchUrl, {
|
|
method: 'GET',
|
|
headers: {
|
|
'User-Agent': USER_AGENT,
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
'Accept-Language': 'fr-FR,fr;q=0.9,en;q=0.8',
|
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
'Connection': 'keep-alive',
|
|
'Upgrade-Insecure-Requests': '1'
|
|
},
|
|
timeout: REQUEST_TIMEOUT_MS
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const html = await response.text();
|
|
const dom = new JSDOM(html);
|
|
const document = dom.window.document;
|
|
|
|
return extractInforgreffeData(document, siren);
|
|
|
|
} catch (error) {
|
|
console.warn(`[Inforgreffe] Erreur:`, error.message);
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
data: null
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extrait les données de Societe.com
|
|
* @param {Document} document - Document DOM parsé
|
|
* @param {string} companyName - Nom de l'entreprise
|
|
* @param {string} siren - SIREN
|
|
* @returns {Object} Données extraites
|
|
*/
|
|
function extractSocieteComData(document, companyName, siren) {
|
|
try {
|
|
const data = {
|
|
name: companyName,
|
|
siren: siren,
|
|
siret: '',
|
|
forme: '',
|
|
capital: '',
|
|
adresse: '',
|
|
dirigeants: [],
|
|
activite: '',
|
|
dateCreation: '',
|
|
sourceUrl: SOCIETE_COM_BASE_URL
|
|
};
|
|
|
|
// Extraction du nom de l'entreprise
|
|
const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title');
|
|
if (nameElement) {
|
|
data.name = nameElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction du SIREN/SIRET
|
|
const sirenElement = document.querySelector('.siren, .num-siren, [data-siren]');
|
|
if (sirenElement) {
|
|
const sirenText = sirenElement.textContent || sirenElement.getAttribute('data-siren');
|
|
data.siren = extractSiren(sirenText);
|
|
}
|
|
|
|
// Extraction de la forme juridique
|
|
const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form');
|
|
if (formeElement) {
|
|
data.forme = formeElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction du capital
|
|
const capitalElement = document.querySelector('.capital, .capital-social, .share-capital');
|
|
if (capitalElement) {
|
|
data.capital = capitalElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction de l'adresse
|
|
const adresseElement = document.querySelector('.adresse, .address, .company-address');
|
|
if (adresseElement) {
|
|
data.adresse = adresseElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction des dirigeants
|
|
const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant');
|
|
dirigeantsElements.forEach(element => {
|
|
const name = element.textContent.trim();
|
|
if (name && name.length > 2) {
|
|
data.dirigeants.push({
|
|
nom: name,
|
|
fonction: 'Dirigeant',
|
|
source: 'societe.com'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Extraction de l'activité
|
|
const activiteElement = document.querySelector('.activite, .activity, .secteur');
|
|
if (activiteElement) {
|
|
data.activite = activiteElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction de la date de création
|
|
const dateElement = document.querySelector('.date-creation, .creation-date, .date-creation-entreprise');
|
|
if (dateElement) {
|
|
data.dateCreation = dateElement.textContent.trim();
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data
|
|
};
|
|
|
|
} catch (error) {
|
|
console.warn(`[Societe.com] Erreur extraction:`, error.message);
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
data: null
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extrait les données d'Inforgreffe
|
|
* @param {Document} document - Document DOM parsé
|
|
* @param {string} siren - SIREN
|
|
* @returns {Object} Données extraites
|
|
*/
|
|
function extractInforgreffeData(document, siren) {
|
|
try {
|
|
const data = {
|
|
siren: siren,
|
|
name: '',
|
|
siret: '',
|
|
forme: '',
|
|
capital: '',
|
|
adresse: '',
|
|
dirigeants: [],
|
|
activite: '',
|
|
dateCreation: '',
|
|
sourceUrl: `${INFORGREFFE_BASE_URL}/entreprise/${siren}`
|
|
};
|
|
|
|
// Extraction du nom de l'entreprise
|
|
const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title');
|
|
if (nameElement) {
|
|
data.name = nameElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction du SIRET
|
|
const siretElement = document.querySelector('.siret, .num-siret, [data-siret]');
|
|
if (siretElement) {
|
|
data.siret = siretElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction de la forme juridique
|
|
const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form');
|
|
if (formeElement) {
|
|
data.forme = formeElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction du capital
|
|
const capitalElement = document.querySelector('.capital, .capital-social, .share-capital');
|
|
if (capitalElement) {
|
|
data.capital = capitalElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction de l'adresse
|
|
const adresseElement = document.querySelector('.adresse, .address, .company-address');
|
|
if (adresseElement) {
|
|
data.adresse = adresseElement.textContent.trim();
|
|
}
|
|
|
|
// Extraction des dirigeants
|
|
const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant');
|
|
dirigeantsElements.forEach(element => {
|
|
const name = element.textContent.trim();
|
|
if (name && name.length > 2) {
|
|
data.dirigeants.push({
|
|
nom: name,
|
|
fonction: 'Dirigeant',
|
|
source: 'inforgreffe.com'
|
|
});
|
|
}
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data
|
|
};
|
|
|
|
} catch (error) {
|
|
console.warn(`[Inforgreffe] Erreur extraction:`, error.message);
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
data: null
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fusionne les résultats de Societe.com et Inforgreffe
|
|
* @param {Object} societeComResult - Résultat Societe.com
|
|
* @param {Object} inforgreffeResult - Résultat Inforgreffe
|
|
* @param {string} originalName - Nom original de l'entreprise
|
|
* @returns {Object} Données fusionnées
|
|
*/
|
|
function mergeCompanyResults(societeComResult, inforgreffeResult, originalName) {
|
|
const merged = {
|
|
name: originalName,
|
|
siren: '',
|
|
siret: '',
|
|
forme: '',
|
|
capital: '',
|
|
adresse: '',
|
|
dirigeants: [],
|
|
activite: '',
|
|
dateCreation: '',
|
|
sources: []
|
|
};
|
|
|
|
// Fusion des données Societe.com
|
|
if (societeComResult.success && societeComResult.data) {
|
|
const sc = societeComResult.data;
|
|
merged.name = sc.name || merged.name;
|
|
merged.siren = sc.siren || merged.siren;
|
|
merged.siret = sc.siret || merged.siret;
|
|
merged.forme = sc.forme || merged.forme;
|
|
merged.capital = sc.capital || merged.capital;
|
|
merged.adresse = sc.adresse || merged.adresse;
|
|
merged.activite = sc.activite || merged.activite;
|
|
merged.dateCreation = sc.dateCreation || merged.dateCreation;
|
|
merged.dirigeants.push(...sc.dirigeants);
|
|
merged.sources.push('societe.com');
|
|
}
|
|
|
|
// Fusion des données Inforgreffe
|
|
if (inforgreffeResult && inforgreffeResult.success && inforgreffeResult.data) {
|
|
const ig = inforgreffeResult.data;
|
|
merged.name = ig.name || merged.name;
|
|
merged.siren = ig.siren || merged.siren;
|
|
merged.siret = ig.siret || merged.siret;
|
|
merged.forme = ig.forme || merged.forme;
|
|
merged.capital = ig.capital || merged.capital;
|
|
merged.adresse = ig.adresse || merged.adresse;
|
|
merged.dateCreation = ig.dateCreation || merged.dateCreation;
|
|
merged.dirigeants.push(...ig.dirigeants);
|
|
merged.sources.push('inforgreffe.com');
|
|
}
|
|
|
|
// Déduplication des dirigeants
|
|
merged.dirigeants = merged.dirigeants.filter((dirigeant, index, self) =>
|
|
index === self.findIndex(d => d.nom === dirigeant.nom)
|
|
);
|
|
|
|
return merged;
|
|
}
|
|
|
|
/**
|
|
* Extrait le SIREN d'un texte
|
|
* @param {string} text - Texte contenant potentiellement un SIREN
|
|
* @returns {string} SIREN extrait
|
|
*/
|
|
function extractSiren(text) {
|
|
if (!text) return '';
|
|
|
|
// Recherche d'un SIREN (9 chiffres)
|
|
const sirenMatch = text.match(/\b(\d{9})\b/);
|
|
return sirenMatch ? sirenMatch[1] : '';
|
|
}
|
|
|
|
/**
|
|
* Génère un résumé des données d'entreprise pour le PDF
|
|
* @param {Object} companyData - Données de l'entreprise
|
|
* @returns {Object} Résumé formaté
|
|
*/
|
|
function generateCompanySummary(companyData) {
|
|
return {
|
|
name: companyData.name,
|
|
siren: companyData.siren,
|
|
siret: companyData.siret,
|
|
forme: companyData.forme,
|
|
capital: companyData.capital,
|
|
adresse: companyData.adresse,
|
|
dirigeantsCount: companyData.dirigeants.length,
|
|
activite: companyData.activite,
|
|
dateCreation: companyData.dateCreation,
|
|
sources: companyData.sources,
|
|
hasCompleteInfo: !!(companyData.siren && companyData.forme && companyData.adresse),
|
|
summary: companyData.siren ?
|
|
`Entreprise trouvée: ${companyData.name} (SIREN: ${companyData.siren})` :
|
|
`Informations partielles pour: ${companyData.name}`
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
searchCompanyInfo,
|
|
generateCompanySummary
|
|
};
|