[ka6] nouveau connecteur Votresite.ca (plateforme e-commerce québécoise) — 45 boutiques débloquées, +3 190 produits: le pool de 1 045 boutiques du registre sans plateforme cachait 61 sites Votresite.ca (vitrine Drupal 8 gérée, thème owebo-votresite, boutique OpenCart montée en sous-répertoire /boutique|/produits|/shop). VotresiteConnector: montage détecté (registre → page d'accueil → chemins usuels), inventaire par <mount>/sitemap.xml (extension OpenCart pas toujours activée) sinon crawl des catégories <mount>/fr avec ?limit=100&page=N, puis fiche par fiche …/<slug>-p<ID>/ (rendu 100 % serveur, aucune API). Pièges gérés: prix courant = <h2>…$</h2> et barré = span line-through (twitter:data1 affiche le prix RÉGULIER même en solde, gardé en secours), titre = dernier <h1> sans ancre (le 1er h1 est le logo-lien, og:title parfois bourré de mots-clés), dédup par ID produit (même p<ID> sous plusieurs chemins -p361c37c45c44), images OpenCart aux espaces bruts encodées. Registre: 45/61 boutiques confirmées live → platform=votresite + endpoint, les 16 autres sans boutique réelle (archivées/fermées) restent inertes. Sync réel: 45 ok / 0 erreur, 3 190 produits (bijouteriesimard 488, zylvery 312, alpagadore 238, monastère 174, vivelesepices 166…), 4 fiches vérifiées à la main contre la source (titre/prix/solde/modèle/dispo). Docs régénérées (fiche votresite.md), README 8→9 connecteurs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
17 changed files +671 −272
modified
README.md
+2 −2
@@ -15,7 +15,7 @@ | ||
| 15 | 15 |  |
| 16 | 16 |  |
| 17 | 17 |  |
| 18 | − | |
| 18 | + | |
| 19 | 19 |  |
| 20 | 20 |  |
| 21 | 21 | |
@@ -77,7 +77,7 @@ Acheter québécois demande de connaître des centaines de boutiques dispersées | ||
| 77 | 77 | | **Backend** | **Python 3.14** · **FastAPI** (API + SSR SEO + service du frontend) | |
| 78 | 78 | | **Base de données** | **SQLite + FTS5** — upsert par **hash de contenu**, retraits avec délai de grâce (2 syncs) | |
| 79 | 79 | | **Frontend** | **React 18 + Vite + TypeScript** — 9 pages, identité famille KA « éditorial sharp » (Space Grotesk + Inter + JetBrains Mono, palette crème/terracotta/pin/miel), tokens **ka-ui** | |
| 80 | −| **Connecteurs** | **Shopify** `products.json` (transport curl anti-429 TLS) · **WooCommerce** Store API · **Wix Stores** GraphQL · **Squarespace** `?format=json` · **Square Online** API storefront publique (`/app/store/api/v13/…/products`, IDs user/site extraits du HTML de la page d'accueil) · **connecteur générique** (sitemap → JSON-LD/microdata/OG : PrestaShop, Lightspeed, Snipcart, Magento, sites custom) · **Scrapfly/Firecrawl** en secours anti-bot. **Ecwid** non couvert : storefront 100 % client-side (l'API REST v3 exige un token secret — le token `pub…` de script.js est générique et refusé (403) ; aucun rendu serveur du catalogue, ni sur les instant sites ni via le plugin WordPress) | | |
| 80 | +| **Connecteurs** | **Shopify** `products.json` (transport curl anti-429 TLS) · **WooCommerce** Store API · **Wix Stores** GraphQL · **Squarespace** `?format=json` · **Square Online** API storefront publique (`/app/store/api/v13/…/products`, IDs user/site extraits du HTML de la page d'accueil) · **Votresite.ca** (plateforme QC : Drupal 8 + boutique OpenCart en sous-répertoire — sitemap OpenCart ou crawl des catégories, puis fiche par fiche) · **connecteur générique** (sitemap → JSON-LD/microdata/OG : PrestaShop, Lightspeed, Snipcart, Magento, sites custom) · **Scrapfly/Firecrawl** en secours anti-bot. **Ecwid** non couvert : storefront 100 % client-side (l'API REST v3 exige un token secret — le token `pub…` de script.js est générique et refusé (403) ; aucun rendu serveur du catalogue, ni sur les instant sites ni via le plugin WordPress) | | |
| 81 | 81 | | **Découverte** | **35+ sources** : sitemaps d'annuaires, API cachées de cartes (wpgmza, FacetWP), pagination htmx, sessions **Firecrawl** pour répertoires JS | |
| 82 | 82 | | **Comptes** | **KA ID** SSO (JWT HS256, stdlib pure) · favoris HMAC-SHA256 vers le hub central | |
| 83 | 83 | | **Prod** | **PM2** + **ngrok** sur le cluster **MacLustr** | |
modified
data/stores.json
+154 −154
@@ -3418,8 +3418,8 @@ | ||
| 3418 | 3418 | "id": "alpagadore.com", |
| 3419 | 3419 | "name": "AlpagAdore", |
| 3420 | 3420 | "url": "https://alpagadore.com", |
| 3421 | − "platform": "", | |
| 3422 | − "catalog_endpoint": "", | |
| 3421 | + "platform": "votresite", | |
| 3422 | + "catalog_endpoint": "/boutique", | |
| 3423 | 3423 | "city": "", |
| 3424 | 3424 | "region": "Montérégie", |
| 3425 | 3425 | "postal_prefix": "J0S", |
@@ -3444,7 +3444,7 @@ | ||
| 3444 | 3444 | "ecommerce": true, |
| 3445 | 3445 | "verification_date": "2026-08-12", |
| 3446 | 3446 | "status": "verified", |
| 3447 | − "enabled": false, | |
| 3447 | + "enabled": true, | |
| 3448 | 3448 | "last_reprobe": "2026-08-19", |
| 3449 | 3449 | "geo": { |
| 3450 | 3450 | "lat": 45.0131, |
@@ -5311,8 +5311,8 @@ | ||
| 5311 | 5311 | "id": "artcimentdecoration.ca", |
| 5312 | 5312 | "name": "Art Ciment décoration", |
| 5313 | 5313 | "url": "https://artcimentdecoration.ca", |
| 5314 | − "platform": "", | |
| 5315 | − "catalog_endpoint": "", | |
| 5314 | + "platform": "votresite", | |
| 5315 | + "catalog_endpoint": "/boutique", | |
| 5316 | 5316 | "city": "", |
| 5317 | 5317 | "region": "", |
| 5318 | 5318 | "postal_prefix": null, |
@@ -5334,10 +5334,10 @@ | ||
| 5334 | 5334 | "Art Ciment décoration Julie Bellemare québec" |
| 5335 | 5335 | ], |
| 5336 | 5336 | "language": "fr", |
| 5337 | − "ecommerce": false, | |
| 5337 | + "ecommerce": true, | |
| 5338 | 5338 | "verification_date": "2026-08-12", |
| 5339 | 5339 | "status": "verified", |
| 5340 | − "enabled": false, | |
| 5340 | + "enabled": true, | |
| 5341 | 5341 | "last_reprobe": "2026-08-19" |
| 5342 | 5342 | }, |
| 5343 | 5343 | { |
@@ -13016,8 +13016,8 @@ | ||
| 13016 | 13016 | "id": "bijouteriebrouillette.ca", |
| 13017 | 13017 | "name": "Bijouterie Brouillette", |
| 13018 | 13018 | "url": "https://bijouteriebrouillette.ca", |
| 13019 | − "platform": "", | |
| 13020 | − "catalog_endpoint": "", | |
| 13019 | + "platform": "votresite", | |
| 13020 | + "catalog_endpoint": "/boutique", | |
| 13021 | 13021 | "city": "", |
| 13022 | 13022 | "region": "", |
| 13023 | 13023 | "postal_prefix": null, |
@@ -13039,7 +13039,7 @@ | ||
| 13039 | 13039 | "ecommerce": true, |
| 13040 | 13040 | "verification_date": "2026-08-12", |
| 13041 | 13041 | "status": "probable", |
| 13042 | − "enabled": false, | |
| 13042 | + "enabled": true, | |
| 13043 | 13043 | "last_reprobe": "2026-08-19" |
| 13044 | 13044 | }, |
| 13045 | 13045 | { |
@@ -13467,8 +13467,8 @@ | ||
| 13467 | 13467 | "id": "bijouteriesimard.ca", |
| 13468 | 13468 | "name": "Bijouterie Simard", |
| 13469 | 13469 | "url": "https://bijouteriesimard.ca", |
| 13470 | − "platform": "", | |
| 13471 | − "catalog_endpoint": "", | |
| 13470 | + "platform": "votresite", | |
| 13471 | + "catalog_endpoint": "/boutique", | |
| 13472 | 13472 | "city": "", |
| 13473 | 13473 | "region": "Saguenay–Lac-Saint-Jean", |
| 13474 | 13474 | "postal_prefix": null, |
@@ -13490,7 +13490,7 @@ | ||
| 13490 | 13490 | "ecommerce": true, |
| 13491 | 13491 | "verification_date": "2026-08-12", |
| 13492 | 13492 | "status": "probable", |
| 13493 | − "enabled": false, | |
| 13493 | + "enabled": true, | |
| 13494 | 13494 | "last_reprobe": "2026-08-19" |
| 13495 | 13495 | }, |
| 13496 | 13496 | { |
@@ -18064,8 +18064,8 @@ | ||
| 18064 | 18064 | "id": "bourdeauartistepeintre.com", |
| 18065 | 18065 | "name": "Bourdeau artiste peintre", |
| 18066 | 18066 | "url": "https://bourdeauartistepeintre.com", |
| 18067 | − "platform": "", | |
| 18068 | − "catalog_endpoint": "", | |
| 18067 | + "platform": "votresite", | |
| 18068 | + "catalog_endpoint": "/boutique", | |
| 18069 | 18069 | "city": "", |
| 18070 | 18070 | "region": "Capitale-Nationale", |
| 18071 | 18071 | "postal_prefix": null, |
@@ -18089,10 +18089,10 @@ | ||
| 18089 | 18089 | "https://www.tourisme-charlevoix.com/fr/entreprises/bourdeau-artiste-peintre" |
| 18090 | 18090 | ], |
| 18091 | 18091 | "language": "fr", |
| 18092 | − "ecommerce": false, | |
| 18092 | + "ecommerce": true, | |
| 18093 | 18093 | "verification_date": "2026-08-12", |
| 18094 | 18094 | "status": "verified", |
| 18095 | − "enabled": false, | |
| 18095 | + "enabled": true, | |
| 18096 | 18096 | "last_reprobe": "2026-08-19" |
| 18097 | 18097 | }, |
| 18098 | 18098 | { |
@@ -20455,8 +20455,8 @@ | ||
| 20455 | 20455 | "id": "britanniamills.com", |
| 20456 | 20456 | "name": "Domaine Britannia Mills", |
| 20457 | 20457 | "url": "https://britanniamills.com", |
| 20458 | − "platform": "", | |
| 20459 | − "catalog_endpoint": "", | |
| 20458 | + "platform": "votresite", | |
| 20459 | + "catalog_endpoint": "/shop", | |
| 20460 | 20460 | "city": "", |
| 20461 | 20461 | "region": "Montérégie", |
| 20462 | 20462 | "postal_prefix": "J0H", |
@@ -20480,10 +20480,10 @@ | ||
| 20480 | 20480 | "https://alimentsduquebec.com/entreprises/domaine-britannia-mills" |
| 20481 | 20481 | ], |
| 20482 | 20482 | "language": "fr", |
| 20483 | − "ecommerce": false, | |
| 20483 | + "ecommerce": true, | |
| 20484 | 20484 | "verification_date": "2026-08-12", |
| 20485 | 20485 | "status": "verified", |
| 20486 | − "enabled": false, | |
| 20486 | + "enabled": true, | |
| 20487 | 20487 | "last_reprobe": "2026-08-19", |
| 20488 | 20488 | "geo": { |
| 20489 | 20489 | "lat": 45.6125, |
@@ -22243,8 +22243,8 @@ | ||
| 22243 | 22243 | "id": "cabanetilouisbrochu.com", |
| 22244 | 22244 | "name": "Cabane chez Ti-Louis Brochu", |
| 22245 | 22245 | "url": "https://cabanetilouisbrochu.com", |
| 22246 | − "platform": "", | |
| 22247 | − "catalog_endpoint": "", | |
| 22246 | + "platform": "votresite", | |
| 22247 | + "catalog_endpoint": "/boutique", | |
| 22248 | 22248 | "city": "", |
| 22249 | 22249 | "region": "Chaudière-Appalaches", |
| 22250 | 22250 | "postal_prefix": "G0S", |
@@ -22271,7 +22271,7 @@ | ||
| 22271 | 22271 | "ecommerce": true, |
| 22272 | 22272 | "verification_date": "2026-08-12", |
| 22273 | 22273 | "status": "probable", |
| 22274 | − "enabled": false, | |
| 22274 | + "enabled": true, | |
| 22275 | 22275 | "last_reprobe": "2026-08-19", |
| 22276 | 22276 | "geo": { |
| 22277 | 22277 | "lat": 46.2635, |
@@ -26378,8 +26378,8 @@ | ||
| 26378 | 26378 | "id": "centrefrancinethibeault.com", |
| 26379 | 26379 | "name": "Centre Santé-Beauté Francine Thibeault", |
| 26380 | 26380 | "url": "https://centrefrancinethibeault.com", |
| 26381 | − "platform": "", | |
| 26382 | − "catalog_endpoint": "", | |
| 26381 | + "platform": "votresite", | |
| 26382 | + "catalog_endpoint": "/boutique", | |
| 26383 | 26383 | "city": "", |
| 26384 | 26384 | "region": "Capitale-Nationale", |
| 26385 | 26385 | "postal_prefix": "G3Z", |
@@ -26403,10 +26403,10 @@ | ||
| 26403 | 26403 | "https://www.tourisme-charlevoix.com/fr/entreprises/centre-sante-beaute-francine-thibeault" |
| 26404 | 26404 | ], |
| 26405 | 26405 | "language": "fr", |
| 26406 | − "ecommerce": false, | |
| 26406 | + "ecommerce": true, | |
| 26407 | 26407 | "verification_date": "2026-08-12", |
| 26408 | 26408 | "status": "verified", |
| 26409 | − "enabled": false, | |
| 26409 | + "enabled": true, | |
| 26410 | 26410 | "last_reprobe": "2026-08-19", |
| 26411 | 26411 | "geo": { |
| 26412 | 26412 | "lat": 47.4454, |
@@ -27318,8 +27318,8 @@ | ||
| 27318 | 27318 | "id": "champdelfes.com", |
| 27319 | 27319 | "name": "Champ d'elfes", |
| 27320 | 27320 | "url": "https://champdelfes.com", |
| 27321 | − "platform": "", | |
| 27322 | − "catalog_endpoint": "", | |
| 27321 | + "platform": "votresite", | |
| 27322 | + "catalog_endpoint": "/boutique", | |
| 27323 | 27323 | "city": "", |
| 27324 | 27324 | "region": "", |
| 27325 | 27325 | "postal_prefix": null, |
@@ -27341,7 +27341,7 @@ | ||
| 27341 | 27341 | "ecommerce": true, |
| 27342 | 27342 | "verification_date": "2026-08-12", |
| 27343 | 27343 | "status": "probable", |
| 27344 | − "enabled": false, | |
| 27344 | + "enabled": true, | |
| 27345 | 27345 | "last_reprobe": "2026-08-19" |
| 27346 | 27346 | }, |
| 27347 | 27347 | { |
@@ -27999,8 +27999,8 @@ | ||
| 27999 | 27999 | "id": "charlevoixpurelaine.ca", |
| 28000 | 28000 | "name": "Charlevoix Pure laine - CMAQ", |
| 28001 | 28001 | "url": "https://charlevoixpurelaine.ca", |
| 28002 | − "platform": "", | |
| 28003 | − "catalog_endpoint": "", | |
| 28002 | + "platform": "votresite", | |
| 28003 | + "catalog_endpoint": "/boutique", | |
| 28004 | 28004 | "city": "", |
| 28005 | 28005 | "region": "Côte-Nord", |
| 28006 | 28006 | "postal_prefix": "G0T", |
@@ -28026,10 +28026,10 @@ | ||
| 28026 | 28026 | "Charlevoix pure laine Yvan Delage tricoteur québec" |
| 28027 | 28027 | ], |
| 28028 | 28028 | "language": "fr", |
| 28029 | − "ecommerce": false, | |
| 28029 | + "ecommerce": true, | |
| 28030 | 28030 | "verification_date": "2026-08-12", |
| 28031 | 28031 | "status": "verified", |
| 28032 | − "enabled": false, | |
| 28032 | + "enabled": true, | |
| 28033 | 28033 | "last_reprobe": "2026-08-19", |
| 28034 | 28034 | "geo": { |
| 28035 | 28035 | "lat": 47.6525, |
@@ -31179,8 +31179,8 @@ | ||
| 31179 | 31179 | "id": "closdespetitsbergers.ca", |
| 31180 | 31180 | "name": "Clos des Petits Bergers", |
| 31181 | 31181 | "url": "https://closdespetitsbergers.ca", |
| 31182 | − "platform": "", | |
| 31183 | − "catalog_endpoint": "", | |
| 31182 | + "platform": "votresite", | |
| 31183 | + "catalog_endpoint": "/boutique", | |
| 31184 | 31184 | "city": "", |
| 31185 | 31185 | "region": "Centre-du-Québec", |
| 31186 | 31186 | "postal_prefix": "J0C", |
@@ -31206,10 +31206,10 @@ | ||
| 31206 | 31206 | "https://goutezy.com/entreprise/clos-des-petits-bergers/" |
| 31207 | 31207 | ], |
| 31208 | 31208 | "language": "fr", |
| 31209 | − "ecommerce": false, | |
| 31209 | + "ecommerce": true, | |
| 31210 | 31210 | "verification_date": "2026-08-12", |
| 31211 | 31211 | "status": "probable", |
| 31212 | − "enabled": false, | |
| 31212 | + "enabled": true, | |
| 31213 | 31213 | "last_reprobe": "2026-08-18", |
| 31214 | 31214 | "geo": { |
| 31215 | 31215 | "lat": 45.9914, |
@@ -32476,8 +32476,8 @@ | ||
| 32476 | 32476 | "id": "concepterable.ca", |
| 32477 | 32477 | "name": "Conceptérable inc.", |
| 32478 | 32478 | "url": "https://concepterable.ca", |
| 32479 | − "platform": "", | |
| 32480 | − "catalog_endpoint": "", | |
| 32479 | + "platform": "votresite", | |
| 32480 | + "catalog_endpoint": "/produits", | |
| 32481 | 32481 | "city": "", |
| 32482 | 32482 | "region": "Capitale-Nationale", |
| 32483 | 32483 | "postal_prefix": "G0A", |
@@ -32501,10 +32501,10 @@ | ||
| 32501 | 32501 | "https://www.erabledici.ca/fr/erabliere/concepterable-inc/" |
| 32502 | 32502 | ], |
| 32503 | 32503 | "language": "fr", |
| 32504 | − "ecommerce": false, | |
| 32504 | + "ecommerce": true, | |
| 32505 | 32505 | "verification_date": "2026-08-12", |
| 32506 | 32506 | "status": "probable", |
| 32507 | − "enabled": false, | |
| 32507 | + "enabled": true, | |
| 32508 | 32508 | "last_reprobe": "2026-08-18", |
| 32509 | 32509 | "geo": { |
| 32510 | 32510 | "lat": 46.8524, |
@@ -38028,8 +38028,8 @@ | ||
| 38028 | 38028 | "id": "metamorphoseonaturel.ca", |
| 38029 | 38029 | "name": "Délices Sublimes", |
| 38030 | 38030 | "url": "https://metamorphoseonaturel.ca", |
| 38031 | − "platform": "", | |
| 38032 | − "catalog_endpoint": "", | |
| 38031 | + "platform": "votresite", | |
| 38032 | + "catalog_endpoint": "/boutique", | |
| 38033 | 38033 | "city": "", |
| 38034 | 38034 | "region": "Outaouais", |
| 38035 | 38035 | "postal_prefix": "J8V", |
@@ -38056,7 +38056,7 @@ | ||
| 38056 | 38056 | "ecommerce": true, |
| 38057 | 38057 | "verification_date": "2026-08-12", |
| 38058 | 38058 | "status": "verified", |
| 38059 | − "enabled": false, | |
| 38059 | + "enabled": true, | |
| 38060 | 38060 | "last_reprobe": "2026-08-19", |
| 38061 | 38061 | "geo": { |
| 38062 | 38062 | "lat": 45.488, |
@@ -40628,8 +40628,8 @@ | ||
| 40628 | 40628 | "id": "domainecotedunord.com", |
| 40629 | 40629 | "name": "Domaine Côte du Nord", |
| 40630 | 40630 | "url": "https://domainecotedunord.com", |
| 40631 | − "platform": "", | |
| 40632 | − "catalog_endpoint": "", | |
| 40631 | + "platform": "votresite", | |
| 40632 | + "catalog_endpoint": "/boutique", | |
| 40633 | 40633 | "city": "", |
| 40634 | 40634 | "region": "Côte-Nord", |
| 40635 | 40635 | "postal_prefix": "G0H", |
@@ -40655,7 +40655,7 @@ | ||
| 40655 | 40655 | "ecommerce": true, |
| 40656 | 40656 | "verification_date": "2026-08-12", |
| 40657 | 40657 | "status": "probable", |
| 40658 | − "enabled": false, | |
| 40658 | + "enabled": true, | |
| 40659 | 40659 | "last_reprobe": "2026-08-18", |
| 40660 | 40660 | "geo": { |
| 40661 | 40661 | "lat": 49.1633, |
@@ -41631,8 +41631,8 @@ | ||
| 41631 | 41631 | "id": "domainelacharmante.com", |
| 41632 | 41632 | "name": "Domaine La Charmante", |
| 41633 | 41633 | "url": "https://domainelacharmante.com", |
| 41634 | − "platform": "", | |
| 41635 | − "catalog_endpoint": "", | |
| 41634 | + "platform": "votresite", | |
| 41635 | + "catalog_endpoint": "/boutique", | |
| 41636 | 41636 | "city": "", |
| 41637 | 41637 | "region": "Chaudière-Appalaches", |
| 41638 | 41638 | "postal_prefix": "G0R", |
@@ -41656,10 +41656,10 @@ | ||
| 41656 | 41656 | "https://arretsgourmands.ca/arrets-gourmands/domaine-la-charmante" |
| 41657 | 41657 | ], |
| 41658 | 41658 | "language": "fr", |
| 41659 | − "ecommerce": false, | |
| 41659 | + "ecommerce": true, | |
| 41660 | 41660 | "verification_date": "2026-08-12", |
| 41661 | 41661 | "status": "probable", |
| 41662 | − "enabled": false, | |
| 41662 | + "enabled": true, | |
| 41663 | 41663 | "last_reprobe": "2026-08-18", |
| 41664 | 41664 | "geo": { |
| 41665 | 41665 | "lat": 46.9055, |
@@ -41763,8 +41763,8 @@ | ||
| 41763 | 41763 | "id": "domaineloreedesbois.ca", |
| 41764 | 41764 | "name": "Domaine L’Orée des Bois", |
| 41765 | 41765 | "url": "https://domaineloreedesbois.ca", |
| 41766 | − "platform": "", | |
| 41767 | − "catalog_endpoint": "", | |
| 41766 | + "platform": "votresite", | |
| 41767 | + "catalog_endpoint": "/boutique", | |
| 41768 | 41768 | "city": "", |
| 41769 | 41769 | "region": "Saguenay–Lac-Saint-Jean", |
| 41770 | 41770 | "postal_prefix": "G0W", |
@@ -41788,10 +41788,10 @@ | ||
| 41788 | 41788 | "https://zoneboreale.com/entreprises/domaine-loree-des-bois/" |
| 41789 | 41789 | ], |
| 41790 | 41790 | "language": "fr", |
| 41791 | − "ecommerce": false, | |
| 41791 | + "ecommerce": true, | |
| 41792 | 41792 | "verification_date": "2026-08-12", |
| 41793 | 41793 | "status": "verified", |
| 41794 | − "enabled": false, | |
| 41794 | + "enabled": true, | |
| 41795 | 41795 | "last_reprobe": "2026-08-18", |
| 41796 | 41796 | "geo": { |
| 41797 | 41797 | "lat": 48.8854, |
@@ -45996,8 +45996,8 @@ | ||
| 45996 | 45996 | "id": "erablieredulactaureau.com", |
| 45997 | 45997 | "name": "Érablière du Lac Taureau", |
| 45998 | 45998 | "url": "https://erablieredulactaureau.com", |
| 45999 | − "platform": "", | |
| 46000 | − "catalog_endpoint": "", | |
| 45999 | + "platform": "votresite", | |
| 46000 | + "catalog_endpoint": "/boutique", | |
| 46001 | 46001 | "city": "", |
| 46002 | 46002 | "region": "Lanaudière", |
| 46003 | 46003 | "postal_prefix": "J0K", |
@@ -46024,7 +46024,7 @@ | ||
| 46024 | 46024 | "ecommerce": true, |
| 46025 | 46025 | "verification_date": "2026-08-12", |
| 46026 | 46026 | "status": "probable", |
| 46027 | − "enabled": false, | |
| 46027 | + "enabled": true, | |
| 46028 | 46028 | "last_reprobe": "2026-08-18", |
| 46029 | 46029 | "geo": { |
| 46030 | 46030 | "lat": 46.104, |
@@ -66916,8 +66916,8 @@ | ||
| 66916 | 66916 | "id": "imatech-moore.com", |
| 66917 | 66917 | "name": "Imatech-Moore", |
| 66918 | 66918 | "url": "https://imatech-moore.com", |
| 66919 | − "platform": "", | |
| 66920 | − "catalog_endpoint": "", | |
| 66919 | + "platform": "votresite", | |
| 66920 | + "catalog_endpoint": "/boutique", | |
| 66921 | 66921 | "city": "", |
| 66922 | 66922 | "region": "Centre-du-Québec", |
| 66923 | 66923 | "postal_prefix": "G6P", |
@@ -66939,10 +66939,10 @@ | ||
| 66939 | 66939 | "https://lesproduitsduquebec.com/entreprises-adherentes/imatech-moore" |
| 66940 | 66940 | ], |
| 66941 | 66941 | "language": "fr", |
| 66942 | − "ecommerce": false, | |
| 66942 | + "ecommerce": true, | |
| 66943 | 66943 | "verification_date": "2026-08-12", |
| 66944 | 66944 | "status": "verified", |
| 66945 | − "enabled": false, | |
| 66945 | + "enabled": true, | |
| 66946 | 66946 | "last_reprobe": "2026-08-18", |
| 66947 | 66947 | "geo": { |
| 66948 | 66948 | "lat": 46.0606, |
@@ -68456,8 +68456,8 @@ | ||
| 68456 | 68456 | "id": "jardinschantdevie.com", |
| 68457 | 68457 | "name": "Jardins Chant de Vie - Goûtez-y!", |
| 68458 | 68458 | "url": "https://jardinschantdevie.com", |
| 68459 | − "platform": "", | |
| 68460 | − "catalog_endpoint": "", | |
| 68459 | + "platform": "votresite", | |
| 68460 | + "catalog_endpoint": "/boutique", | |
| 68461 | 68461 | "city": "", |
| 68462 | 68462 | "region": "Centre-du-Québec", |
| 68463 | 68463 | "postal_prefix": "J0B", |
@@ -68481,10 +68481,10 @@ | ||
| 68481 | 68481 | "https://goutezy.com/entreprise/jardins-chant-de-vie/" |
| 68482 | 68482 | ], |
| 68483 | 68483 | "language": "fr", |
| 68484 | − "ecommerce": false, | |
| 68484 | + "ecommerce": true, | |
| 68485 | 68485 | "verification_date": "2026-08-12", |
| 68486 | 68486 | "status": "verified", |
| 68487 | − "enabled": false, | |
| 68487 | + "enabled": true, | |
| 68488 | 68488 | "last_reprobe": "2026-08-19", |
| 68489 | 68489 | "geo": { |
| 68490 | 68490 | "lat": 45.242, |
@@ -77266,8 +77266,8 @@ | ||
| 77266 | 77266 | "id": "lamanchure.com", |
| 77267 | 77267 | "name": "LaManchure", |
| 77268 | 77268 | "url": "https://lamanchure.com", |
| 77269 | − "platform": "", | |
| 77270 | − "catalog_endpoint": "", | |
| 77269 | + "platform": "votresite", | |
| 77270 | + "catalog_endpoint": "/boutique", | |
| 77271 | 77271 | "city": "", |
| 77272 | 77272 | "region": "", |
| 77273 | 77273 | "postal_prefix": null, |
@@ -77289,7 +77289,7 @@ | ||
| 77289 | 77289 | "ecommerce": true, |
| 77290 | 77290 | "verification_date": "2026-08-12", |
| 77291 | 77291 | "status": "probable", |
| 77292 | − "enabled": false, | |
| 77292 | + "enabled": true, | |
| 77293 | 77293 | "last_reprobe": "2026-08-19" |
| 77294 | 77294 | }, |
| 77295 | 77295 | { |
@@ -82336,8 +82336,8 @@ | ||
| 82336 | 82336 | "id": "lemieldabee.ca", |
| 82337 | 82337 | "name": "Créateurs", |
| 82338 | 82338 | "url": "https://lemieldabee.ca", |
| 82339 | − "platform": "", | |
| 82340 | − "catalog_endpoint": "", | |
| 82339 | + "platform": "votresite", | |
| 82340 | + "catalog_endpoint": "/boutique", | |
| 82341 | 82341 | "city": "", |
| 82342 | 82342 | "region": "Estrie", |
| 82343 | 82343 | "postal_prefix": "J1E", |
@@ -82361,10 +82361,10 @@ | ||
| 82361 | 82361 | "https://createursdesaveurs.com/createurs/le-miel-dabee/" |
| 82362 | 82362 | ], |
| 82363 | 82363 | "language": "fr", |
| 82364 | − "ecommerce": false, | |
| 82364 | + "ecommerce": true, | |
| 82365 | 82365 | "verification_date": "2026-08-12", |
| 82366 | 82366 | "status": "verified", |
| 82367 | − "enabled": false, | |
| 82367 | + "enabled": true, | |
| 82368 | 82368 | "last_reprobe": "2026-08-19", |
| 82369 | 82369 | "geo": { |
| 82370 | 82370 | "lat": 45.4301, |
@@ -82617,8 +82617,8 @@ | ||
| 82617 | 82617 | "id": "lemoussonneur.ca", |
| 82618 | 82618 | "name": "Le Moussonneur", |
| 82619 | 82619 | "url": "https://lemoussonneur.ca", |
| 82620 | − "platform": "", | |
| 82621 | − "catalog_endpoint": "", | |
| 82620 | + "platform": "votresite", | |
| 82621 | + "catalog_endpoint": "/produits", | |
| 82622 | 82622 | "city": "", |
| 82623 | 82623 | "region": "Bas-Saint-Laurent", |
| 82624 | 82624 | "postal_prefix": null, |
@@ -82640,7 +82640,7 @@ | ||
| 82640 | 82640 | "ecommerce": true, |
| 82641 | 82641 | "verification_date": "2026-08-12", |
| 82642 | 82642 | "status": "probable", |
| 82643 | − "enabled": false, | |
| 82643 | + "enabled": true, | |
| 82644 | 82644 | "last_reprobe": "2026-08-19" |
| 82645 | 82645 | }, |
| 82646 | 82646 | { |
@@ -84587,8 +84587,8 @@ | ||
| 84587 | 84587 | "id": "lesappeauxdusaintlaurent.com", |
| 84588 | 84588 | "name": "Les appeaux du Saint-Laurent - CMAQ", |
| 84589 | 84589 | "url": "https://lesappeauxdusaintlaurent.com", |
| 84590 | − "platform": "", | |
| 84591 | − "catalog_endpoint": "", | |
| 84590 | + "platform": "votresite", | |
| 84591 | + "catalog_endpoint": "/boutique", | |
| 84592 | 84592 | "city": "", |
| 84593 | 84593 | "region": "", |
| 84594 | 84594 | "postal_prefix": "G6V", |
@@ -84613,7 +84613,7 @@ | ||
| 84613 | 84613 | "ecommerce": true, |
| 84614 | 84614 | "verification_date": "2026-08-12", |
| 84615 | 84615 | "status": "verified", |
| 84616 | − "enabled": false, | |
| 84616 | + "enabled": true, | |
| 84617 | 84617 | "last_reprobe": "2026-08-19", |
| 84618 | 84618 | "geo": { |
| 84619 | 84619 | "lat": 46.8207, |
@@ -86872,8 +86872,8 @@ | ||
| 86872 | 86872 | "id": "lesjardinsrevertere.ca", |
| 86873 | 86873 | "name": "Les Jardins Revertere S.E.N.C.", |
| 86874 | 86874 | "url": "https://lesjardinsrevertere.ca", |
| 86875 | − "platform": "", | |
| 86876 | − "catalog_endpoint": "", | |
| 86875 | + "platform": "votresite", | |
| 86876 | + "catalog_endpoint": "/boutique", | |
| 86877 | 86877 | "city": "", |
| 86878 | 86878 | "region": "Estrie", |
| 86879 | 86879 | "postal_prefix": "J0B", |
@@ -86902,7 +86902,7 @@ | ||
| 86902 | 86902 | "ecommerce": true, |
| 86903 | 86903 | "verification_date": "2026-08-12", |
| 86904 | 86904 | "status": "probable", |
| 86905 | − "enabled": false, | |
| 86905 | + "enabled": true, | |
| 86906 | 86906 | "last_reprobe": "2026-08-19", |
| 86907 | 86907 | "geo": { |
| 86908 | 86908 | "lat": 45.242, |
@@ -96495,8 +96495,8 @@ | ||
| 96495 | 96495 | "id": "merlaine.com", |
| 96496 | 96496 | "name": "Merlaine", |
| 96497 | 96497 | "url": "https://merlaine.com", |
| 96498 | − "platform": "", | |
| 96499 | − "catalog_endpoint": "", | |
| 96498 | + "platform": "votresite", | |
| 96499 | + "catalog_endpoint": "/boutique", | |
| 96500 | 96500 | "city": "", |
| 96501 | 96501 | "region": "", |
| 96502 | 96502 | "postal_prefix": null, |
@@ -96516,7 +96516,7 @@ | ||
| 96516 | 96516 | "ecommerce": true, |
| 96517 | 96517 | "verification_date": "2026-08-12", |
| 96518 | 96518 | "status": "probable", |
| 96519 | − "enabled": false, | |
| 96519 | + "enabled": true, | |
| 96520 | 96520 | "last_reprobe": "2026-08-19" |
| 96521 | 96521 | }, |
| 96522 | 96522 | { |
@@ -96912,8 +96912,8 @@ | ||
| 96912 | 96912 | "id": "michelecourtemanche.ca", |
| 96913 | 96913 | "name": "Michèle Courtemanche, artiste bijoutière - CMAQ", |
| 96914 | 96914 | "url": "https://michelecourtemanche.ca", |
| 96915 | − "platform": "", | |
| 96916 | − "catalog_endpoint": "", | |
| 96915 | + "platform": "votresite", | |
| 96916 | + "catalog_endpoint": "/boutique", | |
| 96917 | 96917 | "city": "", |
| 96918 | 96918 | "region": "Outaouais", |
| 96919 | 96919 | "postal_prefix": "J8Y", |
@@ -96938,7 +96938,7 @@ | ||
| 96938 | 96938 | "ecommerce": true, |
| 96939 | 96939 | "verification_date": "2026-08-12", |
| 96940 | 96940 | "status": "verified", |
| 96941 | − "enabled": false, | |
| 96941 | + "enabled": true, | |
| 96942 | 96942 | "last_reprobe": "2026-08-19", |
| 96943 | 96943 | "geo": { |
| 96944 | 96944 | "lat": 45.4603, |
@@ -99590,8 +99590,8 @@ | ||
| 99590 | 99590 | "id": "mlatelierdecouture.com", |
| 99591 | 99591 | "name": "M l’atelier de couture - CMAQ", |
| 99592 | 99592 | "url": "https://mlatelierdecouture.com", |
| 99593 | − "platform": "", | |
| 99594 | − "catalog_endpoint": "", | |
| 99593 | + "platform": "votresite", | |
| 99594 | + "catalog_endpoint": "/boutique", | |
| 99595 | 99595 | "city": "", |
| 99596 | 99596 | "region": "Chaudière-Appalaches", |
| 99597 | 99597 | "postal_prefix": "G0N", |
@@ -99616,7 +99616,7 @@ | ||
| 99616 | 99616 | "ecommerce": true, |
| 99617 | 99617 | "verification_date": "2026-08-12", |
| 99618 | 99618 | "status": "verified", |
| 99619 | − "enabled": false, | |
| 99619 | + "enabled": true, | |
| 99620 | 99620 | "last_reprobe": "2026-08-19", |
| 99621 | 99621 | "geo": { |
| 99622 | 99622 | "lat": 46.0651, |
@@ -100206,8 +100206,8 @@ | ||
| 100206 | 100206 | "id": "monasteredebethleem.ca", |
| 100207 | 100207 | "name": "Les Moniales de Bethléem - CMAQ", |
| 100208 | 100208 | "url": "https://monasteredebethleem.ca", |
| 100209 | − "platform": "", | |
| 100210 | − "catalog_endpoint": "", | |
| 100209 | + "platform": "votresite", | |
| 100210 | + "catalog_endpoint": "/boutique", | |
| 100211 | 100211 | "city": "", |
| 100212 | 100212 | "region": "Lanaudière", |
| 100213 | 100213 | "postal_prefix": "J0K", |
@@ -100232,7 +100232,7 @@ | ||
| 100232 | 100232 | "ecommerce": true, |
| 100233 | 100233 | "verification_date": "2026-08-12", |
| 100234 | 100234 | "status": "verified", |
| 100235 | − "enabled": false, | |
| 100235 | + "enabled": true, | |
| 100236 | 100236 | "last_reprobe": "2026-08-19", |
| 100237 | 100237 | "geo": { |
| 100238 | 100238 | "lat": 46.104, |
@@ -110027,8 +110027,8 @@ | ||
| 110027 | 110027 | "id": "patelin.ca", |
| 110028 | 110028 | "name": "Les produits Patelin", |
| 110029 | 110029 | "url": "https://patelin.ca", |
| 110030 | − "platform": "", | |
| 110031 | − "catalog_endpoint": "", | |
| 110030 | + "platform": "votresite", | |
| 110031 | + "catalog_endpoint": "/boutique", | |
| 110032 | 110032 | "city": "", |
| 110033 | 110033 | "region": "Chaudière-Appalaches", |
| 110034 | 110034 | "postal_prefix": "G0R", |
@@ -110052,10 +110052,10 @@ | ||
| 110052 | 110052 | "https://alimentsduquebec.com/entreprises/les-produits-patelin" |
| 110053 | 110053 | ], |
| 110054 | 110054 | "language": "fr", |
| 110055 | − "ecommerce": false, | |
| 110055 | + "ecommerce": true, | |
| 110056 | 110056 | "verification_date": "2026-08-12", |
| 110057 | 110057 | "status": "verified", |
| 110058 | − "enabled": false, | |
| 110058 | + "enabled": true, | |
| 110059 | 110059 | "last_reprobe": "2026-08-19", |
| 110060 | 110060 | "geo": { |
| 110061 | 110061 | "lat": 46.9055, |
@@ -110920,8 +110920,8 @@ | ||
| 110920 | 110920 | "id": "penelopeclinique.com", |
| 110921 | 110921 | "name": "Pénélope Clinique", |
| 110922 | 110922 | "url": "https://penelopeclinique.com", |
| 110923 | − "platform": "", | |
| 110924 | − "catalog_endpoint": "", | |
| 110923 | + "platform": "votresite", | |
| 110924 | + "catalog_endpoint": "/boutique", | |
| 110925 | 110925 | "city": "", |
| 110926 | 110926 | "region": "Laurentides", |
| 110927 | 110927 | "postal_prefix": "J7Z", |
@@ -110943,10 +110943,10 @@ | ||
| 110943 | 110943 | "piercing body jewelry Québec boutique en ligne" |
| 110944 | 110944 | ], |
| 110945 | 110945 | "language": "fr", |
| 110946 | − "ecommerce": false, | |
| 110946 | + "ecommerce": true, | |
| 110947 | 110947 | "verification_date": "2026-08-12", |
| 110948 | 110948 | "status": "probable", |
| 110949 | − "enabled": false, | |
| 110949 | + "enabled": true, | |
| 110950 | 110950 | "last_reprobe": "2026-08-19", |
| 110951 | 110951 | "geo": { |
| 110952 | 110952 | "lat": 45.795, |
@@ -122590,8 +122590,8 @@ | ||
| 122590 | 122590 | "id": "savonneriedemartigny.ca", |
| 122591 | 122591 | "name": "Savonnerie de Martigny", |
| 122592 | 122592 | "url": "https://savonneriedemartigny.ca", |
| 122593 | − "platform": "", | |
| 122594 | − "catalog_endpoint": "", | |
| 122593 | + "platform": "votresite", | |
| 122594 | + "catalog_endpoint": "/boutique", | |
| 122595 | 122595 | "city": "", |
| 122596 | 122596 | "region": "", |
| 122597 | 122597 | "postal_prefix": null, |
@@ -122614,7 +122614,7 @@ | ||
| 122614 | 122614 | "ecommerce": true, |
| 122615 | 122615 | "verification_date": "2026-08-12", |
| 122616 | 122616 | "status": "probable", |
| 122617 | − "enabled": false, | |
| 122617 | + "enabled": true, | |
| 122618 | 122618 | "last_reprobe": "2026-08-19" |
| 122619 | 122619 | }, |
| 122620 | 122620 | { |
@@ -124072,8 +124072,8 @@ | ||
| 124072 | 124072 | "id": "serreslouiseturcotte.com", |
| 124073 | 124073 | "name": "Serres Louise Turcotte", |
| 124074 | 124074 | "url": "https://serreslouiseturcotte.com", |
| 124075 | − "platform": "", | |
| 124076 | − "catalog_endpoint": "", | |
| 124075 | + "platform": "votresite", | |
| 124076 | + "catalog_endpoint": "/boutique", | |
| 124077 | 124077 | "city": "", |
| 124078 | 124078 | "region": "Saguenay–Lac-Saint-Jean", |
| 124079 | 124079 | "postal_prefix": "G0V", |
@@ -124100,7 +124100,7 @@ | ||
| 124100 | 124100 | "ecommerce": true, |
| 124101 | 124101 | "verification_date": "2026-08-12", |
| 124102 | 124102 | "status": "probable", |
| 124103 | − "enabled": false, | |
| 124103 | + "enabled": true, | |
| 124104 | 124104 | "last_reprobe": "2026-08-19", |
| 124105 | 124105 | "geo": { |
| 124106 | 124106 | "lat": 48.3448, |
@@ -127421,8 +127421,8 @@ | ||
| 127421 | 127421 | "id": "sucredorgedantan.com", |
| 127422 | 127422 | "name": "Sucre D'orge D'antan inc.", |
| 127423 | 127423 | "url": "https://sucredorgedantan.com", |
| 127424 | − "platform": "", | |
| 127425 | − "catalog_endpoint": "", | |
| 127424 | + "platform": "votresite", | |
| 127425 | + "catalog_endpoint": "/boutique", | |
| 127426 | 127426 | "city": "", |
| 127427 | 127427 | "region": "Estrie", |
| 127428 | 127428 | "postal_prefix": "J0B", |
@@ -127449,7 +127449,7 @@ | ||
| 127449 | 127449 | "ecommerce": true, |
| 127450 | 127450 | "verification_date": "2026-08-12", |
| 127451 | 127451 | "status": "verified", |
| 127452 | − "enabled": false, | |
| 127452 | + "enabled": true, | |
| 127453 | 127453 | "last_reprobe": "2026-08-19", |
| 127454 | 127454 | "geo": { |
| 127455 | 127455 | "lat": 45.242, |
@@ -131239,8 +131239,8 @@ | ||
| 131239 | 131239 | "id": "tresorsdesbois2.com", |
| 131240 | 131240 | "name": "Trésors des Bois", |
| 131241 | 131241 | "url": "https://tresorsdesbois2.com", |
| 131242 | − "platform": "", | |
| 131243 | − "catalog_endpoint": "", | |
| 131242 | + "platform": "votresite", | |
| 131243 | + "catalog_endpoint": "/boutique", | |
| 131244 | 131244 | "city": "", |
| 131245 | 131245 | "region": "Côte-Nord", |
| 131246 | 131246 | "postal_prefix": null, |
@@ -131260,7 +131260,7 @@ | ||
| 131260 | 131260 | "ecommerce": true, |
| 131261 | 131261 | "verification_date": "2026-08-12", |
| 131262 | 131262 | "status": "probable", |
| 131263 | − "enabled": false, | |
| 131263 | + "enabled": true, | |
| 131264 | 131264 | "last_reprobe": "2026-08-19" |
| 131265 | 131265 | }, |
| 131266 | 131266 | { |
@@ -133444,8 +133444,8 @@ | ||
| 133444 | 133444 | "id": "varin.ca", |
| 133445 | 133445 | "name": "Érablière Varin", |
| 133446 | 133446 | "url": "https://varin.ca", |
| 133447 | − "platform": "", | |
| 133448 | − "catalog_endpoint": "", | |
| 133447 | + "platform": "votresite", | |
| 133448 | + "catalog_endpoint": "/boutique", | |
| 133449 | 133449 | "city": "", |
| 133450 | 133450 | "region": "Laurentides", |
| 133451 | 133451 | "postal_prefix": "J0N", |
@@ -133469,10 +133469,10 @@ | ||
| 133469 | 133469 | "https://www.erabledici.ca/fr/erabliere/erabliere-varin/" |
| 133470 | 133470 | ], |
| 133471 | 133471 | "language": "fr", |
| 133472 | − "ecommerce": false, | |
| 133472 | + "ecommerce": true, | |
| 133473 | 133473 | "verification_date": "2026-08-12", |
| 133474 | 133474 | "status": "verified", |
| 133475 | − "enabled": false, | |
| 133475 | + "enabled": true, | |
| 133476 | 133476 | "last_reprobe": "2026-08-19", |
| 133477 | 133477 | "geo": { |
| 133478 | 133478 | "lat": 45.718, |
@@ -137007,8 +137007,8 @@ | ||
| 137007 | 137007 | "id": "vivelesepices.com", |
| 137008 | 137008 | "name": "Vive les Épices", |
| 137009 | 137009 | "url": "https://vivelesepices.com", |
| 137010 | − "platform": "", | |
| 137011 | − "catalog_endpoint": "", | |
| 137010 | + "platform": "votresite", | |
| 137011 | + "catalog_endpoint": "/boutique", | |
| 137012 | 137012 | "city": "", |
| 137013 | 137013 | "region": "Estrie", |
| 137014 | 137014 | "postal_prefix": "J1N", |
@@ -137035,7 +137035,7 @@ | ||
| 137035 | 137035 | "ecommerce": true, |
| 137036 | 137036 | "verification_date": "2026-08-12", |
| 137037 | 137037 | "status": "probable", |
| 137038 | − "enabled": false, | |
| 137038 | + "enabled": true, | |
| 137039 | 137039 | "last_reprobe": "2026-08-19", |
| 137040 | 137040 | "geo": { |
| 137041 | 137041 | "lat": 45.3814, |
@@ -138896,8 +138896,8 @@ | ||
| 138896 | 138896 | "id": "zylverybijouxdesign.com", |
| 138897 | 138897 | "name": "Zylvery-Bijoux Design", |
| 138898 | 138898 | "url": "https://zylverybijouxdesign.com", |
| 138899 | − "platform": "", | |
| 138900 | − "catalog_endpoint": "", | |
| 138899 | + "platform": "votresite", | |
| 138900 | + "catalog_endpoint": "/boutique", | |
| 138901 | 138901 | "city": "", |
| 138902 | 138902 | "region": "", |
| 138903 | 138903 | "postal_prefix": null, |
@@ -138922,7 +138922,7 @@ | ||
| 138922 | 138922 | "ecommerce": true, |
| 138923 | 138923 | "verification_date": "2026-08-12", |
| 138924 | 138924 | "status": "verified", |
| 138925 | − "enabled": false, | |
| 138925 | + "enabled": true, | |
| 138926 | 138926 | "last_reprobe": "2026-08-19" |
| 138927 | 138927 | }, |
| 138928 | 138928 | { |
@@ -152521,8 +152521,8 @@ | ||
| 152521 | 152521 | "id": "bouetteetbrouette.ca", |
| 152522 | 152522 | "name": "Bouette & Brouette", |
| 152523 | 152523 | "url": "https://bouetteetbrouette.ca", |
| 152524 | − "platform": "", | |
| 152525 | − "catalog_endpoint": "", | |
| 152524 | + "platform": "votresite", | |
| 152525 | + "catalog_endpoint": "/produits", | |
| 152526 | 152526 | "city": "", |
| 152527 | 152527 | "region": "Montérégie", |
| 152528 | 152528 | "postal_prefix": "J0J", |
@@ -152545,7 +152545,7 @@ | ||
| 152545 | 152545 | "ecommerce": true, |
| 152546 | 152546 | "verification_date": "2026-08-19", |
| 152547 | 152547 | "status": "probable", |
| 152548 | − "enabled": false, | |
| 152548 | + "enabled": true, | |
| 152549 | 152549 | "certifications": [ |
| 152550 | 152550 | { |
| 152551 | 152551 | "label": "Biologique — CARTV", |
@@ -154813,8 +154813,8 @@ | ||
| 154813 | 154813 | "id": "degermeenpousse.com", |
| 154814 | 154814 | "name": "De Germe en Pousse", |
| 154815 | 154815 | "url": "https://degermeenpousse.com", |
| 154816 | − "platform": "", | |
| 154817 | − "catalog_endpoint": "", | |
| 154816 | + "platform": "votresite", | |
| 154817 | + "catalog_endpoint": "/boutique", | |
| 154818 | 154818 | "city": "", |
| 154819 | 154819 | "region": "Laurentides", |
| 154820 | 154820 | "postal_prefix": "J7N", |
@@ -154834,7 +154834,7 @@ | ||
| 154834 | 154834 | "ecommerce": true, |
| 154835 | 154835 | "verification_date": "2026-08-19", |
| 154836 | 154836 | "status": "probable", |
| 154837 | − "enabled": false, | |
| 154837 | + "enabled": true, | |
| 154838 | 154838 | "certifications": [ |
| 154839 | 154839 | { |
| 154840 | 154840 | "label": "Biologique — CARTV", |
@@ -157031,8 +157031,8 @@ | ||
| 157031 | 157031 | "id": "fermelabonte.com", |
| 157032 | 157032 | "name": "Ferme Labonté et Filles", |
| 157033 | 157033 | "url": "https://fermelabonte.com", |
| 157034 | − "platform": "", | |
| 157035 | − "catalog_endpoint": "", | |
| 157034 | + "platform": "votresite", | |
| 157035 | + "catalog_endpoint": "/boutique", | |
| 157036 | 157036 | "city": "", |
| 157037 | 157037 | "region": "Chaudière-Appalaches", |
| 157038 | 157038 | "postal_prefix": "G0S", |
@@ -157051,10 +157051,10 @@ | ||
| 157051 | 157051 | "http://www.produitsbioquebec.info/interroGrandPublicFr.do" |
| 157052 | 157052 | ], |
| 157053 | 157053 | "language": "fr", |
| 157054 | − "ecommerce": false, | |
| 157054 | + "ecommerce": true, | |
| 157055 | 157055 | "verification_date": "2026-08-19", |
| 157056 | 157056 | "status": "verified", |
| 157057 | − "enabled": false, | |
| 157057 | + "enabled": true, | |
| 157058 | 157058 | "certifications": [ |
| 157059 | 157059 | { |
| 157060 | 157060 | "label": "Biologique — CARTV", |
@@ -158849,8 +158849,8 @@ | ||
| 158849 | 158849 | "id": "houblonsfranklin.com", |
| 158850 | 158850 | "name": "Houblons Franklin", |
| 158851 | 158851 | "url": "https://houblonsfranklin.com", |
| 158852 | − "platform": "", | |
| 158853 | − "catalog_endpoint": "", | |
| 158852 | + "platform": "votresite", | |
| 158853 | + "catalog_endpoint": "/produits", | |
| 158854 | 158854 | "city": "", |
| 158855 | 158855 | "region": "Montérégie", |
| 158856 | 158856 | "postal_prefix": "JOS", |
@@ -158869,10 +158869,10 @@ | ||
| 158869 | 158869 | "http://www.produitsbioquebec.info/interroGrandPublicFr.do" |
| 158870 | 158870 | ], |
| 158871 | 158871 | "language": "fr", |
| 158872 | − "ecommerce": false, | |
| 158872 | + "ecommerce": true, | |
| 158873 | 158873 | "verification_date": "2026-08-19", |
| 158874 | 158874 | "status": "probable", |
| 158875 | − "enabled": false, | |
| 158875 | + "enabled": true, | |
| 158876 | 158876 | "certifications": [ |
| 158877 | 158877 | { |
| 158878 | 158878 | "label": "Biologique — CARTV", |
@@ -162138,8 +162138,8 @@ | ||
| 162138 | 162138 | "id": "lejardindesvioloneux.ca", |
| 162139 | 162139 | "name": "Édith Baragar DBA Le Jardin des Violoneux", |
| 162140 | 162140 | "url": "https://lejardindesvioloneux.ca", |
| 162141 | − "platform": "", | |
| 162142 | − "catalog_endpoint": "", | |
| 162141 | + "platform": "votresite", | |
| 162142 | + "catalog_endpoint": "/boutique", | |
| 162143 | 162143 | "city": "", |
| 162144 | 162144 | "region": "Montérégie", |
| 162145 | 162145 | "postal_prefix": "J0H", |
@@ -162156,10 +162156,10 @@ | ||
| 162156 | 162156 | "http://www.produitsbioquebec.info/interroGrandPublicFr.do" |
| 162157 | 162157 | ], |
| 162158 | 162158 | "language": "fr", |
| 162159 | − "ecommerce": false, | |
| 162159 | + "ecommerce": true, | |
| 162160 | 162160 | "verification_date": "2026-08-19", |
| 162161 | 162161 | "status": "verified", |
| 162162 | − "enabled": false, | |
| 162162 | + "enabled": true, | |
| 162163 | 162163 | "certifications": [ |
| 162164 | 162164 | { |
| 162165 | 162165 | "label": "Biologique — CARTV", |
@@ -162426,8 +162426,8 @@ | ||
| 162426 | 162426 | "id": "lesfantaisiesdelerable.ca", |
| 162427 | 162427 | "name": "Marc Carignan enr.", |
| 162428 | 162428 | "url": "https://lesfantaisiesdelerable.ca", |
| 162429 | − "platform": "", | |
| 162430 | − "catalog_endpoint": "", | |
| 162429 | + "platform": "votresite", | |
| 162430 | + "catalog_endpoint": "/boutique", | |
| 162431 | 162431 | "city": "", |
| 162432 | 162432 | "region": "Montérégie", |
| 162433 | 162433 | "postal_prefix": "J7W", |
@@ -162447,7 +162447,7 @@ | ||
| 162447 | 162447 | "ecommerce": true, |
| 162448 | 162448 | "verification_date": "2026-08-19", |
| 162449 | 162449 | "status": "probable", |
| 162450 | − "enabled": false, | |
| 162450 | + "enabled": true, | |
| 162451 | 162451 | "certifications": [ |
| 162452 | 162452 | { |
| 162453 | 162453 | "label": "Biologique — CARTV", |
@@ -163210,8 +163210,8 @@ | ||
| 163210 | 163210 | "id": "manoverde.ca", |
| 163211 | 163211 | "name": "Mano Verde", |
| 163212 | 163212 | "url": "https://manoverde.ca", |
| 163213 | − "platform": "", | |
| 163214 | − "catalog_endpoint": "", | |
| 163213 | + "platform": "votresite", | |
| 163214 | + "catalog_endpoint": "/boutique", | |
| 163215 | 163215 | "city": "", |
| 163216 | 163216 | "region": "", |
| 163217 | 163217 | "postal_prefix": null, |
@@ -163234,7 +163234,7 @@ | ||
| 163234 | 163234 | "ecommerce": true, |
| 163235 | 163235 | "verification_date": "2026-08-19", |
| 163236 | 163236 | "status": "verified", |
| 163237 | − "enabled": false | |
| 163237 | + "enabled": true | |
| 163238 | 163238 | }, |
| 163239 | 163239 | { |
| 163240 | 163240 | "id": "mapleleaffoods.com", |
@@ -172841,8 +172841,8 @@ | ||
| 172841 | 172841 | "id": "paraventsdesign.com", |
| 172842 | 172842 | "name": "Design", |
| 172843 | 172843 | "url": "https://paraventsdesign.com", |
| 172844 | − "platform": "", | |
| 172845 | − "catalog_endpoint": "", | |
| 172844 | + "platform": "votresite", | |
| 172845 | + "catalog_endpoint": "/boutique", | |
| 172846 | 172846 | "city": "", |
| 172847 | 172847 | "region": "Lanaudière", |
| 172848 | 172848 | "postal_prefix": "J0K", |
@@ -172866,7 +172866,7 @@ | ||
| 172866 | 172866 | "ecommerce": true, |
| 172867 | 172867 | "verification_date": "2026-08-21", |
| 172868 | 172868 | "status": "verified", |
| 172869 | − "enabled": false, | |
| 172869 | + "enabled": true, | |
| 172870 | 172870 | "geo": { |
| 172871 | 172871 | "lat": 46.104, |
| 172872 | 172872 | "lng": -73.256, |
@@ -173767,4 +173767,4 @@ | ||
| 173767 | 173767 | } |
| 173768 | 173768 | } |
| 173769 | 173769 | ] |
| 173770 | −} | |
| 173770 | +} | |
| \ No newline at end of file | ||
modified
docs/connecteurs/INDEX.md
+25 −24
@@ -1,21 +1,22 @@ | ||
| 1 | 1 | # Fabri-Ka — Connecteurs (documentation standardisée) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | −**3507 boutiques** au registre (`data/stores.json`, généré le 2026-08-18), **1 570** activées en base, **300 526 produits actifs**. Un connecteur par PLATEFORME e-commerce (dispatch `fabrika/connectors/__init__.py`), plus un transport de secours Scrapfly et deux pipelines transverses (découverte/registre, enrichissement). | |
| 5 | +**4082 boutiques** au registre (`data/stores.json`, généré le 2026-08-21), **1 701** activées en base, **361 215 produits actifs**. Un connecteur par PLATEFORME e-commerce (dispatch `fabrika/connectors/__init__.py`), plus un transport de secours Scrapfly et deux pipelines transverses (découverte/registre, enrichissement). | |
| 6 | 6 | |
| 7 | 7 | ## Connecteurs-plateformes |
| 8 | 8 | |
| 9 | 9 | | Connecteur | Fiche | Boutiques (registre) | Avec produits | Produits actifs | Prix | Photos | Détails | |
| 10 | 10 | |---|---|---|---|---|---|---|---| |
| 11 | −| Connecteur Shopify | [shopify](shopify.md) | 702 | 642 | 207 187 | 99.2 % | 96.5 % | 100.0 % | | |
| 12 | −| Connecteur WooCommerce (Store API) | [woocommerce](woocommerce.md) | 1320 | 442 | 74 048 | 94.0 % | 71.8 % | 86.6 % | | |
| 13 | −| Connecteur Wix Stores | [wix](wix.md) | 339 | 197 | 7 423 | 97.0 % | 98.6 % | 97.9 % | | |
| 14 | −| Connecteur Squarespace | [squarespace](squarespace.md) | 128 | 23 | 803 | 100.0 % | 99.6 % | 0.0 % | | |
| 15 | −| Connecteur Square Online | [square](square.md) | 56 | 36 | 2 833 | 99.7 % | 92.5 % | 100.0 % | | |
| 16 | −| Connecteur générique (JSON-LD / microdata / OG) | [generic](generic.md) | 74 | 23 | 8 232 | 100.0 % | 82.8 % | 0.0 % | | |
| 11 | +| Connecteur Shopify | [shopify](shopify.md) | 763 | 694 | 244 732 | 99.3 % | 96.8 % | 100.0 % | | |
| 12 | +| Connecteur WooCommerce (Store API) | [woocommerce](woocommerce.md) | 1556 | 509 | 92 521 | 86.4 % | 71.5 % | 87.8 % | | |
| 13 | +| Connecteur Wix Stores | [wix](wix.md) | 393 | 240 | 8 924 | 97.1 % | 98.5 % | 97.5 % | | |
| 14 | +| Connecteur Squarespace | [squarespace](squarespace.md) | 157 | 23 | 788 | 100.0 % | 99.6 % | 0.0 % | | |
| 15 | +| Connecteur Square Online | [square](square.md) | 68 | 36 | 2 832 | 99.7 % | 92.5 % | 100.0 % | | |
| 16 | +| Connecteur Votresite.ca (Drupal + OpenCart) | [votresite](votresite.md) | 45 | 43 | 3 190 | 95.5 % | 100.0 % | 100.0 % | | |
| 17 | +| Connecteur générique (JSON-LD / microdata / OG) | [generic](generic.md) | 81 | 23 | 8 228 | 100.0 % | 82.8 % | 0.0 % | | |
| 17 | 18 | | Transport Scrapfly | [scrapfly-transport](scrapfly-transport.md) | — | — | — | — | — | — | |
| 18 | −| Ecwid (verdict : non couvert) | [ecwid](ecwid.md) | 15 | 0 | 0 | — | — | — | | |
| 19 | +| Ecwid (verdict : non couvert) | [ecwid](ecwid.md) | 19 | 0 | 0 | — | — | — | | |
| 19 | 20 | |
| 20 | 21 | Pipelines transverses : [découverte & registre](decouverte-registre.md) · [enrichissement boutiques](enrichissement-boutiques.md). |
| 21 | 22 | |
@@ -23,21 +24,21 @@ Pipelines transverses : [découverte & registre](decouverte-registre.md) · [enr | ||
| 23 | 24 | |
| 24 | 25 | | Boutique | Domaine | Plateforme | Produits | Dernier sync | |
| 25 | 26 | |---|---|---|---|---| |
| 26 | −| Ici & Là - T-shirts et Souvenirs des régions - Acheter québécois | `ici-la.co` | shopify | 20 075 | 2026-08-19 02:27 | | |
| 27 | −| GAGNON - La Grande Quincaillerie | `gagnonlgq.com` | shopify | 19 516 | 2026-08-19 02:16 | | |
| 28 | −| Pieces de remorques et accessoires - Acheter québécois | `remorquetrailer.com` | woocommerce | 19 358 | 2026-08-19 03:23 | | |
| 29 | −| La Maison du Bleuet | `lamaisondubleuet.com` | shopify | 8 629 | 2026-08-19 02:36 | | |
| 30 | −| Bijouterie Jodoin | `bijouteriejodoin.com` | shopify | 8 252 | 2026-08-19 01:24 | | |
| 31 | −| Oberson | `oberson.com` | shopify | 7 419 | 2026-08-19 03:14 | | |
| 32 | −| Coopérative La Manne - Goûtez-y! | `cooplamanne.com` | woocommerce | 7 216 | 2026-08-19 01:48 | | |
| 33 | −| LilloJEUX | `lillojeux.ca` | woocommerce | 6 590 | 2026-08-19 02:50 | | |
| 34 | −| Paperole | `paperole.com` | shopify | 4 946 | 2026-08-19 03:15 | | |
| 35 | −| Veille sur toi Inc. - CMAQ | `veillesurtoi.com` | shopify | 4 431 | 2026-08-18 22:07 | | |
| 36 | −| Chic Placard | `chicplacard.ca` | shopify | 4 420 | 2026-08-19 01:43 | | |
| 37 | −| Bijoux Medusa | `bijouxmedusa.com` | shopify | 3 794 | 2026-08-19 01:25 | | |
| 38 | −| Les Ptits Mosüs (Alice et Simone) | `lesptitsmosus.com` | shopify | 3 396 | 2026-08-19 02:46 | | |
| 39 | −| Poches & Fils | `pochesetfils.com` | shopify | 3 238 | 2026-08-19 03:16 | | |
| 40 | −| Biscotte Yarns | `biscotteyarns.com` | shopify | 3 194 | 2026-08-19 01:26 | | |
| 27 | +| Ici & Là - T-shirts et Souvenirs des régions - Acheter québécois | `ici-la.co` | shopify | 20 075 | 2026-08-23 15:14 | | |
| 28 | +| GAGNON - La Grande Quincaillerie | `gagnonlgq.com` | shopify | 19 519 | 2026-08-23 15:10 | | |
| 29 | +| Pieces de remorques et accessoires - Acheter québécois | `remorquetrailer.com` | woocommerce | 19 372 | 2026-08-23 13:43 | | |
| 30 | +| EPIPRESTO | `epipresto.ca` | shopify | 13 266 | 2026-08-23 13:59 | | |
| 31 | +| La Boite à Grains | `laboiteagrains.com` | shopify | 10 403 | 2026-08-23 14:00 | | |
| 32 | +| La Maison du Bleuet | `lamaisondubleuet.com` | shopify | 8 652 | 2026-08-23 15:16 | | |
| 33 | +| Bijouterie Jodoin | `bijouteriejodoin.com` | shopify | 8 012 | 2026-08-23 14:53 | | |
| 34 | +| Oberson | `oberson.com` | shopify | 7 519 | 2026-08-23 13:34 | | |
| 35 | +| Coopérative La Manne - Goûtez-y! | `cooplamanne.com` | woocommerce | 7 220 | 2026-08-23 15:03 | | |
| 36 | +| LilloJEUX | `lillojeux.ca` | woocommerce | 6 608 | 2026-08-23 15:22 | | |
| 37 | +| Paperole | `paperole.com` | shopify | 4 970 | 2026-08-23 13:35 | | |
| 38 | +| Veille sur toi Inc. - CMAQ | `veillesurtoi.com` | shopify | 4 455 | 2026-08-23 13:45 | | |
| 39 | +| Chic Placard | `chicplacard.ca` | shopify | 4 419 | 2026-08-23 14:58 | | |
| 40 | +| Norseco S.E.C. | `norseco.com` | woocommerce | 4 295 | 2026-08-23 13:57 | | |
| 41 | +| Bijoux Medusa | `bijouxmedusa.com` | shopify | 3 797 | 2026-08-23 14:53 | | |
| 41 | 42 | |
| 42 | 43 | ## Gotchas transverses |
| 43 | 44 | |
modified
docs/connecteurs/decouverte-registre.md
+20 −19
@@ -1,16 +1,16 @@ | ||
| 1 | 1 | # Découverte & registre (`data/stores.json`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | −Registre généré le **2026-08-18** — **3507 boutiques** (champ `count`), toutes avec id (domaine canonique), plateforme, endpoint catalogue, classe d'origine, preuves et sources de découverte. | |
| 5 | +Registre généré le **2026-08-21** — **4082 boutiques** (champ `count`), toutes avec id (domaine canonique), plateforme, endpoint catalogue, classe d'origine, preuves et sources de découverte. | |
| 6 | 6 | |
| 7 | 7 | ## Classes d'origine (`origin_class`) |
| 8 | 8 | |
| 9 | 9 | | Classe | Boutiques | Signification | |
| 10 | 10 | |---|---|---| |
| 11 | −| A | 3303 | fabrication/production au Québec attestée | | |
| 12 | −| C | 37 | marque québécoise (fabrication partielle ou incertaine) | | |
| 13 | −| E | 167 | à requalifier / preuve faible | | |
| 11 | +| A | 3864 | fabrication/production au Québec attestée | | |
| 12 | +| C | 39 | marque québécoise (fabrication partielle ou incertaine) | | |
| 13 | +| E | 179 | à requalifier / preuve faible | | |
| 14 | 14 | |
| 15 | 15 | Confiance : `origin_confidence` (0-1) + `origin_evidence` (texte de preuve, annuaire ou mention sur le site). |
| 16 | 16 | |
@@ -19,6 +19,7 @@ Confiance : `origin_confidence` (0-1) + `origin_evidence` (texte de preuve, annu | ||
| 19 | 19 | | Source | Boutiques | |
| 20 | 20 | |---|---| |
| 21 | 21 | | `alimentsduquebec_ent` | 752 | |
| 22 | +| `cartv_bio` | 340 | | |
| 22 | 23 | | `lesproduitsduquebec_ent` | 329 | |
| 23 | 24 | | `charlevoix` | 304 | |
| 24 | 25 | | `zoneboreale` | 264 | |
@@ -32,28 +33,28 @@ Confiance : `origin_confidence` (0-1) + `origin_evidence` (texte de preuve, annu | ||
| 32 | 33 | | `search_sweep_nonfood` | 104 | |
| 33 | 34 | | `search_sweep_vendors` | 97 | |
| 34 | 35 | | `search_sweep_cmaq` | 94 | |
| 35 | −| `marchespublics` | 80 | | |
| 36 | 36 | |
| 37 | −Statuts de vérification : `verified` : 2273, `probable` : 1234 | |
| 37 | +Statuts de vérification : `verified` : 2656, `probable` : 1426 | |
| 38 | 38 | |
| 39 | 39 | ## Plateformes détectées au registre |
| 40 | 40 | |
| 41 | 41 | | Plateforme | Boutiques | |
| 42 | 42 | |---|---| |
| 43 | −| `(vide)` | 873 | | |
| 44 | −| `woocommerce` | 756 | | |
| 45 | −| `shopify` | 702 | | |
| 46 | −| `wordpress` | 564 | | |
| 47 | −| `wix` | 339 | | |
| 48 | −| `squarespace` | 128 | | |
| 49 | −| `square` | 56 | | |
| 43 | +| `(vide)` | 1000 | | |
| 44 | +| `woocommerce` | 888 | | |
| 45 | +| `shopify` | 763 | | |
| 46 | +| `wordpress` | 668 | | |
| 47 | +| `wix` | 393 | | |
| 48 | +| `squarespace` | 157 | | |
| 49 | +| `square` | 68 | | |
| 50 | +| `votresite` | 45 | | |
| 51 | +| `lightspeed` | 23 | | |
| 50 | 52 | | `generic` | 22 | |
| 51 | −| `lightspeed` | 20 | | |
| 52 | −| `ecwid` | 15 | | |
| 53 | −| `snipcart` | 14 | | |
| 54 | −| `magento` | 9 | | |
| 53 | +| `ecwid` | 19 | | |
| 54 | +| `snipcart` | 15 | | |
| 55 | +| `magento` | 11 | | |
| 55 | 56 | | `prestashop` | 8 | |
| 56 | −| `bigcommerce` | 1 | | |
| 57 | +| `bigcommerce` | 2 | | |
| 57 | 58 | |
| 58 | 59 | ## Re-sondage (`scripts/reprobe_stores.py`) |
| 59 | 60 | |
modified
docs/connecteurs/ecwid.md
+6 −2
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Ecwid — verdict : NON COUVERT |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Verdict |
| 6 | 6 | |
@@ -14,15 +14,19 @@ | ||
| 14 | 14 | - Conséquence : les boutiques Ecwid restent au registre (`enabled=0`, |
| 15 | 15 | plateforme détectée) en attente d'une éventuelle voie d'accès. |
| 16 | 16 | |
| 17 | −## Boutiques Ecwid recensées (15) | |
| 17 | +## Boutiques Ecwid recensées (19) | |
| 18 | 18 | |
| 19 | 19 | | Boutique | Domaine | Statut registre | |
| 20 | 20 | |---|---|---| |
| 21 | 21 | | Spiritueux Alpha Tango | `alphatango.ca` | désactivée (pas d'endpoint) | |
| 22 | 22 | | Boswell Brasserie Artisanale | `brasserieboswell.com` | désactivée (pas d'endpoint) | |
| 23 | 23 | | Camp de Base Brasserie Artisanale | `brasseriecampdebase.com` | désactivée (pas d'endpoint) | |
| 24 | +| Fruits et Légumes en gros Montréal | `canadawidefruits.com` | désactivée (pas d'endpoint) | | |
| 25 | +| Ferme Charejo inc. | `charejo.com` | désactivée (pas d'endpoint) | | |
| 24 | 26 | | Crème Boulangerie Pâtisserie | `cremecreme.ca` | désactivée (pas d'endpoint) | |
| 25 | 27 | | Centre de production DAÏMÔN | `daimon.qc.ca` | désactivée (pas d'endpoint) | |
| 28 | +| Dums Coffee inc. | `dumscoffee.com` | désactivée (pas d'endpoint) | | |
| 29 | +| Érablière Hatley | `erablierehatley.com` | désactivée (pas d'endpoint) | | |
| 26 | 30 | | Ferme Gadbois | `fermegadbois.com` | désactivée (pas d'endpoint) | |
| 27 | 31 | | Frescadel International Inc. | `frescadel.com` | désactivée (pas d'endpoint) | |
| 28 | 32 | | Fromagerie de l'Île-aux-Grues (Agrilait s.e.c.) | `fromagesileauxgrues.com` | désactivée (pas d'endpoint) | |
modified
docs/connecteurs/enrichissement-boutiques.md
+3 −3
@@ -1,16 +1,16 @@ | ||
| 1 | 1 | # Enrichissement des boutiques |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | Deux scripts rejouables complètent la table `stores` (colonnes additives `logo_url`, `cover_url`, `description_meta`, `shipping_info`). |
| 6 | 6 | |
| 7 | 7 | ## `scripts/enrich_stores.py` — logo / couverture / description |
| 8 | 8 | |
| 9 | −- Couverture actuelle : **logo 3220/3507** (91.8 %), **cover 1938/3507** (55.3 %). | |
| 9 | +- Couverture actuelle : **logo 3220/4082** (78.9 %), **cover 1938/4082** (47.5 %). | |
| 10 | 10 | - Cache disque `data/enrich_cache/` : 3224 fichiers (page d'accueil analysée une seule fois ; Scrapfly en secours pour les 403). |
| 11 | 11 | |
| 12 | 12 | ## `scripts/enrich_shipping.py` — politiques de livraison (vague 2) |
| 13 | 13 | |
| 14 | −- Couverture actuelle : **shipping_info 365/3507** (10.4 %) — ciblé sur les boutiques productives (`product_count > 0`). | |
| 14 | +- Couverture actuelle : **shipping_info 365/4082** (8.9 %) — ciblé sur les boutiques productives (`product_count > 0`). | |
| 15 | 15 | - Cache disque `data/enrich_cache/shipping/` : 618 fichiers (échecs mémorisés pour ne pas re-marteler les sites). |
| 16 | 16 | |
modified
docs/connecteurs/generic.md
+8 −8
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur générique (JSON-LD / microdata / OG) (`generic`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -21,24 +21,24 @@ | ||
| 21 | 21 | |
| 22 | 22 | ## Boutiques rattachées |
| 23 | 23 | |
| 24 | −- Registre `data/stores.json` : **74** boutiques | |
| 24 | +- Registre `data/stores.json` : **81** boutiques | |
| 25 | 25 | - En base (table `stores`) : **30** activées, **23** avec produits |
| 26 | 26 | |
| 27 | 27 | **Top 5 par volume :** |
| 28 | 28 | |
| 29 | 29 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 30 | 30 | |---|---|---|---|---| |
| 31 | −| Alpha Signa | `alphasigna.com` | 800 | 2026-08-19 01:10 | ok | | |
| 32 | −| Bijouterie Concept | `bijouterieconcept.com` | 800 | 2026-08-19 01:52 | ok | | |
| 33 | −| Mondou | `mondou.com` | 799 | 2026-08-19 03:05 | ok | | |
| 34 | −| Boutique Nomade | `boutiquenomade.net` | 799 | 2026-08-19 01:30 | ok | | |
| 35 | −| Bijouterie Pénélope | `bijouteriepenelope.com` | 798 | 2026-08-19 01:20 | ok | | |
| 31 | +| Alpha Signa | `alphasigna.com` | 800 | 2026-08-23 14:49 | ok | | |
| 32 | +| Bijouterie Concept | `bijouterieconcept.com` | 800 | 2026-08-23 15:31 | ok | | |
| 33 | +| Mondou | `mondou.com` | 799 | 2026-08-23 15:31 | ok | | |
| 34 | +| Boutique Nomade | `boutiquenomade.net` | 799 | 2026-08-23 14:55 | ok | | |
| 35 | +| Bijouterie Pénélope | `bijouteriepenelope.com` | 798 | 2026-08-23 14:52 | ok | | |
| 36 | 36 | |
| 37 | 37 | ## Volumétrie & complétude (BD live) |
| 38 | 38 | |
| 39 | 39 | | Indicateur | Valeur | |
| 40 | 40 | |---|---| |
| 41 | −| Produits actifs | 8 232 | | |
| 41 | +| Produits actifs | 8 228 | | |
| 42 | 42 | | Prix | 100.0 % | |
| 43 | 43 | | Photos | 82.8 % | |
| 44 | 44 | | Description | 95.4 % | |
modified
docs/connecteurs/scrapfly-transport.md
+1 −1
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Transport de secours Scrapfly (`scrapfly-transport`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique |
| 6 | 6 | |
modified
docs/connecteurs/shopify.md
+12 −12
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur Shopify (`shopify`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -17,27 +17,27 @@ | ||
| 17 | 17 | |
| 18 | 18 | ## Boutiques rattachées |
| 19 | 19 | |
| 20 | −- Registre `data/stores.json` : **702** boutiques | |
| 21 | −- En base (table `stores`) : **662** activées, **642** avec produits | |
| 20 | +- Registre `data/stores.json` : **763** boutiques | |
| 21 | +- En base (table `stores`) : **715** activées, **694** avec produits | |
| 22 | 22 | |
| 23 | 23 | **Top 5 par volume :** |
| 24 | 24 | |
| 25 | 25 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 26 | 26 | |---|---|---|---|---| |
| 27 | −| Ici & Là - T-shirts et Souvenirs des régions - Acheter québécois | `ici-la.co` | 20 075 | 2026-08-19 02:27 | ok | | |
| 28 | −| GAGNON - La Grande Quincaillerie | `gagnonlgq.com` | 19 516 | 2026-08-19 02:16 | ok | | |
| 29 | −| La Maison du Bleuet | `lamaisondubleuet.com` | 8 629 | 2026-08-19 02:36 | ok | | |
| 30 | −| Bijouterie Jodoin | `bijouteriejodoin.com` | 8 252 | 2026-08-19 01:24 | ok | | |
| 31 | −| Oberson | `oberson.com` | 7 419 | 2026-08-19 03:14 | ok | | |
| 27 | +| Ici & Là - T-shirts et Souvenirs des régions - Acheter québécois | `ici-la.co` | 20 075 | 2026-08-23 15:14 | ok | | |
| 28 | +| GAGNON - La Grande Quincaillerie | `gagnonlgq.com` | 19 519 | 2026-08-23 15:10 | ok | | |
| 29 | +| EPIPRESTO | `epipresto.ca` | 13 266 | 2026-08-23 13:59 | ok | | |
| 30 | +| La Boite à Grains | `laboiteagrains.com` | 10 403 | 2026-08-23 14:00 | ok | | |
| 31 | +| La Maison du Bleuet | `lamaisondubleuet.com` | 8 652 | 2026-08-23 15:16 | ok | | |
| 32 | 32 | |
| 33 | 33 | ## Volumétrie & complétude (BD live) |
| 34 | 34 | |
| 35 | 35 | | Indicateur | Valeur | |
| 36 | 36 | |---|---| |
| 37 | −| Produits actifs | 207 187 | | |
| 38 | −| Prix | 99.2 % | | |
| 39 | −| Photos | 96.5 % | | |
| 40 | −| Description | 94.0 % | | |
| 37 | +| Produits actifs | 244 732 | | |
| 38 | +| Prix | 99.3 % | | |
| 39 | +| Photos | 96.8 % | | |
| 40 | +| Description | 90.2 % | | |
| 41 | 41 | | Détails (variantes/attributs) | 100.0 % | |
| 42 | 42 | | — dont avis (rating/review_count) | 0.0 % | |
| 43 | 43 | | — dont poids/dimensions | 0.1 % | |
modified
docs/connecteurs/square.md
+9 −9
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur Square Online (`square`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -21,27 +21,27 @@ | ||
| 21 | 21 | |
| 22 | 22 | ## Boutiques rattachées |
| 23 | 23 | |
| 24 | −- Registre `data/stores.json` : **56** boutiques | |
| 24 | +- Registre `data/stores.json` : **68** boutiques | |
| 25 | 25 | - En base (table `stores`) : **36** activées, **36** avec produits |
| 26 | 26 | |
| 27 | 27 | **Top 5 par volume :** |
| 28 | 28 | |
| 29 | 29 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 30 | 30 | |---|---|---|---|---| |
| 31 | −| BIZZ coopérative d’alimentation locale | `bizzcoop.com` | 558 | 2026-08-19 01:24 | ok | | |
| 32 | −| À Outrance | `aoutrance.com` | 303 | 2026-08-19 01:08 | ok | | |
| 33 | −| Misskikooz | `melissacharette.com` | 280 | 2026-08-19 02:59 | ok | | |
| 34 | −| ÉCONOMUSÉE® du cidrier | `charlevoixenligne.com` | 213 | 2026-08-19 01:38 | ok | | |
| 35 | −| Chaga aromatisé - Acheter québécois | `sorcieredepouvoir.com` | 213 | 2026-08-19 03:26 | ok | | |
| 31 | +| BIZZ coopérative d’alimentation locale | `bizzcoop.com` | 558 | 2026-08-23 14:53 | ok | | |
| 32 | +| À Outrance | `aoutrance.com` | 303 | 2026-08-23 14:49 | ok | | |
| 33 | +| Misskikooz | `melissacharette.com` | 280 | 2026-08-23 15:27 | ok | | |
| 34 | +| ÉCONOMUSÉE® du cidrier | `charlevoixenligne.com` | 213 | 2026-08-23 14:57 | ok | | |
| 35 | +| Chaga aromatisé - Acheter québécois | `sorcieredepouvoir.com` | 213 | 2026-08-23 13:40 | ok | | |
| 36 | 36 | |
| 37 | 37 | ## Volumétrie & complétude (BD live) |
| 38 | 38 | |
| 39 | 39 | | Indicateur | Valeur | |
| 40 | 40 | |---|---| |
| 41 | −| Produits actifs | 2 833 | | |
| 41 | +| Produits actifs | 2 832 | | |
| 42 | 42 | | Prix | 99.7 % | |
| 43 | 43 | | Photos | 92.5 % | |
| 44 | −| Description | 88.6 % | | |
| 44 | +| Description | 88.5 % | | |
| 45 | 45 | | Détails (variantes/attributs) | 100.0 % | |
| 46 | 46 | | — dont avis (rating/review_count) | 3.6 % | |
| 47 | 47 | | — dont poids/dimensions | 0.0 % | |
modified
docs/connecteurs/squarespace.md
+9 −9
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur Squarespace (`squarespace`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -17,27 +17,27 @@ | ||
| 17 | 17 | |
| 18 | 18 | ## Boutiques rattachées |
| 19 | 19 | |
| 20 | −- Registre `data/stores.json` : **128** boutiques | |
| 20 | +- Registre `data/stores.json` : **157** boutiques | |
| 21 | 21 | - En base (table `stores`) : **27** activées, **23** avec produits |
| 22 | 22 | |
| 23 | 23 | **Top 5 par volume :** |
| 24 | 24 | |
| 25 | 25 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 26 | 26 | |---|---|---|---|---| |
| 27 | −| Apéro à zéro | `aperoazero.ca` | 238 | 2026-08-19 01:09 | ok | | |
| 28 | −| Les Mains d'ici | `lesmainsdici.com` | 106 | 2026-08-19 02:42 | ok | | |
| 29 | −| Nos Cabanes S.E.N.C | `noscabanes.com` | 78 | 2026-08-19 03:12 | ok | | |
| 30 | −| Hugo & Clay | `hugoandclay.com` | 42 | 2026-08-19 02:21 | ok | | |
| 31 | −| Distillerie COMONT | `comont.ca` | 39 | 2026-08-19 01:43 | ok | | |
| 27 | +| Apéro à zéro | `aperoazero.ca` | 235 | 2026-08-23 14:49 | ok | | |
| 28 | +| Les Mains d'ici | `lesmainsdici.com` | 106 | 2026-08-23 15:17 | ok | | |
| 29 | +| Nos Cabanes S.E.N.C | `noscabanes.com` | 78 | 2026-08-23 15:38 | ok | | |
| 30 | +| Hugo & Clay | `hugoandclay.com` | 42 | 2026-08-23 15:09 | ok | | |
| 31 | +| Atelier V Cuir | `ateliervcuir.com` | 39 | 2026-08-23 14:50 | ok | | |
| 32 | 32 | |
| 33 | 33 | ## Volumétrie & complétude (BD live) |
| 34 | 34 | |
| 35 | 35 | | Indicateur | Valeur | |
| 36 | 36 | |---|---| |
| 37 | −| Produits actifs | 803 | | |
| 37 | +| Produits actifs | 788 | | |
| 38 | 38 | | Prix | 100.0 % | |
| 39 | 39 | | Photos | 99.6 % | |
| 40 | −| Description | 96.3 % | | |
| 40 | +| Description | 96.2 % | | |
| 41 | 41 | | Détails (variantes/attributs) | 0.0 % | |
| 42 | 42 | | — dont avis (rating/review_count) | 0.0 % | |
| 43 | 43 | | — dont poids/dimensions | 0.0 % | |
added
docs/connecteurs/votresite.md
+65 −0
@@ -0,0 +1,65 @@ | ||
| 1 | +# Connecteur Votresite.ca (Drupal + OpenCart) (`votresite`) | |
| 2 | + | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | + | |
| 5 | +## Mécanique / endpoint | |
| 6 | + | |
| 7 | +- Boutique OpenCart montée sous `/boutique` (parfois `/produits`, `/shop`) : inventaire par `<mount>/sitemap.xml` sinon crawl des catégories `<mount>/fr` (`?limit=100&page=N`), puis fiche par fiche `…/<slug>-p<ID>/` (rendu 100 % serveur, aucune API JSON). | |
| 8 | +- Module : `fabrika/connectors/votresite.py` | |
| 9 | +- Plateformes BD routées ici : `votresite` | |
| 10 | + | |
| 11 | +**En-tête du module :** | |
| 12 | + | |
| 13 | +> Fabri-Ka — Agrégateur de produits québécois | |
| 14 | +> Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 15 | +> connectors/votresite.py : connecteur Votresite.ca (plateforme québécoise). | |
| 16 | +> Les sites Votresite.ca sont des Drupal 8 gérés (thème owebo-votresite) avec | |
| 17 | +> une boutique OpenCart montée dans un sous-répertoire (/boutique/ ou | |
| 18 | +> /produits/, parfois autre). Rendu 100 % serveur, aucune API JSON : | |
| 19 | +> - inventaire : <mount>/sitemap.xml (extension OpenCart, pas toujours | |
| 20 | +> activée) sinon crawl des catégories <mount>/fr + pagination | |
| 21 | +> ?limit=100&page=N ; | |
| 22 | +> - fiche : URL …/<slug>-p<ID>[c<ID>…]/ — prix courant dans <h2>…$</h2>, | |
| 23 | +> prix barré (spécial) dans <span style="text-decoration: line-through">, | |
| 24 | +> « Disponibilité: » / « Modèle: » en <li>, description div#tab-description, | |
| 25 | +> galerie <a class="thumbnail">. Les meta twitter:data1/2 servent de | |
| 26 | +> secours mais affichent le prix RÉGULIER même en solde. | |
| 27 | +> Dédup par ID produit (le même p<ID> apparaît sous plusieurs chemins de | |
| 28 | +> catégorie, ex. -p361c37c45c44). | |
| 29 | + | |
| 30 | +## Boutiques rattachées | |
| 31 | + | |
| 32 | +- Registre `data/stores.json` : **45** boutiques | |
| 33 | +- En base (table `stores`) : **45** activées, **43** avec produits | |
| 34 | + | |
| 35 | +**Top 5 par volume :** | |
| 36 | + | |
| 37 | +| Boutique | Domaine | Produits | Dernier sync | Statut | | |
| 38 | +|---|---|---|---|---| | |
| 39 | +| Bijouterie Simard | `bijouteriesimard.ca` | 488 | 2026-08-23 15:36 | ok | | |
| 40 | +| Zylvery-Bijoux Design | `zylverybijouxdesign.com` | 312 | 2026-08-23 15:36 | ok | | |
| 41 | +| AlpagAdore | `alpagadore.com` | 234 | 2026-08-23 15:35 | ok | | |
| 42 | +| Bourdeau artiste peintre | `bourdeauartistepeintre.com` | 182 | 2026-08-23 15:35 | ok | | |
| 43 | +| Les Moniales de Bethléem - CMAQ | `monasteredebethleem.ca` | 174 | 2026-08-23 15:36 | ok | | |
| 44 | + | |
| 45 | +## Volumétrie & complétude (BD live) | |
| 46 | + | |
| 47 | +| Indicateur | Valeur | | |
| 48 | +|---|---| | |
| 49 | +| Produits actifs | 3 190 | | |
| 50 | +| Prix | 95.5 % | | |
| 51 | +| Photos | 100.0 % | | |
| 52 | +| Description | 100.0 % | | |
| 53 | +| Détails (variantes/attributs) | 100.0 % | | |
| 54 | +| — dont avis (rating/review_count) | 0.0 % | | |
| 55 | +| — dont poids/dimensions | 0.0 % | | |
| 56 | + | |
| 57 | +## Gotchas | |
| 58 | + | |
| 59 | +- **Plateforme québécoise** (scripts.votresite.ca) : vitrine Drupal 8 géré (thème `owebo-votresite`) + boutique OpenCart en sous-répertoire — le montage est détecté via le registre, la page d'accueil, puis `/boutique`/`/produits`. | |
| 60 | +- **Prix : le HTML d'abord, les meta en secours** — en solde, `twitter:data1` affiche le prix RÉGULIER ; le prix courant est le `<h2>…$</h2>` de la fiche et le prix barré le `<span>` `text-decoration: line-through` (→ `compare_at_price`). | |
| 61 | +- **Titre = dernier `<h1>` sans ancre** : le premier `<h1>` est le logo du site (un lien) sur plusieurs thèmes ; `og:title` peut être du bourrage de mots-clés (ex. lemieldabee.ca). | |
| 62 | +- **Dédup par ID produit** : le même `p<ID>` apparaît sous plusieurs chemins de catégorie (`-p361c37c45c44`). | |
| 63 | +- Les URLs d'images OpenCart contiennent espaces/accents bruts (`image/cache/catalog/…`) — encodées avant stockage. | |
| 64 | + | |
| 65 | +Voir aussi : [INDEX](INDEX.md) · [transport Scrapfly](scrapfly-transport.md) · [découverte & registre](decouverte-registre.md). | |
modified
docs/connecteurs/wix.md
+14 −14
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur Wix Stores (`wix`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -18,30 +18,30 @@ | ||
| 18 | 18 | |
| 19 | 19 | ## Boutiques rattachées |
| 20 | 20 | |
| 21 | −- Registre `data/stores.json` : **339** boutiques | |
| 22 | −- En base (table `stores`) : **339** activées, **197** avec produits | |
| 21 | +- Registre `data/stores.json` : **393** boutiques | |
| 22 | +- En base (table `stores`) : **302** activées, **240** avec produits | |
| 23 | 23 | |
| 24 | 24 | **Top 5 par volume :** |
| 25 | 25 | |
| 26 | 26 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 27 | 27 | |---|---|---|---|---| |
| 28 | −| Bijouterie Alarie | `bijouteriealarie.com` | 909 | 2026-08-19 01:19 | ok | | |
| 29 | −| Savonnerie Histoire de Bulles | `histoiredebulles.com` | 514 | 2026-08-19 02:21 | ok | | |
| 30 | −| Petits Fruits St-Louis | `souslesoliviers.ca` | 281 | 2026-08-18 22:09 | ok | | |
| 31 | −| CRÉATIONS GLi - CMAQ | `bijouxgli.com` | 202 | 2026-08-19 01:21 | ok | | |
| 32 | −| Savonnerie Bon Bain | `savonneriebonbain.ca` | 180 | 2026-08-19 03:17 | ok | | |
| 28 | +| Bijouterie Alarie | `bijouteriealarie.com` | 907 | 2026-08-23 14:51 | ok | | |
| 29 | +| Savonnerie Histoire de Bulles | `histoiredebulles.com` | 514 | 2026-08-23 15:09 | ok | | |
| 30 | +| Bidon Rempli inc. | `aubidonrempli.com` | 315 | 2026-08-23 13:52 | ok | | |
| 31 | +| Petits Fruits St-Louis | `souslesoliviers.ca` | 281 | 2026-08-23 13:51 | ok | | |
| 32 | +| Ferme Les Carottés inc. | `fermelescarottes.com` | 230 | 2026-08-23 13:55 | ok | | |
| 33 | 33 | |
| 34 | 34 | ## Volumétrie & complétude (BD live) |
| 35 | 35 | |
| 36 | 36 | | Indicateur | Valeur | |
| 37 | 37 | |---|---| |
| 38 | −| Produits actifs | 7 423 | | |
| 39 | −| Prix | 97.0 % | | |
| 40 | −| Photos | 98.6 % | | |
| 41 | −| Description | 90.1 % | | |
| 42 | −| Détails (variantes/attributs) | 97.9 % | | |
| 38 | +| Produits actifs | 8 924 | | |
| 39 | +| Prix | 97.1 % | | |
| 40 | +| Photos | 98.5 % | | |
| 41 | +| Description | 90.4 % | | |
| 42 | +| Détails (variantes/attributs) | 97.5 % | | |
| 43 | 43 | | — dont avis (rating/review_count) | 0.0 % | |
| 44 | −| — dont poids/dimensions | 12.4 % | | |
| 44 | +| — dont poids/dimensions | 11.1 % | | |
| 45 | 45 | |
| 46 | 46 | ## Gotchas |
| 47 | 47 | |
modified
docs/connecteurs/woocommerce.md
+15 −15
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | # Connecteur WooCommerce (Store API) (`woocommerce`) |
| 2 | 2 | |
| 3 | −*Généré le 2026-08-19 03:40 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 3 | +*Généré le 2026-08-23 15:39 par `scripts/gen_connector_docs.py` — fichier produit automatiquement, ne pas éditer à la main.* | |
| 4 | 4 | |
| 5 | 5 | ## Mécanique / endpoint |
| 6 | 6 | |
@@ -17,30 +17,30 @@ | ||
| 17 | 17 | |
| 18 | 18 | ## Boutiques rattachées |
| 19 | 19 | |
| 20 | −- Registre `data/stores.json` : **1320** boutiques | |
| 21 | −- En base (table `stores`) : **476** activées, **442** avec produits | |
| 20 | +- Registre `data/stores.json` : **1556** boutiques | |
| 21 | +- En base (table `stores`) : **546** activées, **509** avec produits | |
| 22 | 22 | |
| 23 | 23 | **Top 5 par volume :** |
| 24 | 24 | |
| 25 | 25 | | Boutique | Domaine | Produits | Dernier sync | Statut | |
| 26 | 26 | |---|---|---|---|---| |
| 27 | −| Pieces de remorques et accessoires - Acheter québécois | `remorquetrailer.com` | 19 358 | 2026-08-19 03:23 | ok | | |
| 28 | −| Coopérative La Manne - Goûtez-y! | `cooplamanne.com` | 7 216 | 2026-08-19 01:48 | ok | | |
| 29 | −| LilloJEUX | `lillojeux.ca` | 6 590 | 2026-08-19 02:50 | ok | | |
| 30 | −| Létourno | `letourno.com` | 2 552 | 2026-08-19 02:49 | ok | | |
| 31 | −| Fourrures Grenier | `grenierboutique.ca` | 2 345 | 2026-08-19 02:19 | ok | | |
| 27 | +| Pieces de remorques et accessoires - Acheter québécois | `remorquetrailer.com` | 19 372 | 2026-08-23 13:43 | ok | | |
| 28 | +| Coopérative La Manne - Goûtez-y! | `cooplamanne.com` | 7 220 | 2026-08-23 15:03 | ok | | |
| 29 | +| LilloJEUX | `lillojeux.ca` | 6 608 | 2026-08-23 15:22 | ok | | |
| 30 | +| Norseco S.E.C. | `norseco.com` | 4 295 | 2026-08-23 13:57 | ok | | |
| 31 | +| Aliments Merci | `alimentsmerci.com` | 2 829 | 2026-08-23 13:53 | ok | | |
| 32 | 32 | |
| 33 | 33 | ## Volumétrie & complétude (BD live) |
| 34 | 34 | |
| 35 | 35 | | Indicateur | Valeur | |
| 36 | 36 | |---|---| |
| 37 | −| Produits actifs | 74 048 | | |
| 38 | −| Prix | 94.0 % | | |
| 39 | −| Photos | 71.8 % | | |
| 40 | −| Description | 63.6 % | | |
| 41 | −| Détails (variantes/attributs) | 86.6 % | | |
| 42 | −| — dont avis (rating/review_count) | 3.8 % | | |
| 43 | −| — dont poids/dimensions | 37.5 % | | |
| 37 | +| Produits actifs | 92 521 | | |
| 38 | +| Prix | 86.4 % | | |
| 39 | +| Photos | 71.5 % | | |
| 40 | +| Description | 66.6 % | | |
| 41 | +| Détails (variantes/attributs) | 87.8 % | | |
| 42 | +| — dont avis (rating/review_count) | 3.2 % | | |
| 43 | +| — dont poids/dimensions | 31.5 % | | |
| 44 | 44 | |
| 45 | 45 | ## Gotchas |
| 46 | 46 | |
modified
fabrika/connectors/__init__.py
+2 −0
@@ -10,6 +10,7 @@ from .generic import GenericConnector | ||
| 10 | 10 | from .shopify import ShopifyConnector |
| 11 | 11 | from .square import SquareConnector |
| 12 | 12 | from .squarespace import SquarespaceConnector |
| 13 | +from .votresite import VotresiteConnector | |
| 13 | 14 | from .wix import WixConnector |
| 14 | 15 | from .woocommerce import WooCommerceConnector |
| 15 | 16 | |
@@ -20,6 +21,7 @@ PLATFORM_CONNECTORS: dict[str, type[BaseConnector]] = { | ||
| 20 | 21 | "squarespace": SquarespaceConnector, |
| 21 | 22 | "square": SquareConnector, |
| 22 | 23 | "wix": WixConnector, |
| 24 | + "votresite": VotresiteConnector, # Votresite.ca (QC) : Drupal + OpenCart | |
| 23 | 25 | # plateformes à rendu serveur → extraction du balisage produit (JSON-LD…) |
| 24 | 26 | "prestashop": GenericConnector, |
| 25 | 27 | "magento": GenericConnector, |
added
fabrika/connectors/votresite.py
+302 −0
@@ -0,0 +1,302 @@ | ||
| 1 | +# ----------------------------------------------------------------------------- | |
| 2 | +# Fabri-Ka — Agrégateur de produits québécois | |
| 3 | +# Auteur : Simon-Pierre Boucher — contact@spboucher.ai | |
| 4 | +# connectors/votresite.py : connecteur Votresite.ca (plateforme québécoise). | |
| 5 | +# Les sites Votresite.ca sont des Drupal 8 gérés (thème owebo-votresite) avec | |
| 6 | +# une boutique OpenCart montée dans un sous-répertoire (/boutique/ ou | |
| 7 | +# /produits/, parfois autre). Rendu 100 % serveur, aucune API JSON : | |
| 8 | +# - inventaire : <mount>/sitemap.xml (extension OpenCart, pas toujours | |
| 9 | +# activée) sinon crawl des catégories <mount>/fr + pagination | |
| 10 | +# ?limit=100&page=N ; | |
| 11 | +# - fiche : URL …/<slug>-p<ID>[c<ID>…]/ — prix courant dans <h2>…$</h2>, | |
| 12 | +# prix barré (spécial) dans <span style="text-decoration: line-through">, | |
| 13 | +# « Disponibilité: » / « Modèle: » en <li>, description div#tab-description, | |
| 14 | +# galerie <a class="thumbnail">. Les meta twitter:data1/2 servent de | |
| 15 | +# secours mais affichent le prix RÉGULIER même en solde. | |
| 16 | +# Dédup par ID produit (le même p<ID> apparaît sous plusieurs chemins de | |
| 17 | +# catégorie, ex. -p361c37c45c44). | |
| 18 | +# ----------------------------------------------------------------------------- | |
| 19 | +from __future__ import annotations | |
| 20 | + | |
| 21 | +import concurrent.futures as cf | |
| 22 | +import re | |
| 23 | +from html import unescape | |
| 24 | + | |
| 25 | +from ..schema import Product, parse_price | |
| 26 | +from .base import BaseConnector | |
| 27 | + | |
| 28 | +# …/slug-p361/ ou …/slug-p361c37c45/ (produit) ; …/slug-c116c139/ (catégorie) | |
| 29 | +PROD_URL_RE = re.compile(r"/([^/]+)-p(\d+)(?:c\d+)*/?(?:\?.*)?$") | |
| 30 | +CAT_URL_RE = re.compile(r"-c\d+(?:c\d+)*/?$") | |
| 31 | +LOC_RE = re.compile(r"<loc>\s*(?:<!\[CDATA\[)?\s*(.*?)\s*(?:\]\]>)?\s*</loc>", | |
| 32 | + re.I | re.S) | |
| 33 | +HREF_RE = re.compile(r'href="([^"]+)"') | |
| 34 | +SKIP_RE = re.compile(r"(/account|/cart|/checkout|/wishlist|/compare|/login|" | |
| 35 | + r"/register|route=|mailto:|tel:|javascript:)", re.I) | |
| 36 | + | |
| 37 | +# marqueurs OpenCart d'une boutique Votresite valide | |
| 38 | +_OC_MARKERS = ("image/cache", "route=product", 'class="thumbnails"', | |
| 39 | + "list-unstyled") | |
| 40 | + | |
| 41 | +CANDIDATE_MOUNTS = ["/boutique", "/produits"] | |
| 42 | + | |
| 43 | + | |
| 44 | +def _clean(s: str | None) -> str: | |
| 45 | + return unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", s or ""))).strip() | |
| 46 | + | |
| 47 | + | |
| 48 | +def _enc(url: str) -> str: | |
| 49 | + """Les chemins d'images OpenCart contiennent espaces et accents bruts.""" | |
| 50 | + return url.replace(" ", "%20") | |
| 51 | + | |
| 52 | + | |
| 53 | +class VotresiteConnector(BaseConnector): | |
| 54 | + platform = "votresite" | |
| 55 | + request_delay = 0.2 | |
| 56 | + max_products = 2000 | |
| 57 | + max_listing_pages = 250 # garde-fou du crawl catégories | |
| 58 | + | |
| 59 | + # ------------------------------------------------------------------ mount | |
| 60 | + def _try_mount(self, mount: str) -> bool: | |
| 61 | + try: | |
| 62 | + r = self.get(f"{self.base}{mount}/fr") | |
| 63 | + except Exception: | |
| 64 | + return False | |
| 65 | + html = r.text or "" | |
| 66 | + return (r.status_code == 200 | |
| 67 | + and any(m in html for m in _OC_MARKERS) | |
| 68 | + and (PROD_URL_RE.search(html) is not None | |
| 69 | + or re.search(r'-[pc]\d+[c\d]*/"', html) is not None | |
| 70 | + or "-c" in html)) | |
| 71 | + | |
| 72 | + def _discover_mount(self) -> str: | |
| 73 | + ep = (self.store.get("catalog_endpoint") or "").strip().rstrip("/") | |
| 74 | + candidates: list[str] = [] | |
| 75 | + if ep and ep != "__generic__": | |
| 76 | + candidates.append(ep if ep.startswith("/") else f"/{ep}") | |
| 77 | + # page d'accueil Drupal : le lien vers la boutique révèle le montage | |
| 78 | + try: | |
| 79 | + html = self.get(self.base + "/").text | |
| 80 | + for m in re.finditer( | |
| 81 | + r'href="https?://[^"/]+(/[a-z0-9_-]+)(?:/fr)?/?"', html, re.I): | |
| 82 | + p = m.group(1) | |
| 83 | + if re.search(r"boutique|produit|magasin|commander|achat", p, re.I): | |
| 84 | + candidates.append(p) | |
| 85 | + for m in re.finditer( | |
| 86 | + r'href="https?://[^"/]+(/[a-z0-9_-]+)/fr/[^"]*-[pc]\d', html): | |
| 87 | + candidates.append(m.group(1)) | |
| 88 | + except Exception: | |
| 89 | + pass | |
| 90 | + candidates += CANDIDATE_MOUNTS | |
| 91 | + seen: set[str] = set() | |
| 92 | + for c in candidates: | |
| 93 | + c = c.rstrip("/") | |
| 94 | + if not c or c in seen: | |
| 95 | + continue | |
| 96 | + seen.add(c) | |
| 97 | + if self._try_mount(c): | |
| 98 | + return c | |
| 99 | + raise RuntimeError("boutique Votresite (OpenCart) introuvable " | |
| 100 | + f"(montages essayés : {sorted(seen)})") | |
| 101 | + | |
| 102 | + # -------------------------------------------------------------- inventaire | |
| 103 | + def _sitemap_urls(self, mount: str) -> dict[str, str]: | |
| 104 | + """{pid: url produit} depuis <mount>/sitemap.xml (souvent absent).""" | |
| 105 | + out: dict[str, str] = {} | |
| 106 | + try: | |
| 107 | + r = self.get(f"{self.base}{mount}/sitemap.xml") | |
| 108 | + except Exception: | |
| 109 | + return out | |
| 110 | + xml = r.text or "" | |
| 111 | + if r.status_code != 200 or "<urlset" not in xml: | |
| 112 | + return out | |
| 113 | + for loc in LOC_RE.findall(xml): | |
| 114 | + m = PROD_URL_RE.search(loc) | |
| 115 | + if m: | |
| 116 | + out.setdefault(m.group(2), loc) | |
| 117 | + return out | |
| 118 | + | |
| 119 | + def _crawl_urls(self, mount: str) -> dict[str, str]: | |
| 120 | + """Crawl des pages catégories : {pid: url produit}.""" | |
| 121 | + root = f"{self.base}{mount}" | |
| 122 | + prods: dict[str, str] = {} | |
| 123 | + seen: set[str] = set() | |
| 124 | + queue: list[str] = [f"{root}/fr"] | |
| 125 | + fetched = 0 | |
| 126 | + while queue and fetched < self.max_listing_pages: | |
| 127 | + url = queue.pop(0) | |
| 128 | + key = url.rstrip("/") | |
| 129 | + if key in seen: | |
| 130 | + continue | |
| 131 | + seen.add(key) | |
| 132 | + try: | |
| 133 | + html = self.get(url).text or "" | |
| 134 | + except Exception: | |
| 135 | + continue | |
| 136 | + fetched += 1 | |
| 137 | + for href in HREF_RE.findall(html): | |
| 138 | + href = unescape(href).split("#")[0] | |
| 139 | + if not href.startswith(root) or SKIP_RE.search(href): | |
| 140 | + continue | |
| 141 | + pm = PROD_URL_RE.search(href.split("?")[0]) | |
| 142 | + if pm: | |
| 143 | + prods.setdefault(pm.group(2), href.split("?")[0]) | |
| 144 | + continue | |
| 145 | + path = href.split("?")[0] | |
| 146 | + if CAT_URL_RE.search(path): | |
| 147 | + # 100 produits par page de liste (défaut : 15) | |
| 148 | + if path.rstrip("/") + "/?limit=100" not in seen: | |
| 149 | + queue.append(path.rstrip("/") + "/?limit=100") | |
| 150 | + elif "page=" in href and "limit=" in href: | |
| 151 | + queue.append(href) # pagination déjà paramétrée | |
| 152 | + if len(prods) >= self.max_products: | |
| 153 | + break | |
| 154 | + return prods | |
| 155 | + | |
| 156 | + # ------------------------------------------------------------------ fiche | |
| 157 | + def _parse_product(self, pid: str, url: str, html: str) -> Product | None: | |
| 158 | + # le 1er <h1> est souvent le logo du site (un lien) ; le titre du | |
| 159 | + # produit est le dernier <h1> SANS ancre (ex. lemieldabee.ca) | |
| 160 | + title, h1_pos = None, -1 | |
| 161 | + h1s = list(re.finditer(r"<h1[^>]*>(.*?)</h1>", html, re.S)) | |
| 162 | + plain = [m for m in h1s if "<a " not in m.group(1)] | |
| 163 | + chosen = (plain or h1s)[-1] if h1s else None | |
| 164 | + if chosen and plain: | |
| 165 | + title, h1_pos = _clean(chosen.group(1)), chosen.start() | |
| 166 | + if not title: | |
| 167 | + m = re.search(r'<meta[^>]+property="og:title"[^>]+content="([^"]+)"', | |
| 168 | + html) | |
| 169 | + title = _clean(m.group(1)) if m else None | |
| 170 | + if chosen: | |
| 171 | + h1_pos = chosen.start() | |
| 172 | + if not title: | |
| 173 | + return None | |
| 174 | + | |
| 175 | + # zone d'info produit : entre le <h1> et le formulaire d'achat | |
| 176 | + if h1_pos < 0: | |
| 177 | + h1_pos = 0 | |
| 178 | + zone_end = html.find('<div id="product"', h1_pos) | |
| 179 | + zone = html[h1_pos: zone_end if zone_end > h1_pos else h1_pos + 6000] | |
| 180 | + | |
| 181 | + compare = None | |
| 182 | + m = re.search(r"line-through[^>]*>\s*([^<]*\d[^<]*)</", zone) | |
| 183 | + if m: | |
| 184 | + compare = parse_price(m.group(1)) | |
| 185 | + price = None | |
| 186 | + m = re.search(r"<h2[^>]*>\s*([^<]*\d[^<]*\$[^<]*)</h2>", zone) | |
| 187 | + if m: | |
| 188 | + price = parse_price(m.group(1)) | |
| 189 | + if price is None: # secours : meta twitter (prix régulier) | |
| 190 | + m = re.search(r'twitter:data1"\s+content="([^"]+)"', html) | |
| 191 | + if m: | |
| 192 | + price = parse_price(m.group(1)) | |
| 193 | + if compare is not None and price is not None and compare <= price: | |
| 194 | + compare = None | |
| 195 | + | |
| 196 | + available = None | |
| 197 | + m = (re.search(r"Disponibilité\s*:\s*</?[^>]*>?\s*([^<]+)<", zone) | |
| 198 | + or re.search(r'twitter:data2"\s+content="([^"]+)"', html)) | |
| 199 | + dispo = _clean(m.group(1)) if m else "" | |
| 200 | + if dispo: | |
| 201 | + low = dispo.lower() | |
| 202 | + if "rupture" in low or "épuis" in low or "epuis" in low: | |
| 203 | + available = False | |
| 204 | + elif "stock" in low or "commande" in low or "jour" in low: | |
| 205 | + available = True | |
| 206 | + | |
| 207 | + det: dict = {} | |
| 208 | + m = re.search(r"Modèle\s*:\s*([^<]+)<", zone) | |
| 209 | + if m and _clean(m.group(1)): | |
| 210 | + det["model"] = _clean(m.group(1)) | |
| 211 | + if dispo: | |
| 212 | + det["availability_text"] = dispo | |
| 213 | + | |
| 214 | + # options (listes déroulantes OpenCart) | |
| 215 | + opts = [] | |
| 216 | + for sel in re.finditer( | |
| 217 | + r'<label[^>]*control-label[^>]*>(.*?)</label>\s*<select[^>]*' | |
| 218 | + r'name="option\[\d+\]"[^>]*>(.*?)</select>', html, re.S): | |
| 219 | + name = _clean(sel.group(1)) | |
| 220 | + values = [_clean(v) for v in | |
| 221 | + re.findall(r"<option[^>]*>(.*?)</option>", sel.group(2), re.S)] | |
| 222 | + values = [v for v in values if v and "choisir" not in v.lower()] | |
| 223 | + if name and values: | |
| 224 | + opts.append({"name": name, "values": values[:30]}) | |
| 225 | + if opts: | |
| 226 | + det["options"] = opts | |
| 227 | + | |
| 228 | + # description : div#tab-description jusqu'au prochain onglet/bloc | |
| 229 | + desc = "" | |
| 230 | + start = html.find('id="tab-description"') | |
| 231 | + if start != -1: | |
| 232 | + start = html.find(">", start) + 1 | |
| 233 | + cuts = [html.find(marker, start) for marker in | |
| 234 | + ('id="tab-', 'class="related', "<footer", "Produits apparentés")] | |
| 235 | + cuts = [c for c in cuts if c > start] | |
| 236 | + desc = html[start: min(cuts) if cuts else start + 20000] | |
| 237 | + if not _clean(desc): | |
| 238 | + m = (re.search(r'<meta[^>]+property="og:description"[^>]+content="([^"]+)"', html) | |
| 239 | + or re.search(r'<meta[^>]+name="description"[^>]+content="([^"]+)"', html)) | |
| 240 | + desc = m.group(1) if m else "" | |
| 241 | + | |
| 242 | + images: list[str] = [] | |
| 243 | + for m in re.finditer(r'<a[^>]+class="thumbnail"[^>]+href="([^"]+)"', html): | |
| 244 | + u = _enc(unescape(m.group(1))) | |
| 245 | + if u.startswith("http") and u not in images: | |
| 246 | + images.append(u) | |
| 247 | + m = re.search(r'<meta[^>]+property="og:image"[^>]+content="([^"]+)"', html) | |
| 248 | + if m: | |
| 249 | + u = _enc(unescape(m.group(1))) | |
| 250 | + if u.startswith("http") and u not in images: | |
| 251 | + images.append(u) | |
| 252 | + | |
| 253 | + # catégories du fil d'Ariane (sans l'accueil ni le produit lui-même) | |
| 254 | + cats: list[str] = [] | |
| 255 | + m = re.search(r'<ul class="breadcrumb"[^>]*>(.*?)</ul>', html, re.S) | |
| 256 | + if m: | |
| 257 | + entries = re.findall(r"<a[^>]*>(.*?)</a>", m.group(1), re.S) | |
| 258 | + cats = [_clean(e) for e in entries | |
| 259 | + if _clean(e) and "fa-home" not in e and _clean(e) != title] | |
| 260 | + | |
| 261 | + return Product( | |
| 262 | + store_id=self.store_id, | |
| 263 | + external_id=pid, | |
| 264 | + url=url, | |
| 265 | + title=title, | |
| 266 | + description=desc, | |
| 267 | + price=price, | |
| 268 | + price_max=price, | |
| 269 | + compare_at_price=compare, | |
| 270 | + images=images, | |
| 271 | + product_type=cats[-1] if cats else "", | |
| 272 | + tags=cats, | |
| 273 | + available=available, | |
| 274 | + details=det, | |
| 275 | + ) | |
| 276 | + | |
| 277 | + # ------------------------------------------------------------------ fetch | |
| 278 | + def fetch(self) -> list[Product]: | |
| 279 | + mount = self._discover_mount() | |
| 280 | + urls = self._sitemap_urls(mount) | |
| 281 | + if len(urls) < 3: # sitemap absent ou quasi vide -> crawl | |
| 282 | + crawled = self._crawl_urls(mount) | |
| 283 | + for pid, u in crawled.items(): | |
| 284 | + urls.setdefault(pid, u) | |
| 285 | + items = list(urls.items())[: self.max_products] | |
| 286 | + out: list[Product] = [] | |
| 287 | + | |
| 288 | + def work(item: tuple[str, str]) -> Product | None: | |
| 289 | + pid, u = item | |
| 290 | + try: | |
| 291 | + html = self.get(u).text or "" | |
| 292 | + except Exception: | |
| 293 | + return None | |
| 294 | + if len(html) < 500: | |
| 295 | + return None | |
| 296 | + return self._parse_product(pid, u, html) | |
| 297 | + | |
| 298 | + with cf.ThreadPoolExecutor(6) as ex: | |
| 299 | + for rec in ex.map(work, items): | |
| 300 | + if rec: | |
| 301 | + out.append(rec) | |
| 302 | + return out | |
modified
scripts/gen_connector_docs.py
+24 −0
@@ -45,6 +45,7 @@ GROUPS: dict[str, list[str]] = { | ||
| 45 | 45 | "wix": ["wix"], |
| 46 | 46 | "squarespace": ["squarespace"], |
| 47 | 47 | "square": ["square"], |
| 48 | + "votresite": ["votresite"], | |
| 48 | 49 | "generic": ["generic", "prestashop", "magento", "bigcommerce", |
| 49 | 50 | "lightspeed", "snipcart"], |
| 50 | 51 | } |
@@ -102,6 +103,29 @@ FICHES = { | ||
| 102 | 103 | "connectables les boutiques Square jusque-là à 0 produit.", |
| 103 | 104 | "Deux requêtes minimum par boutique (HTML d'accueil + API).", |
| 104 | 105 | ]), |
| 106 | + "votresite": dict( | |
| 107 | + titre="Connecteur Votresite.ca (Drupal + OpenCart)", module="votresite.py", | |
| 108 | + endpoint="Boutique OpenCart montée sous `/boutique` (parfois `/produits`, " | |
| 109 | + "`/shop`) : inventaire par `<mount>/sitemap.xml` sinon crawl des " | |
| 110 | + "catégories `<mount>/fr` (`?limit=100&page=N`), puis fiche par " | |
| 111 | + "fiche `…/<slug>-p<ID>/` (rendu 100 % serveur, aucune API JSON).", | |
| 112 | + gotchas=[ | |
| 113 | + "**Plateforme québécoise** (scripts.votresite.ca) : vitrine Drupal 8 " | |
| 114 | + "géré (thème `owebo-votresite`) + boutique OpenCart en sous-répertoire — " | |
| 115 | + "le montage est détecté via le registre, la page d'accueil, puis " | |
| 116 | + "`/boutique`/`/produits`.", | |
| 117 | + "**Prix : le HTML d'abord, les meta en secours** — en solde, " | |
| 118 | + "`twitter:data1` affiche le prix RÉGULIER ; le prix courant est le " | |
| 119 | + "`<h2>…$</h2>` de la fiche et le prix barré le `<span>` " | |
| 120 | + "`text-decoration: line-through` (→ `compare_at_price`).", | |
| 121 | + "**Titre = dernier `<h1>` sans ancre** : le premier `<h1>` est le " | |
| 122 | + "logo du site (un lien) sur plusieurs thèmes ; `og:title` peut être " | |
| 123 | + "du bourrage de mots-clés (ex. lemieldabee.ca).", | |
| 124 | + "**Dédup par ID produit** : le même `p<ID>` apparaît sous plusieurs " | |
| 125 | + "chemins de catégorie (`-p361c37c45c44`).", | |
| 126 | + "Les URLs d'images OpenCart contiennent espaces/accents bruts " | |
| 127 | + "(`image/cache/catalog/…`) — encodées avant stockage.", | |
| 128 | + ]), | |
| 105 | 129 | "generic": dict( |
| 106 | 130 | titre="Connecteur générique (JSON-LD / microdata / OG)", module="generic.py", |
| 107 | 131 | endpoint="Sitemap → pages produit → extraction du balisage produit " |
| 108 | 132 | |