Skip to content

Commit 67f751f

Browse files
authored
Merge pull request #109 from RustyRory/feat/103-scraping-matchs
feat(scraping): Fixes #103 - Matches
2 parents a5e139c + a792d77 commit 67f751f

2 files changed

Lines changed: 39 additions & 37 deletions

File tree

app/backend/src/models/Team.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,9 @@ const teamSchema = new mongoose.Schema(
5858
},
5959
],
6060
photo: {
61-
type: String, // URL Nextcloud
61+
type: String, // URL
6262
trim: true,
6363
},
64-
isArchived: {
65-
type: Boolean,
66-
default: false,
67-
},
6864
},
6965
{
7066
timestamps: true,

app/backend/src/scripts/scraping.js

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,17 @@ import * as cheerio from 'cheerio';
77
import Match from '../models/Match.js';
88
import Standing from '../models/Standing.js';
99

10-
// 🔹 Constantes
11-
const CHAMPIONSHIP_ID = '6985bd859903c98a455ca98d'; // ton championnat
10+
// 🔹 Club fixe
1211
const CLUB_TEAM_NAME = "AS SAINT-BARTHELEMY D'ANJOU V.B.";
13-
const FFVB_URL =
14-
'https://www.ffvbbeach.org/ffvbapp/resu/vbspo_calendrier.php?saison=2025%2F2026&codent=ABCCS&poule=3MB&division=&tour=&calend=COMPLET&x=15&y=15';
1512

16-
// 🔹 Utilitaire pour parser date FR -> ISO
13+
// 🔹 Utilitaires
1714
function parseDateFR(dateStr, timeStr) {
1815
const [day, month, year] = dateStr.split('/').map(Number);
1916
const fullYear = year < 100 ? 2000 + year : year;
2017
const [hours, minutes] = timeStr.split(':').map(Number);
2118
return new Date(fullYear, month - 1, day, hours, minutes).toISOString();
2219
}
2320

24-
// 🔹 Transforme string sets en array d'objets pour Mongo
2521
function parseSetsDetail(setsStr) {
2622
if (!setsStr) return [];
2723
return setsStr.split(',').map((s, idx) => {
@@ -30,15 +26,19 @@ function parseSetsDetail(setsStr) {
3026
});
3127
}
3228

33-
// 🔹 Fonction principale
34-
async function scrapeFFVB() {
29+
// 🔹 Scraping d’un championnat
30+
async function scrapeChampionship(champ) {
3531
try {
36-
console.log('📡 Lancement de Puppeteer...');
32+
console.log(`\n🏐 ${champ.name || 'Championnat inconnu'}`);
33+
console.log(`🔗 ${champ.federationUrl}`);
34+
if (!champ.federationUrl) {
35+
console.warn(`⚠️ Championnat ${champ.name || champ._id} n’a pas d’URL, skipping...`);
36+
return;
37+
}
38+
3739
const browser = await puppeteer.launch({ headless: true });
3840
const page = await browser.newPage();
39-
40-
console.log('📊 Récupération du HTML...');
41-
await page.goto(FFVB_URL, { waitUntil: 'networkidle2' });
41+
await page.goto(champ.federationUrl, { waitUntil: 'networkidle2' });
4242
const html = await page.content();
4343
await browser.close();
4444

@@ -55,26 +55,28 @@ async function scrapeFFVB() {
5555
const tds = $(tr).find('td');
5656
if (tds.length < 6) return;
5757

58-
const homeTeam = $(tds[3]).text().trim();
59-
const awayTeam = $(tds[5]).text().trim();
58+
const row = [];
59+
tds.each((j, td) => row.push($(td).text().trim()));
60+
61+
const homeTeam = row[3];
62+
const awayTeam = row[5];
6063
if (!homeTeam || !awayTeam) return;
6164

6265
if (homeTeam === CLUB_TEAM_NAME || awayTeam === CLUB_TEAM_NAME) {
6366
const homeAway = homeTeam === CLUB_TEAM_NAME ? 'home' : 'away';
64-
const scoreFor = homeAway === 'home' ? parseInt($(tds[6]).text()) || 0 : parseInt($(tds[7]).text()) || 0;
65-
const scoreAgainst = homeAway === 'home' ? parseInt($(tds[7]).text()) || 0 : parseInt($(tds[6]).text()) || 0;
66-
const dateISO = parseDateFR($(tds[1]).text().trim(), $(tds[2]).text().trim());
67-
const setsDetail = parseSetsDetail($(tds[8]).text().trim());
67+
const scoreFor = homeAway === 'home' ? parseInt(row[6]) || 0 : parseInt(row[7]) || 0;
68+
const scoreAgainst = homeAway === 'home' ? parseInt(row[7]) || 0 : parseInt(row[6]) || 0;
69+
const dateISO = parseDateFR(row[1], row[2]);
70+
const setsDetail = parseSetsDetail(row[8]);
6871

69-
// 🔹 Déterminer le status correctement
7072
const matchDate = new Date(dateISO);
7173
let status = 'scheduled';
7274
if (matchDate <= now && (scoreFor > 0 || scoreAgainst > 0)) {
7375
status = 'played';
7476
}
7577

7678
matches.push({
77-
championshipId: CHAMPIONSHIP_ID,
79+
championshipId: champ._id,
7880
opponentName: homeAway === 'home' ? awayTeam : homeTeam,
7981
date: dateISO,
8082
homeAway,
@@ -86,16 +88,16 @@ async function scrapeFFVB() {
8688
}
8789
});
8890

89-
console.log('💾 Mise à jour des matchs dans MongoDB...');
91+
console.log(`🧪 ${matches.length} matchs détectés`);
92+
9093
for (const m of matches) {
9194
const existing = await Match.findOne({
92-
championshipId: CHAMPIONSHIP_ID,
95+
championshipId: champ._id,
9396
opponentName: m.opponentName,
9497
date: m.date,
9598
});
9699

97100
if (existing) {
98-
// 🔹 Vérifier si on a de nouvelles infos avant mise à jour
99101
const needsUpdate =
100102
existing.status !== m.status ||
101103
existing.scoreFor !== m.scoreFor ||
@@ -111,7 +113,6 @@ async function scrapeFFVB() {
111113
console.log(`➕ Match créé : ${m.opponentName} (${m.date})`);
112114
}
113115
}
114-
console.log(`🎉 ${matches.length} matchs analysés.`);
115116

116117
// -----------------------------
117118
// 🔹 Scraping des standings
@@ -139,7 +140,7 @@ async function scrapeFFVB() {
139140
const coefficientPoints = parseFloat($(tds[18]).text()) || 0;
140141

141142
standings.push({
142-
championshipId: CHAMPIONSHIP_ID,
143+
championshipId: champ._id,
143144
teamName,
144145
rank,
145146
played,
@@ -156,22 +157,27 @@ async function scrapeFFVB() {
156157
});
157158

158159
console.log('💾 Mise à jour des standings dans MongoDB...');
159-
let updatedCount = 0;
160160
for (const s of standings) {
161-
await Standing.findOneAndUpdate({ championshipId: CHAMPIONSHIP_ID, teamName: s.teamName }, s, { upsert: true });
162-
updatedCount++;
161+
await Standing.findOneAndUpdate({ championshipId: champ._id, teamName: s.teamName }, s, { upsert: true });
163162
}
164-
165-
console.log(`🎉 ${updatedCount} équipes mises à jour ou créées.`);
163+
console.log(`🎉 ${standings.length} équipes mises à jour ou créées`);
166164
} catch (err) {
167165
console.error('❌ Erreur pendant le scraping :', err);
168166
}
169167
}
170168

171169
// -----------------------------
172-
// 🔹 Connexion MongoDB via .env
170+
// 🔹 Connexion MongoDB et scraping de tous les championnats
173171
// -----------------------------
174172
mongoose
175173
.connect(process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/saintbarthvolley')
176-
.then(() => scrapeFFVB())
174+
.then(async () => {
175+
console.log('✅ MongoDB connecté');
176+
const championships = await mongoose.connection.db.collection('championships').find().toArray();
177+
178+
console.log(`🚀 ${championships.length} championnats à scraper`);
179+
for (const champ of championships) {
180+
await scrapeChampionship(champ);
181+
}
182+
})
177183
.finally(() => mongoose.disconnect());

0 commit comments

Comments
 (0)