V1.23.28 Mise à jour de la BDD des entreprises et stratégies

This commit is contained in:
2026-09-15 21:45:02 +00:00
parent e2de83ad41
commit 2825430bf4
9 changed files with 871 additions and 7 deletions
+98 -5
View File
@@ -115,6 +115,26 @@ NAF_CODES = [
'98.20Z', '99.00Z',
]
# Plage de divisions (2 premiers chiffres du code NAF) par section -- permet de
# limiter le repli par code NAF precis (3e niveau) aux seuls codes de la section
# en cours, au lieu de retester les 732 codes en entier a chaque section plafonnee
# (bug corrige le 13/09/2026 : provoquait un blocage de plusieurs heures sur les
# grandes villes, ex. Toulouse, ou plusieurs sections restent plafonnees).
SECTION_DIVISIONS = {
"A": range(1, 4), "B": range(5, 10), "C": range(10, 34), "D": range(35, 36),
"E": range(36, 40), "F": range(41, 44), "G": range(45, 48), "H": range(49, 54),
"I": range(55, 57), "J": range(58, 64), "K": range(64, 67), "L": range(68, 69),
"M": range(69, 76), "N": range(77, 83), "O": range(84, 85), "P": range(85, 86),
"Q": range(86, 89), "R": range(90, 94), "S": range(94, 97), "T": range(97, 99),
"U": range(99, 100),
}
def codes_for_section(section):
divisions = SECTION_DIVISIONS[section]
return [c for c in NAF_CODES if int(c[:2]) in divisions]
CAP = 10000
PAGE_SIZE = 25
RATE_DELAY = 0.15 # ~6-7 req/s, sous le quota documente de l'API
@@ -128,6 +148,7 @@ CREATE TABLE IF NOT EXISTS `Entreprises{dep}Phase1` (
`ENT_AdresseSiege` varchar(255) DEFAULT NULL,
`ENT_CodePostal` varchar(20) DEFAULT NULL,
`ENT_Commune` varchar(100) DEFAULT NULL,
`ENT_CodeCommune` char(5) DEFAULT NULL,
`ENT_Departement` char(3) DEFAULT NULL,
`ENT_Region` char(2) DEFAULT NULL,
`ENT_DateCreation` date DEFAULT NULL,
@@ -154,8 +175,10 @@ CREATE TABLE IF NOT EXISTS `Entreprises{dep}Phase1` (
`ENT_DateImport` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ENT_DateMajInsee` datetime DEFAULT NULL,
`ENT_ReponseBruteJson` json DEFAULT NULL,
PRIMARY KEY (`ENT_Siren`)
PRIMARY KEY (`ENT_Siren`),
KEY `idx_commune` (`ENT_CodeCommune`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8
"""
DDL_PHASE2 = """
@@ -183,7 +206,7 @@ CREATE TABLE IF NOT EXISTS `Entreprises{dep}Phase3` (
DDL_COMMUNES = """
CREATE TABLE IF NOT EXISTS `ENT_Communes` (
`COM_CodeInsee` char(5) NOT NULL,
`COM_CodePostal` varchar(20) DEFAULT NULL,
`COM_CodePostal` varchar(100) DEFAULT NULL,
`COM_Ville` varchar(100) NOT NULL,
`COM_Departement` char(3) NOT NULL,
`COM_Latitude` decimal(10,6) DEFAULT NULL,
@@ -193,6 +216,25 @@ CREATE TABLE IF NOT EXISTS `ENT_Communes` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"""
DDL_DEPARTEMENTS = """
CREATE TABLE IF NOT EXISTS `ENT_Departements` (
`DEP_Code` char(3) NOT NULL,
`DEP_Nom` varchar(100) NOT NULL,
`DEP_NbEntreprises` int NOT NULL DEFAULT 0,
`DEP_DateExtractionInitiale` datetime DEFAULT NULL,
`DEP_DateDerniereSyncFormalites` datetime DEFAULT NULL,
PRIMARY KEY (`DEP_Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"""
DDL_CONFIG = """
CREATE TABLE IF NOT EXISTS `ENT_Config` (
`CFG_Cle` varchar(100) NOT NULL,
`CFG_Valeur` varchar(255) DEFAULT NULL,
PRIMARY KEY (`CFG_Cle`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
"""
def log(msg):
print(msg, file=sys.stderr, flush=True)
@@ -209,11 +251,51 @@ def http_get_json(url, retries=5):
time.sleep(1 + attempt)
# Paris, Lyon et Marseille (PLM) : dans les donnees Sirene, le siege d'une
# entreprise de ces trois villes est quasi toujours code au niveau de
# l'arrondissement (75101-75120, 69381-69389, 13201-13216), jamais au code
# commune englobant (75056, 69123, 13055) -- verifie empiriquement le 14
# septembre 2026 sur Marseille : code_commune=13055 ne renvoie qu'une dizaine
# de resultats, alors que chaque arrondissement (13201 a 13216) est a lui
# seul plafonne ou proche du plafond de 10 000. Le code englobant est donc
# remplace par la liste de ses arrondissements avant extraction.
COMMUNES_ARRONDISSEMENTS = {"75": "75056", "69": "69123", "13": "13055"}
def fetch_arrondissements_geo(dep):
url = "https://geo.api.gouv.fr/communes?" + urllib.parse.urlencode(
{"codeDepartement": dep, "type": "arrondissement-municipal",
"fields": "code,nom,centre,codesPostaux,departement"}
)
return http_get_json(url)
def fetch_communes_geo(dep):
url = API_GEO.format(dep=dep) + "?" + urllib.parse.urlencode(
{"fields": "code,nom,centre,codesPostaux,departement"}
)
return http_get_json(url)
communes = http_get_json(url)
code_englobant = COMMUNES_ARRONDISSEMENTS.get(dep)
if code_englobant:
communes = [c for c in communes if c["code"] != code_englobant]
communes.extend(fetch_arrondissements_geo(dep))
return communes
def fetch_departement_nom(dep):
url = f"https://geo.api.gouv.fr/departements/{dep}?fields=code,nom"
data = http_get_json(url)
return data.get("nom", dep)
def upsert_departement(conn, dep, nom, nb_entreprises):
with conn.cursor() as cur:
cur.execute(
"INSERT INTO ENT_Departements (DEP_Code, DEP_Nom, DEP_NbEntreprises, DEP_DateExtractionInitiale) "
"VALUES (%s, %s, %s, NOW()) "
"ON DUPLICATE KEY UPDATE DEP_Nom=VALUES(DEP_Nom), DEP_NbEntreprises=VALUES(DEP_NbEntreprises)",
(dep, nom, nb_entreprises),
)
NON_DIFFUSIBLE = "[NON-DIFFUSIBLE]"
@@ -254,6 +336,7 @@ def map_entreprise(r):
"ENT_AdresseSiege": clean(siege.get("adresse")),
"ENT_CodePostal": clean(siege.get("code_postal")),
"ENT_Commune": clean(siege.get("libelle_commune")),
"ENT_CodeCommune": clean(siege.get("commune")),
"ENT_Departement": clean(siege.get("departement")),
"ENT_Region": clean(siege.get("region")),
"ENT_DateCreation": clean(r.get("date_creation")),
@@ -329,7 +412,7 @@ def fetch_commune_entreprises(code_commune, seen):
# au filtre de section.
log(f" commune {code_commune} section {section} encore plafonnee ({sec_total}), "
f"repli par code NAF precis")
for code in NAF_CODES:
for code in codes_for_section(section):
code_params = dict(base, activite_principale=code)
code_total = probe_total(code_params)
if code_total == 0:
@@ -383,6 +466,8 @@ def ensure_tables(conn, dep):
cur.execute(DDL_PHASE2.format(dep=dep))
cur.execute(DDL_PHASE3.format(dep=dep))
cur.execute(DDL_COMMUNES)
cur.execute(DDL_DEPARTEMENTS)
cur.execute(DDL_CONFIG)
def ensure_communes(conn, dep, communes_geo):
@@ -431,8 +516,16 @@ def run_department(conn, dep):
total_finances += 1
if results:
log(f" {c['nom']} ({c['code']}) : {len(results)} entreprises")
with conn.cursor() as cur:
cur.execute(f"SELECT COUNT(*) FROM `{table1}`")
(nb_total,) = cur.fetchone()
nom_dep = fetch_departement_nom(dep)
upsert_departement(conn, dep, nom_dep, nb_total)
log(f"Departement {dep} termine : {total_upserts} entreprises upsertees dans {table1}, "
f"{total_finances} lignes financieres upsertees dans {table3}")
f"{total_finances} lignes financieres upsertees dans {table3} (total {nb_total} -- "
f"ENT_Departements mise a jour)")
def main():