4NK_IA_front/backend/collectors/inforgreffeCollector.js
4NK IA 8e3daad446 feat: intégration collecteurs Bodacc/Inforgreffe + génération PDF
- 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é
2025-09-18 16:03:57 +00:00

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
};