import time import json from selenium import webdr...

Créé le : 29 novembre 2025

Répondu en utilisant GPT-5.1 Thinking par Chat01

Question

import time
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from bs4 import BeautifulSoup
import pandas as pd
from webdriver_manager.chrome import ChromeDriverManager

class FlashscoreParser:
def init(self, headless=True):
self.setup_driver(headless)

text
def setup_driver(self, headless): """Настройка Chrome драйвера""" chrome_options = Options() if headless: chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") # Исправленная инициализация драйвера service = Service(ChromeDriverManager().install()) self.driver = webdriver.Chrome(service=service, options=chrome_options) self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") def parse_match_stats(self, url): """Парсинг статистики матча""" try: print(f"Загружаем страницу: {url}") self.driver.get(url) # Ждем загрузки основных элементов WebDriverWait(self.driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, '.duelParticipant__home .participant__participantName')) ) WebDriverWait(self.driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, '[data-testid="wcl-statistics"]')) ) # Даем время для полной загрузки time.sleep(3) soup = BeautifulSoup(self.driver.page_source, 'html.parser') # Извлекаем основную информацию о матче match_info = self._parse_match_info(soup) # Извлекаем статистику по секциям stats_data = self._parse_statistics(soup) # Анализируем игру команд analysis = self.analyze_performance(match_info, stats_data) return { 'match_info': match_info, 'statistics': stats_data, 'analysis': analysis } except Exception as e: print(f"Ошибка при парсинге: {e}") # Сохраняем HTML для отладки with open('debug_page.html', 'w', encoding='utf-8') as f: f.write(self.driver.page_source) print("Сохранен debug_page.html для анализа") return None def _parse_match_info(self, soup): """Парсинг основной информации о матче""" match_info = {} try: # Команды home_team_elem = soup.select_one('.duelParticipant__home .participant__participantName') away_team_elem = soup.select_one('.duelParticipant__away .participant__participantName') home_team = home_team_elem.get_text(strip=True) if home_team_elem else 'N/A' away_team = away_team_elem.get_text(strip=True) if away_team_elem else 'N/A' # Счет score_wrapper = soup.find('div', class_='detailScore__wrapper') if score_wrapper: score_spans = score_wrapper.find_all('span') if len(score_spans) >= 3: score = f"{score_spans[0].get_text(strip=True)}-{score_spans[2].get_text(strip=True)}" else: score = score_wrapper.get_text(strip=True) else: score = 'N/A' # Дата и время date_elem = soup.find('div', class_='duelParticipant__startTime') date_time = date_elem.get_text(strip=True) if date_elem else 'N/A' # Турнир breadcrumbs = soup.find('nav', class_='wcl-breadcrumbs_0ZcSd') if breadcrumbs: tournament_elem = breadcrumbs.find_all('li')[-1] tournament = tournament_elem.get_text(strip=True) if tournament_elem else 'N/A' else: tournament = 'N/A' # Статус матча status_elem = soup.find('span', class_='fixedHeaderDuel__detailStatus') status = status_elem.get_text(strip=True) if status_elem else 'Finished' match_info = { 'home_team': home_team, 'away_team': away_team, 'score': score, 'date_time': date_time, 'tournament': tournament, 'status': status } except Exception as e: print(f"Ошибка при парсинге основной информации: {e}") return match_info def _parse_statistics(self, soup): """Парсинг статистических данных""" stats_data = {} try: # Находим все секции со статистикой sections = soup.find_all('div', class_='section') for section in sections: section_title = section.find('div', class_='section__title') if not section_title: continue title = section_title.get_text(strip=True) stats_data[title] = [] # Находим все строки статистики в секции stat_rows = section.find_all('div', attrs={'data-testid': 'wcl-statistics'}) for row in stat_rows: stat_item = self._parse_stat_row(row) if stat_item: stats_data[title].append(stat_item) except Exception as e: print(f"Ошибка при парсинге статистики: {e}") return stats_data def _parse_stat_row(self, row): """Парсинг отдельной строки статистики""" try: # Название показателя category_elem = row.find('div', class_='wcl-category_6sT1J') if not category_elem: return None category = category_elem.get_text(strip=True) # Значения для домашней и гостевой команд home_value_elem = row.find('div', class_='wcl-homeValue_3Q-7P') away_value_elem = row.find('div', class_='wcl-awayValue_Y-QR1') home_value = home_value_elem.get_text(strip=True) if home_value_elem else 'N/A' away_value = away_value_elem.get_text(strip=True) if away_value_elem else 'N/A' return { 'category': category, 'home_value': home_value, 'away_value': away_value } except Exception as e: print(f"Ошибка при парсинге строки статистики: {e}") return None def analyze_performance(self, match_info, stats_data): """Анализ игры команд и создание рейтинговой оценки""" # Извлекаем ключевые статистические данные key_stats = self._extract_key_stats(stats_data) home_team = match_info['home_team'] away_team = match_info['away_team'] # Создаем оценку для каждой команды home_analysis = self._create_team_analysis(home_team, key_stats, is_home=True) away_analysis = self._create_team_analysis(away_team, key_stats, is_home=False) # Сравниваем команды comparison = self._compare_teams(home_analysis, away_analysis) return { 'home_team': home_analysis, 'away_team': away_analysis, 'comparison': comparison, 'overall_verdict': self._generate_overall_verdict(home_analysis, away_analysis, match_info) } def _extract_key_stats(self, stats_data): """Извлечение ключевых статистических данных""" key_stats = {} # Собираем все статистики в один словарь для удобства all_stats = {} for section, stats in stats_data.items(): for stat in stats: all_stats[stat['category']] = { 'home': stat['home_value'], 'away': stat['away_value'] } # Извлекаем числовые значения из строк def parse_value(value_str): try: # Убираем проценты и скобки, берем первое число clean_value = value_str.split('%')[0].split('(')[0].strip() return float(clean_value) except: return 0 # Ключевые показатели для анализа key_metrics = [ 'Expected Goals (xG)', 'Ball Possession', 'Total shots', 'Shots on target', 'Big Chances', 'Passes', 'Tackles', 'Fouls', 'Yellow Cards', 'Goalkeeper Saves' ] for metric in key_metrics: if metric in all_stats: key_stats[metric] = { 'home': parse_value(all_stats[metric]['home']), 'away': parse_value(all_stats[metric]['away']) } return key_stats def _create_team_analysis(self, team_name, key_stats, is_home=True): """Создание анализа для одной команды""" side = 'home' if is_home else 'away' stats = key_stats # Расчет рейтинга атаки (0-10) attack_rating = self._calculate_attack_rating(stats, side) # Расчет рейтинга защиты (0-10) defense_rating = self._calculate_defense_rating(stats, side) # Расчет рейтинга контроля игры (0-10) control_rating = self._calculate_control_rating(stats, side) # Расчет рейтинга эффективности (0-10) efficiency_rating = self._calculate_efficiency_rating(stats, side) # Общий рейтинг (0-10) overall_rating = (attack_rating + defense_rating + control_rating + efficiency_rating) / 4 # Ключевые сильные и слабые стороны strengths = self._identify_strengths(stats, side) weaknesses = self._identify_weaknesses(stats, side) return { 'team_name': team_name, 'ratings': { 'overall': round(overall_rating, 1), 'attack': round(attack_rating, 1), 'defense': round(defense_rating, 1), 'control': round(control_rating, 1), 'efficiency': round(efficiency_rating, 1) }, 'strengths': strengths, 'weaknesses': weaknesses, 'key_insights': self._generate_insights(stats, side) } def _calculate_attack_rating(self, stats, side): """Расчет рейтинга атаки""" rating = 5.0 # Базовая оценка if 'Expected Goals (xG)' in stats: xg = stats['Expected Goals (xG)'][side] rating += min(xg * 2, 3) # xG > 1.5 дает максимальный бонус if 'Shots on target' in stats: shots_on_target = stats['Shots on target'][side] rating += min(shots_on_target * 0.3, 2) # Бонус за удары в створ if 'Big Chances' in stats: big_chances = stats['Big Chances'][side] rating += min(big_chances * 0.5, 2) # Бонус за реальные моменты return min(rating, 10) # Максимум 10 def _calculate_defense_rating(self, stats, side): """Расчет рейтинга защиты""" rating = 5.0 # Базовая оценка if 'Tackles' in stats: tackles = stats['Tackles'][side] rating += min(tackles * 0.2, 2) # Бонус за успешные отборы if 'Fouls' in stats: fouls = stats['Fouls'][side] rating -= min(fouls * 0.1, 2) # Штраф за фолы if 'Yellow Cards' in stats: yellow_cards = stats['Yellow Cards'][side] rating -= min(yellow_cards * 0.3, 2) # Штраф за желтые карточки return max(min(rating, 10), 0) # От 0 до 10 def _calculate_control_rating(self, stats, side): """Расчет рейтинга контроля игры""" rating = 5.0 # Базовая оценка if 'Ball Possession' in stats: possession = stats['Ball Possession'][side] rating += (possession - 50) * 0.08 # Бонус за владение >50% if 'Passes' in stats: pass_accuracy = stats['Passes'][side] rating += (pass_accuracy - 70) * 0.05 # Бонус за точность >70% return min(max(rating, 0), 10) def _calculate_efficiency_rating(self, stats, side): """Расчет рейтинга эффективности""" rating = 5.0 # Эффективность атаки (удары в створ / общее количество ударов) if 'Shots on target' in stats and 'Total shots' in stats: shots_on_target = stats['Shots on target'][side] total_shots = stats['Total shots'][side] if total_shots > 0: efficiency = (shots_on_target / total_shots) * 100 rating += min((efficiency - 30) * 0.1, 3) # Эффективность реализации моментов if 'Big Chances' in stats and 'Expected Goals (xG)' in stats: big_chances = stats['Big Chances'][side] xg = stats['Expected Goals (xG)'][side] if big_chances > 0: conversion_efficiency = (xg / big_chances) * 100 rating += min(conversion_efficiency * 0.05, 2) return min(max(rating, 0), 10) def _identify_strengths(self, stats, side): """Определение сильных сторон команды""" strengths = [] if 'Expected Goals (xG)' in stats and stats['Expected Goals (xG)'][side] > 1.5: strengths.append("Высокая результативность атаки") if 'Shots on target' in stats and stats['Shots on target'][side] >= 5: strengths.append("Много ударов в створ") if 'Big Chances' in stats and stats['Big Chances'][side] >= 3: strengths.append("Создание голевых моментов") if 'Ball Possession' in stats and stats['Ball Possession'][side] > 55: strengths.append("Контроль мяча") if 'Passes' in stats and stats['Passes'][side] > 75: strengths.append("Точные передачи") if 'Tackles' in stats and stats['Tackles'][side] > 70: strengths.append("Эффективные отборы") return strengths def _identify_weaknesses(self, stats, side): """Определение слабых сторон команды""" weaknesses = [] if 'Expected Goals (xG)' in stats and stats['Expected Goals (xG)'][side] < 0.8: weaknesses.append("Слабая атакующая мощь") if 'Shots on target' in stats and stats['Shots on target'][side] < 3: weaknesses.append("Мало опасных моментов") if 'Ball Possession' in stats and stats['Ball Possession'][side] < 40: weaknesses.append("Проблемы с контролем мяча") if 'Fouls' in stats and stats['Fouls'][side] > 15: weaknesses.append("Излишняя агрессия") if 'Yellow Cards' in stats and stats['Yellow Cards'][side] >= 4: weaknesses.append("Проблемы с дисциплиной") return weaknesses def _generate_insights(self, stats, side): """Генерация ключевых инсайтов""" insights = [] if 'Expected Goals (xG)' in stats: xg = stats['Expected Goals (xG)'][side] if xg > 2.0: insights.append(f"Создали моментов на {xg} ожидаемых голов") elif xg < 0.5: insights.append(f"Слабая атака: всего {xg} xG") if 'Big Chances' in stats: bc = stats['Big Chances'][side] if bc >= 3: insights.append(f"Создали {bc} реальных голевых моментов") return insights def _compare_teams(self, home_analysis, away_analysis): """Сравнение команд""" comparison = { 'dominance': '', 'key_advantages': [] } home_rating = home_analysis['ratings']['overall'] away_rating = away_analysis['ratings']['overall'] if home_rating - away_rating >= 2: comparison['dominance'] = f"{home_analysis['team_name']} доминировала в матче" elif away_rating - home_rating >= 2: comparison['dominance'] = f"{away_analysis['team_name']} доминировала в матче" else: comparison['dominance'] = "Балансированный матч" # Определение ключевых преимуществ if home_analysis['ratings']['attack'] > away_analysis['ratings']['attack'] + 1: comparison['key_advantages'].append(f"{home_analysis['team_name']} - более опасная атака") elif away_analysis['ratings']['attack'] > home_analysis['ratings']['attack'] + 1: comparison['key_advantages'].append(f"{away_analysis['team_name']} - более опасная атака") if home_analysis['ratings']['defense'] > away_analysis['ratings']['defense'] + 1: comparison['key_advantages'].append(f"{home_analysis['team_name']} - надежнее в защите") elif away_analysis['ratings']['defense'] > home_analysis['ratings']['defense'] + 1: comparison['key_advantages'].append(f"{away_analysis['team_name']} - надежнее в защите") return comparison def _generate_overall_verdict(self, home_analysis, away_analysis, match_info): """Генерация общего вердикта по матчу""" home_rating = home_analysis['ratings']['overall'] away_rating = away_analysis['ratings']['overall'] verdicts = [ "Очень односторонний матч", "Явное доминирование одной команды", "Уравновешенная игра с небольшим преимуществом", "Близкая и напряженная борьба", "Ничья по игровому наполнению" ] rating_diff = abs(home_rating - away_rating) if rating_diff >= 3: verdict = verdicts[0] elif rating_diff >= 2: verdict = verdicts[1] elif rating_diff >= 1: verdict = verdicts[2] elif rating_diff >= 0.5: verdict = verdicts[3] else: verdict = verdicts[4] return { 'verdict': verdict, 'entertainment_rating': round((home_rating + away_rating) / 2, 1), 'recommendation': "Рекомендуем к просмотру" if (home_rating + away_rating) / 2 >= 6 else "Обычный матч" } def save_to_json(self, data, filename): """Сохранение данных в JSON файл""" with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"Данные сохранены в {filename}") def save_to_excel(self, data, filename): """Сохранение данных в Excel файл""" try: # Создаем DataFrame для статистики rows = [] for section, stats in data['statistics'].items(): for stat in stats: rows.append({ 'Section': section, 'Category': stat['category'], 'Home_Value': stat['home_value'], 'Away_Value': stat['away_value'] }) df_stats = pd.DataFrame(rows) # Создаем DataFrame для основной информации df_info = pd.DataFrame([data['match_info']]) # Создаем DataFrame для анализа analysis_data = [] for team in ['home_team', 'away_team']: team_data = data['analysis'][team] analysis_data.append({ 'Team': team_data['team_name'], 'Overall_Rating': team_data['ratings']['overall'], 'Attack_Rating': team_data['ratings']['attack'], 'Defense_Rating': team_data['ratings']['defense'], 'Control_Rating': team_data['ratings']['control'], 'Efficiency_Rating': team_data['ratings']['efficiency'], 'Strengths': ', '.join(team_data['strengths']), 'Weaknesses': ', '.join(team_data['weaknesses']) }) df_analysis = pd.DataFrame(analysis_data) # Сохраняем в Excel с несколькими листами with pd.ExcelWriter(filename, engine='openpyxl') as writer: df_info.to_excel(writer, sheet_name='Match_Info', index=False) df_stats.to_excel(writer, sheet_name='Statistics', index=False) df_analysis.to_excel(writer, sheet_name='Analysis', index=False) print(f"Данные сохранены в {filename}") except Exception as e: print(f"Ошибка при сохранении в Excel: {e}") def close(self): """Закрытие драйвера""" if self.driver: self.driver.quit() def print_analysis(self, data): """Красивый вывод анализа в консоль""" analysis = data['analysis'] match_info = data['match_info'] print("\n" + "="*80) print("🏆 ДЕТАЛЬНЫЙ АНАЛИЗ МАТЧА") print("="*80) print(f"\n📊 МАТЧ: {match_info['home_team']} {match_info['score']} {match_info['away_team']}") print(f"📅 {match_info['date_time']} | {match_info['tournament']}") # Анализ домашней команды home = analysis['home_team'] print(f"\n{'='*40}") print(f"🏠 {home['team_name']} - ОЦЕНКА: {home['ratings']['overall']}/10") print(f"{'='*40}") print(f"⚽ Атака: {home['ratings']['attack']}/10 | 🛡️ Защита: {home['ratings']['defense']}/10") print(f"🎯 Контроль: {home['ratings']['control']}/10 | 📈 Эффективность: {home['ratings']['efficiency']}/10") if home['strengths']: print(f"\n✅ СИЛЬНЫЕ СТОРОНЫ:") for strength in home['strengths']: print(f" • {strength}") if home['weaknesses']: print(f"\n❌ СЛАБЫЕ СТОРОНЫ:") for weakness in home['weaknesses']: print(f" • {weakness}") # Анализ гостевой команды away = analysis['away_team'] print(f"\n{'='*40}") print(f"✈️ {away['team_name']} - ОЦЕНКА: {away['ratings']['overall']}/10") print(f"{'='*40}") print(f"⚽ Атака: {away['ratings']['attack']}/10 | 🛡️ Защита: {away['ratings']['defense']}/10") print(f"🎯 Контроль: {away['ratings']['control']}/10 | 📈 Эффективность: {away['ratings']['efficiency']}/10") if away['strengths']: print(f"\n✅ СИЛЬНЫЕ СТОРОНЫ:") for strength in away['strengths']: print(f" • {strength}") if away['weaknesses']: print(f"\n❌ СЛАБЫЕ СТОРОНЫ:") for weakness in away['weaknesses']: print(f" • {weakness}") # Сравнение и общий вердикт comparison = analysis['comparison'] verdict = analysis['overall_verdict'] print(f"\n{'='*40}") print("📊 СРАВНИТЕЛЬНЫЙ АНАЛИЗ") print(f"{'='*40}") print(f"📈 {comparison['dominance']}") if comparison['key_advantages']: print(f"\n🎯 КЛЮЧЕВЫЕ ПРЕИМУЩЕСТВА:") for advantage in comparison['key_advantages']: print(f" • {advantage}") print(f"\n{'='*40}") print("🎭 ОБЩИЙ ВЕРДИКТ") print(f"{'='*40}") print(f"📋 {verdict['verdict']}") print(f"⭐ Рейтинг зрелищности: {verdict['entertainment_rating']}/10") print(f"💡 {verdict['recommendation']}")

Пример использования

if name == "main":
# URL матча
match_url = "https://www.flashscore.com/match/football/fc-andorra-O6ucWgAa/gijon-69w4Rb2d/summary/stats/0/?mid=2mq2Zo8T"

text
# Создаем парсер parser = FlashscoreParser(headless=False) # headless=False для отладки try: # Парсим данные match_data = parser.parse_match_stats(match_url) if match_data: # Выводим красивый анализ parser.print_analysis(match_data) # Сохраняем в файлы parser.save_to_json(match_data, 'match_stats.json') parser.save_to_excel(match_data, 'match_stats.xlsx') except Exception as e: print(f"Ошибка: {e}") finally: parser.close() этот код парсит статистические данные с сайта и производит общую оценку игры по командам: ДЕТАЛЬНЫЙ АНАЛИЗ МАТЧА

================================================================================

📊 МАТЧ: Gijon 1-1 Andorra
📅 29.11.2025 04:30 | LaLiga2 - Round 16

========================================
🏠 Gijon - ОЦЕНКА: 7.1/10

⚽ Атака: 10/10 | 🛡️ Защита: 5.0/10
🎯 Контроль: 4.9/10 | 📈 Эффективность: 8.3/10

✅ СИЛЬНЫЕ СТОРОНЫ:
• Высокая результативность атаки
• Много ударов в створ
• Создание голевых моментов
• Точные передачи

========================================
✈️ Andorra - ОЦЕНКА: 6.5/10

⚽ Атака: 8.5/10 | 🛡️ Защита: 5.3/10
🎯 Контроль: 6.1/10 | 📈 Эффективность: 6.0/10

✅ СИЛЬНЫЕ СТОРОНЫ:
• Контроль мяча
• Точные передачи

❌ СЛАБЫЕ СТОРОНЫ:
• Мало опасных моментов

========================================
📊 СРАВНИТЕЛЬНЫЙ АНАЛИЗ

📈 Балансированный матч

🎯 КЛЮЧЕВЫЕ ПРЕИМУЩЕСТВА:
• Gijon - более опасная атака

========================================
🎭 ОБЩИЙ ВЕРДИКТ

📋 Близкая и напряженная борьба
⭐ Рейтинг зрелищности: 6.8/10
💡 Рекомендуем к просмотру
Данные сохранены в match_stats.json
Данные сохранены в match_stats.xlsx я хочу чтобы статистичские данные тоже присутствовоали в итоговом ответе и хочу более детальный анализ по командам, исправь код и вышли мне полный исправленный код, можешь сам придумать новую схему расчета баллов каждой команде для оценки игры

Réflexion

code = r''' import time import json from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from bs4 import BeautifulSoup import pandas as pd from webdriver_manager.chrome import ChromeDriverManager

class FlashscoreParser: def init(self, headless=True): self.setup_driver(headless)

text
def setup_driver(self, headless): """Настройка Chrome драйвера""" chrome_options = Options() if headless: chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") # Исправленная инициализация драйвера service = Service(ChromeDriverManager().install()) self.driver = webdriver.Chrome(service=service, options=chrome_options) self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") def parse_match_stats(self, url): """Парсинг статистики матча""" try: print(f"Загружаем страницу: {url}") self.driver.get(url) # Ждем загрузки основных элементов

Thought for 2m 21s

Réponse

Вот полный переписанный код с:

  • новым, более продуманным алгоритмом расчёта рейтингов;
  • более детальным текстовым анализом по каждой команде;
  • выводом подробной статистики (по всем секциям и показателям) в конце отчёта.
python
import time import json from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from bs4 import BeautifulSoup import pandas as pd from webdriver_manager.chrome import ChromeDriverManager class FlashscoreParser: def __init__(self, headless=True): self.setup_driver(headless) def setup_driver(self, headless): """Настройка Chrome драйвера""" chrome_options = Options() if headless: chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument( "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ) # Инициализация драйвера service = Service(ChromeDriverManager().install()) self.driver = webdriver.Chrome(service=service, options=chrome_options) self.driver.execute_script( "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})" ) def parse_match_stats(self, url): """Парсинг статистики матча""" try: print(f"Загружаем страницу: {url}") self.driver.get(url) # Ждем загрузки основных элементов WebDriverWait(self.driver, 15).until( EC.presence_of_element_located( (By.CSS_SELECTOR, '.duelParticipant__home .participant__participantName') ) ) WebDriverWait(self.driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, '[data-testid="wcl-statistics"]')) ) # Даем время для полной загрузки time.sleep(3) soup = BeautifulSoup(self.driver.page_source, 'html.parser') # Основная информация о матче match_info = self._parse_match_info(soup) # Статистика по секциям stats_data = self._parse_statistics(soup) # Анализ игры команд analysis = self.analyze_performance(match_info, stats_data) return { 'match_info': match_info, 'statistics': stats_data, 'analysis': analysis } except Exception as e: print(f"Ошибка при парсинге: {e}") # Сохраняем HTML для отладки with open('debug_page.html', 'w', encoding='utf-8') as f: f.write(self.driver.page_source) print("Сохранен debug_page.html для анализа") return None def _parse_match_info(self, soup): """Парсинг основной информации о матче""" match_info = {} try: # Команды home_team_elem = soup.select_one('.duelParticipant__home .participant__participantName') away_team_elem = soup.select_one('.duelParticipant__away .participant__participantName') home_team = home_team_elem.get_text(strip=True) if home_team_elem else 'N/A' away_team = away_team_elem.get_text(strip=True) if away_team_elem else 'N/A' # Счет score_wrapper = soup.find('div', class_='detailScore__wrapper') if score_wrapper: score_spans = score_wrapper.find_all('span') if len(score_spans) >= 3: score = f"{score_spans[0].get_text(strip=True)}-{score_spans[2].get_text(strip=True)}" else: score = score_wrapper.get_text(strip=True) else: score = 'N/A' # Дата и время date_elem = soup.find('div', class_='duelParticipant__startTime') date_time = date_elem.get_text(strip=True) if date_elem else 'N/A' # Турнир breadcrumbs = soup.find('nav', class_='wcl-breadcrumbs_0ZcSd') if breadcrumbs: tournament_elem = breadcrumbs.find_all('li')[-1] tournament = tournament_elem.get_text(strip=True) if tournament_elem else 'N/A' else: tournament = 'N/A' # Статус матча status_elem = soup.find('span', class_='fixedHeaderDuel__detailStatus') status = status_elem.get_text(strip=True) if status_elem else 'Finished' match_info = { 'home_team': home_team, 'away_team': away_team, 'score': score, 'date_time': date_time, 'tournament': tournament, 'status': status } except Exception as e: print(f"Ошибка при парсинге основной информации: {e}") return match_info def _parse_statistics(self, soup): """Парсинг статистических данных""" stats_data = {} try: # Находим все секции со статистикой sections = soup.find_all('div', class_='section') for section in sections: section_title = section.find('div', class_='section__title') if not section_title: continue title = section_title.get_text(strip=True) stats_data[title] = [] # Находим все строки статистики в секции stat_rows = section.find_all('div', attrs={'data-testid': 'wcl-statistics'}) for row in stat_rows: stat_item = self._parse_stat_row(row) if stat_item: stats_data[title].append(stat_item) except Exception as e: print(f"Ошибка при парсинге статистики: {e}") return stats_data def _parse_stat_row(self, row): """Парсинг отдельной строки статистики""" try: # Название показателя category_elem = row.find('div', class_='wcl-category_6sT1J') if not category_elem: return None category = category_elem.get_text(strip=True) # Значения для домашней и гостевой команд home_value_elem = row.find('div', class_='wcl-homeValue_3Q-7P') away_value_elem = row.find('div', class_='wcl-awayValue_Y-QR1') home_value = home_value_elem.get_text(strip=True) if home_value_elem else 'N/A' away_value = away_value_elem.get_text(strip=True) if away_value_elem else 'N/A' return { 'category': category, 'home_value': home_value, 'away_value': away_value } except Exception as e: print(f"Ошибка при парсинге строки статистики: {e}") return None def analyze_performance(self, match_info, stats_data): """Анализ игры команд и создание рейтинговой оценки""" # Извлекаем ключевые статистические данные key_stats = self._extract_key_stats(stats_data) home_team = match_info.get('home_team', 'Home') away_team = match_info.get('away_team', 'Away') # Пытаемся извлечь количество забитых голов из счета home_goals = 0 away_goals = 0 score = match_info.get('score', '') try: if score and '-' in score: parts = score.replace(' ', '').split('-') if len(parts) == 2: home_goals = int(parts[0]) away_goals = int(parts[1]) except ValueError: pass # Создаем оценку для каждой команды home_analysis = self._create_team_analysis( home_team, key_stats, is_home=True, goals=home_goals ) away_analysis = self._create_team_analysis( away_team, key_stats, is_home=False, goals=away_goals ) # Сравниваем команды comparison = self._compare_teams(home_analysis, away_analysis) return { 'home_team': home_analysis, 'away_team': away_analysis, 'comparison': comparison, 'overall_verdict': self._generate_overall_verdict(home_analysis, away_analysis, match_info), 'key_stats': key_stats } def _extract_key_stats(self, stats_data): """Извлечение ключевых статистических данных в числовом виде""" key_stats = {} # Собираем все статистики в один словарь по названию показателя all_stats = {} for section, stats in stats_data.items(): for stat in stats: all_stats[stat['category']] = { 'home': stat['home_value'], 'away': stat['away_value'] } # Извлекаем числовые значения из строк def parse_value(value_str): try: # Убираем проценты и скобки, берем первое число clean_value = value_str.split('%')[0].split('(')[0].strip() return float(clean_value.replace(',', '.')) except Exception: return 0.0 # Ключевые показатели для анализа (если есть на странице) key_metrics = [ 'Expected Goals (xG)', 'Ball Possession', 'Total shots', 'Shots on target', 'Shots off target', 'Blocked shots', 'Big Chances', 'Corners', 'Offsides', 'Passes', 'Attacks', 'Dangerous attacks', 'Tackles', 'Fouls', 'Yellow Cards', 'Red Cards', 'Goalkeeper Saves' ] for metric in key_metrics: if metric in all_stats: key_stats[metric] = { 'home': parse_value(all_stats[metric]['home']), 'away': parse_value(all_stats[metric]['away']) } return key_stats def _create_team_analysis(self, team_name, key_stats, is_home=True, goals=0): """Создание детального анализа для одной команды""" side = 'home' if is_home else 'away' opponent_side = 'away' if is_home else 'home' stats = key_stats # Расчет рейтингов (0-10) attack_rating = self._calculate_attack_rating(stats, side, goals) defense_rating = self._calculate_defense_rating(stats, side, opponent_side) control_rating = self._calculate_control_rating(stats, side) efficiency_rating = self._calculate_efficiency_rating(stats, side, goals) # Общий рейтинг (0-10) с весами по компонентам overall_rating = ( attack_rating * 0.30 + defense_rating * 0.30 + control_rating * 0.25 + efficiency_rating * 0.15 ) # Ключевые сильные и слабые стороны strengths = self._identify_strengths(stats, side, opponent_side) weaknesses = self._identify_weaknesses(stats, side, opponent_side) # Детальные выводы с учетом рейтингов key_insights = self._generate_insights( stats, side, opponent_side, { 'attack': attack_rating, 'defense': defense_rating, 'control': control_rating, 'efficiency': efficiency_rating }, goals ) return { 'team_name': team_name, 'ratings': { 'overall': round(overall_rating, 1), 'attack': round(attack_rating, 1), 'defense': round(defense_rating, 1), 'control': round(control_rating, 1), 'efficiency': round(efficiency_rating, 1) }, 'strengths': strengths, 'weaknesses': weaknesses, 'key_insights': key_insights } def _calculate_attack_rating(self, stats, side, goals=0): """Новая схема расчета рейтинга атаки (0-10)""" score = 0.0 xg = stats.get('Expected Goals (xG)', {}).get(side) shots_on_target = stats.get('Shots on target', {}).get(side) total_shots = stats.get('Total shots', {}).get(side) big_chances = stats.get('Big Chances', {}).get(side) # xG: до 3 xG -> до 6 баллов if isinstance(xg, (int, float)): score += min(max(xg, 0.0), 3.0) * 2.0 # Удары в створ: до 8 -> до 4 баллов if isinstance(shots_on_target, (int, float)): score += min(max(shots_on_target, 0.0), 8.0) * 0.5 # Большие моменты: до 5 -> до 3.5 баллов if isinstance(big_chances, (int, float)): score += min(max(big_chances, 0.0), 5.0) * 0.7 # Реальные голы как бонус за завершение атак: до 4 -> до 4.8 баллов if isinstance(goals, (int, float)): score += min(max(goals, 0.0), 4.0) * 1.2 # Нормируем на 0-10 rating = score / 1.8 # ~18 баллов -> 10 return max(0.0, min(rating, 10.0)) def _calculate_defense_rating(self, stats, side, opponent_side): """Расчет рейтинга защиты (0-10). Чем меньше моментов у соперника, тем выше рейтинг.""" score = 0.0 xg_against = stats.get('Expected Goals (xG)', {}).get(opponent_side) shots_on_target_against = stats.get('Shots on target', {}).get(opponent_side) big_chances_against = stats.get('Big Chances', {}).get(opponent_side) tackles = stats.get('Tackles', {}).get(side) fouls = stats.get('Fouls', {}).get(side) yellow_cards = stats.get('Yellow Cards', {}).get(side) # xG соперника: чем меньше, тем лучше (порог ~2.5) if isinstance(xg_against, (int, float)): score += max(0.0, (2.5 - xg_against)) * 3.0 # Удары соперника в створ: чем меньше, тем лучше if isinstance(shots_on_target_against, (int, float)): score += max(0.0, (7.0 - shots_on_target_against)) * 0.6 # Большие моменты соперника if isinstance(big_chances_against, (int, float)): score += max(0.0, (4.0 - big_chances_against)) * 0.8 # Отборы в плюс if isinstance(tackles, (int, float)): score += min(max(tackles, 0.0), 40.0) * 0.1 # Фолы и карточки в минус if isinstance(fouls, (int, float)): score -= min(max(fouls, 0.0), 20.0) * 0.1 if isinstance(yellow_cards, (int, float)): score -= min(max(yellow_cards, 0.0), 5.0) * 0.5 rating = max(0.0, min(score, 10.0)) return rating def _calculate_control_rating(self, stats, side): """Расчет рейтинга контроля игры (0-10)""" score = 0.0 possession = stats.get('Ball Possession', {}).get(side) passes = stats.get('Passes', {}).get(side) total_shots = stats.get('Total shots', {}).get(side) # Владение мячом: учитываем все, что выше 40% if isinstance(possession, (int, float)): score += max(0.0, possession - 40.0) * 0.3 # Передачи: предполагаем %, если значение > 100, режем до 100 if isinstance(passes, (int, float)): pass_metric = min(max(passes, 0.0), 100.0) score += max(0.0, pass_metric - 70.0) * 0.2 # Общее количество ударов как индикатор территориального контроля if isinstance(total_shots, (int, float)): score += min(max(total_shots, 0.0), 20.0) * 0.2 rating = max(0.0, min(score, 10.0)) return rating def _calculate_efficiency_rating(self, stats, side, goals=0): """Расчет рейтинга эффективности реализации (0-10)""" rating = 5.0 # базовая оценка shots_on_target = stats.get('Shots on target', {}).get(side) total_shots = stats.get('Total shots', {}).get(side) xg = stats.get('Expected Goals (xG)', {}).get(side) # Эффективность попаданий в створ if isinstance(shots_on_target, (int, float)) and isinstance(total_shots, (int, float)) and total_shots > 0: ratio = shots_on_target / total_shots * 100.0 rating += (ratio - 40.0) * 0.15 # 40% = средний уровень # Соотношение голов и xG: забили больше, чем ожидалось -> плюс if isinstance(xg, (int, float)) and xg > 0 and isinstance(goals, (int, float)): diff = goals - xg rating += diff * 1.0 # +/- 1 балл за каждый "перебор" xG return max(0.0, min(rating, 10.0)) def _identify_strengths(self, stats, side, opponent_side): """Определение сильных сторон команды""" strengths = [] xg = stats.get('Expected Goals (xG)', {}).get(side, 0.0) xg_against = stats.get('Expected Goals (xG)', {}).get(opponent_side, 0.0) shots_on_target = stats.get('Shots on target', {}).get(side, 0.0) total_shots = stats.get('Total shots', {}).get(side, 0.0) big_chances = stats.get('Big Chances', {}).get(side, 0.0) possession = stats.get('Ball Possession', {}).get(side, 0.0) passes = stats.get('Passes', {}).get(side, 0.0) tackles = stats.get('Tackles', {}).get(side, 0.0) tackles_opp = stats.get('Tackles', {}).get(opponent_side, 0.0) fouls = stats.get('Fouls', {}).get(side, 0.0) if xg >= 1.5: strengths.append("Создавали много опасных моментов (высокий xG)") if shots_on_target >= 6: strengths.append("Часто доводили атаки до ударов в створ") if big_chances >= 3: strengths.append("Создали большое количество голевых моментов") if possession >= 55: strengths.append("Доминировали во владении мячом") if passes >= 82: strengths.append("Высокая точность передач") if tackles >= 18 and tackles >= tackles_opp: strengths.append("Хорошо работали в отборе мяча") if xg_against <= 0.9: strengths.append("Почти не позволяли сопернику создавать моменты") if total_shots >= 14: strengths.append("Постоянно нагружали оборону соперника ударами") if fouls <= 10: strengths.append("Сохраняли дисциплину и не фолили лишний раз") return strengths def _identify_weaknesses(self, stats, side, opponent_side): """Определение слабых сторон команды""" weaknesses = [] xg = stats.get('Expected Goals (xG)', {}).get(side, 0.0) xg_against = stats.get('Expected Goals (xG)', {}).get(opponent_side, 0.0) shots_on_target = stats.get('Shots on target', {}).get(side, 0.0) total_shots = stats.get('Total shots', {}).get(side, 0.0) big_chances = stats.get('Big Chances', {}).get(side, 0.0) possession = stats.get('Ball Possession', {}).get(side, 0.0) passes = stats.get('Passes', {}).get(side, 0.0) tackles = stats.get('Tackles', {}).get(side, 0.0) fouls = stats.get('Fouls', {}).get(side, 0.0) yellow_cards = stats.get('Yellow Cards', {}).get(side, 0.0) if xg < 0.8: weaknesses.append("Слабо выглядели в атаке (низкий xG)") if shots_on_target <= 3 and total_shots <= 9: weaknesses.append("Практически не создавали опасных ударов") if big_chances <= 1: weaknesses.append("Редко доводили атаки до по-настоящему голевых моментов") if possession <= 40: weaknesses.append("Проиграли борьбу за мяч и инициативу") if passes and passes < 78: weaknesses.append("Невысокая точность передач, много потерь мяча") if tackles <= 10: weaknesses.append("Недостаточная плотность в единоборствах") if xg_against >= 1.8: weaknesses.append("Слишком много позволяли сопернику в своей штрафной") if fouls >= 15: weaknesses.append("Излишняя агрессия и фолы") if yellow_cards >= 4: weaknesses.append("Проблемы с дисциплиной (много желтых карточек)") return weaknesses def _generate_insights(self, stats, side, opponent_side, ratings, goals): """Генерация ключевых инсайтов по команде""" insights = [] attack_rating = ratings['attack'] defense_rating = ratings['defense'] control_rating = ratings['control'] efficiency_rating = ratings['efficiency'] xg = stats.get('Expected Goals (xG)', {}).get(side, 0.0) xg_against = stats.get('Expected Goals (xG)', {}).get(opponent_side, 0.0) shots_on_target = stats.get('Shots on target', {}).get(side, 0.0) total_shots = stats.get('Total shots', {}).get(side, 0.0) possession = stats.get('Ball Possession', {}).get(side, 0.0) # Блок по атаке if attack_rating >= 8: insights.append( f"Атакующая игра была одной из сильных сторон: xG = {xg:.2f}, " f"ударов в створ = {int(shots_on_target)}." ) elif attack_rating <= 4: insights.append( "В атаке команда выглядела бледно и редко доводила свои подходы до " "действительно опасных моментов." ) # Блок по обороне if defense_rating >= 8: insights.append( f"Оборона сработала надежно: допустили всего {xg_against:.2f} xG соперника." ) elif defense_rating <= 4: insights.append( "В защите команда часто теряла позиции и позволяла сопернику создавать " "слишком много моментов." ) # Блок по контролю игры if control_rating >= 7.5: insights.append( f"Команда хорошо контролировала ход матча (владение около {possession:.1f}% " f"и постоянное давление ударами, всего {int(total_shots)} ударов)." ) elif control_rating <= 4: insights.append( "Контроль матча в основном был у соперника: команда чаще оборонялась, " "а не диктовала условия игры." ) # Блок по эффективности if efficiency_rating >= 7.5: insights.append("Хорошо использовали свои моменты и достаточно эффективно распоряжались ударами.") elif efficiency_rating <= 4: insights.append("Реализация моментов подвела: от атакующих действий ожидалось большего.") # Дополнительный комментарий по голам if goals >= 3: insights.append("Большое количество забитых голов подтверждает высокий атакующий потенциал в этом матче.") elif goals == 0 and xg >= 1.0: insights.append( "При достойном качестве моментов забить так и не удалось — подвела заключительная стадия атак." ) return insights def _compare_teams(self, home_analysis, away_analysis): """Сравнение команд""" comparison = { 'dominance': '', 'key_advantages': [] } home_rating = home_analysis['ratings']['overall'] away_rating = away_analysis['ratings']['overall'] if home_rating - away_rating >= 2: comparison['dominance'] = f"{home_analysis['team_name']} доминировала в матче" elif away_rating - home_rating >= 2: comparison['dominance'] = f"{away_analysis['team_name']} доминировала в матче" else: comparison['dominance'] = "Балансированный матч" # Определение ключевых преимуществ if home_analysis['ratings']['attack'] > away_analysis['ratings']['attack'] + 1: comparison['key_advantages'].append(f"{home_analysis['team_name']} - более опасная атака") elif away_analysis['ratings']['attack'] > home_analysis['ratings']['attack'] + 1: comparison['key_advantages'].append(f"{away_analysis['team_name']} - более опасная атака") if home_analysis['ratings']['defense'] > away_analysis['ratings']['defense'] + 1: comparison['key_advantages'].append(f"{home_analysis['team_name']} - надежнее в защите") elif away_analysis['ratings']['defense'] > home_analysis['ratings']['defense'] + 1: comparison['key_advantages'].append(f"{away_analysis['team_name']} - надежнее в защите") if home_analysis['ratings']['control'] > away_analysis['ratings']['control'] + 1: comparison['key_advantages'].append(f"{home_analysis['team_name']} - лучше контролировала игру") elif away_analysis['ratings']['control'] > home_analysis['ratings']['control'] + 1: comparison['key_advantages'].append(f"{away_analysis['team_name']} - лучше контролировала игру") return comparison def _generate_overall_verdict(self, home_analysis, away_analysis, match_info): """Генерация общего вердикта по матчу""" home_rating = home_analysis['ratings']['overall'] away_rating = away_analysis['ratings']['overall'] verdicts = [ "Очень односторонний матч", "Явное доминирование одной команды", "Уравновешенная игра с небольшим преимуществом", "Близкая и напряженная борьба", "Ничья по игровому наполнению" ] rating_diff = abs(home_rating - away_rating) if rating_diff >= 3: verdict = verdicts[0] elif rating_diff >= 2: verdict = verdicts[1] elif rating_diff >= 1: verdict = verdicts[2] elif rating_diff >= 0.5: verdict = verdicts[3] else: verdict = verdicts[4] return { 'verdict': verdict, 'entertainment_rating': round((home_rating + away_rating) / 2, 1), 'recommendation': "Рекомендуем к просмотру" if (home_rating + away_rating) / 2 >= 6 else "Обычный матч" } def save_to_json(self, data, filename): """Сохранение данных в JSON файл""" with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"Данные сохранены в {filename}") def save_to_excel(self, data, filename): """Сохранение данных в Excel файл""" try: # Создаем DataFrame для статистики rows = [] for section, stats in data['statistics'].items(): for stat in stats: rows.append({ 'Section': section, 'Category': stat['category'], 'Home_Value': stat['home_value'], 'Away_Value': stat['away_value'] }) df_stats = pd.DataFrame(rows) # Создаем DataFrame для основной информации df_info = pd.DataFrame([data['match_info']]) # Создаем DataFrame для анализа analysis_data = [] for team in ['home_team', 'away_team']: team_data = data['analysis'][team] analysis_data.append({ 'Team': team_data['team_name'], 'Overall_Rating': team_data['ratings']['overall'], 'Attack_Rating': team_data['ratings']['attack'], 'Defense_Rating': team_data['ratings']['defense'], 'Control_Rating': team_data['ratings']['control'], 'Efficiency_Rating': team_data['ratings']['efficiency'], 'Strengths': ', '.join(team_data['strengths']), 'Weaknesses': ', '.join(team_data['weaknesses']), 'Key_Insights': ' | '.join(team_data['key_insights']) }) df_analysis = pd.DataFrame(analysis_data) # Сохраняем в Excel с несколькими листами with pd.ExcelWriter(filename, engine='openpyxl') as writer: df_info.to_excel(writer, sheet_name='Match_Info', index=False) df_stats.to_excel(writer, sheet_name='Statistics', index=False) df_analysis.to_excel(writer, sheet_name='Analysis', index=False) print(f"Данные сохранены в {filename}") except Exception as e: print(f"Ошибка при сохранении в Excel: {e}") def close(self): """Закрытие драйвера""" if self.driver: self.driver.quit() def print_analysis(self, data): """Красивый вывод анализа в консоль вместе с подробной статистикой""" analysis = data['analysis'] match_info = data['match_info'] stats = data.get('statistics', {}) print("\n" + "=" * 80) print("🏆 ДЕТАЛЬНЫЙ АНАЛИЗ МАТЧА") print("=" * 80) print(f"\n📊 МАТЧ: {match_info['home_team']} {match_info['score']} {match_info['away_team']}") print(f"📅 {match_info['date_time']} | {match_info['tournament']}") # Анализ домашней команды home = analysis['home_team'] print(f"\n{'=' * 40}") print(f"🏠 {home['team_name']} - ОЦЕНКА: {home['ratings']['overall']}/10") print(f"{'=' * 40}") print(f"⚽ Атака: {home['ratings']['attack']}/10 | 🛡️ Защита: {home['ratings']['defense']}/10") print(f"🎯 Контроль: {home['ratings']['control']}/10 | 📈 Эффективность: {home['ratings']['efficiency']}/10") if home['strengths']: print(f"\n✅ СИЛЬНЫЕ СТОРОНЫ:") for strength in home['strengths']: print(f" • {strength}") if home['weaknesses']: print(f"\n❌ СЛАБЫЕ СТОРОНЫ:") for weakness in home['weaknesses']: print(f" • {weakness}") if home['key_insights']: print(f"\n🔍 КЛЮЧЕВЫЕ ВЫВОДЫ:") for insight in home['key_insights']: print(f" • {insight}") # Анализ гостевой команды away = analysis['away_team'] print(f"\n{'=' * 40}") print(f"✈️ {away['team_name']} - ОЦЕНКА: {away['ratings']['overall']}/10") print(f"{'=' * 40}") print(f"⚽ Атака: {away['ratings']['attack']}/10 | 🛡️ Защита: {away['ratings']['defense']}/10") print(f"🎯 Контроль: {away['ratings']['control']}/10 | 📈 Эффективность: {away['ratings']['efficiency']}/10") if away['strengths']: print(f"\n✅ СИЛЬНЫЕ СТОРОНЫ:") for strength in away['strengths']: print(f" • {strength}") if away['weaknesses']: print(f"\n❌ СЛАБЫЕ СТОРОНЫ:") for weakness in away['weaknesses']: print(f" • {weakness}") if away['key_insights']: print(f"\n🔍 КЛЮЧЕВЫЕ ВЫВОДЫ:") for insight in away['key_insights']: print(f" • {insight}") # Сравнение и общий вердикт comparison = analysis['comparison'] verdict = analysis['overall_verdict'] print(f"\n{'=' * 40}") print("📊 СРАВНИТЕЛЬНЫЙ АНАЛИЗ") print(f"{'=' * 40}") print(f"📈 {comparison['dominance']}") if comparison['key_advantages']: print(f"\n🎯 КЛЮЧЕВЫЕ ПРЕИМУЩЕСТВА:") for advantage in comparison['key_advantages']: print(f" • {advantage}") print(f"\n{'=' * 40}") print("🎭 ОБЩИЙ ВЕРДИКТ") print(f"{'=' * 40}") print(f"📋 {verdict['verdict']}") print(f"⭐ Рейтинг зрелищности: {verdict['entertainment_rating']}/10") print(f"💡 {verdict['recommendation']}") # Подробная статистика print(f"\n{'=' * 40}") print("📊 ПОДРОБНАЯ СТАТИСТИКА МАТЧА") print(f"{'=' * 40}") if not stats: print("Статистика недоступна.") return for section, items in stats.items(): print(f"\n📂 {section}") for item in items: print(f" • {item['category']}: {item['home_value']} - {item['away_value']}") # Пример использования if __name__ == "__main__": # URL матча match_url = "https://www.flashscore.com/match/football/fc-andorra-O6ucWgAa/gijon-69w4Rb2d/summary/stats/0/?mid=2mq2Zo8T" # Создаем парсер parser = FlashscoreParser(headless=False) # headless=False для отладки try: # Парсим данные match_data = parser.parse_match_stats(match_url) if match_data: # Выводим красивый анализ parser.print_analysis(match_data) # Сохраняем в файлы parser.save_to_json(match_data, 'match_stats.json') parser.save_to_excel(match_data, 'match_stats.xlsx') except Exception as e: print(f"Ошибка: {e}") finally: parser.close()

Что изменилось по сравнению с твоим вариантом:

  1. Новый скоринг:

    • Атака учитывает xG, удары в створ, big chances и реальные голы, затем нормируется к шкале 0–10.
    • Защита учитывает xG соперника, его удары в створ, big chances, твои отборы, фолы и жёлтые.
    • Контроль игры строится на владении, пасах и общем количестве ударов.
    • Эффективность смотрит на % ударов в створ и соотношение голов к xG.
  2. Более детальный анализ по командам:

    • Расширены функции *_identify_strengths и *_identify_weaknesses — они теперь учитывают и свои, и соперничьи метрики.
    • key_insights теперь генерирует несколько содержательных текстовых выводов по каждой команде (атака, защита, контроль, реализация, голы).
  3. Статистика в итоговом выводе:

    • В print_analysis добавлен раздел "📊 ПОДРОБНАЯ СТАТИСТИКА МАТЧА", где по каждому разделу (Section) выводятся все показатели вида:
      text
      • Shots on target: 7 - 3
    • То есть весь блок data['statistics'] теперь отражается в консольном отчёте.
  4. Excel:

    • В лист Analysis добавлен столбец Key_Insights, чтобы в файле были не только числовые рейтинги, но и текстовое резюме по каждой команде.

Если хочешь, дальше можно:

  • подправить веса рейтингов (например, сделать оборону важнее атаки для определённых лиг);
  • отдельно считать рейтинг дисциплины, вратаря и т.п.;
  • фильтровать/группировать выводимую статистику (например, показывать только топ-10 ключевых метрик).

Partager cette Q&R