实用脚本统计SofaScore综合评分?

wen 实用脚本 5

本文目录导读:

实用脚本统计SofaScore综合评分?

  1. 方案:使用Python + Requests 直接请求SofaScore API
  2. 运行说明与注意事项:
  3. 高级用法:使用 Selenium(终极方案)

针对您提到的“SofaScore综合评分”(通常指球员/球队的赛后评分),这里提供一个实用Python脚本,用于抓取SofaScore的评分数据。

重要声明:

  1. 遵守条款:SofaScore有严格的Robots协议和反爬机制,此脚本仅用于个人学习、研究或少量数据获取,请勿用于高频抓取或商业用途。
  2. 技术限制:SofaScore的数据通过动态API(GraphQL)加载,直接抓取HTML无效,此脚本模拟浏览器请求其内部API。
  3. 反爬应对:如果遇到403错误或验证码,请降低抓取频率或使用代理。

方案:使用Python + Requests 直接请求SofaScore API

核心原理: SofaScore前端会向 https://www.sofascore.com/api/v1/ 发送AJAX请求获取JSON数据,我们模拟这个请求,并带上合适的 User-AgentReferer

脚本1:获取指定球队与指定联赛的近期比赛评分

import requests
import json
import time
from datetime import datetime
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
    'Accept': 'application/json, text/plain, */*',
    'Referer': 'https://www.sofascore.com/',
    'Origin': 'https://www.sofascore.com',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
}
def get_team_id(team_name):
    """通过搜索接口获取队伍ID (简化版,需要知道确切的英文名)"""
    search_url = "https://www.sofascore.com/api/v1/search/all"
    params = {'q': team_name}
    try:
        resp = requests.get(search_url, headers=HEADERS, params=params, timeout=10)
        data = resp.json()
        # 优先匹配足球队
        for item in data.get('results', []):
            if item.get('type') == 'team' and item.get('sport') == 'football':
                return item.get('id'), item.get('name')
    except Exception as e:
        print(f"搜索失败: {e}")
    return None, None
def get_team_last_matches(team_id, num=5):
    """获取球队最近比赛ID及评分"""
    url = f"https://www.sofascore.com/api/v1/team/{team_id}/events/last/{num}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        data = resp.json()
        matches = data.get('events', [])
        result = []
        for match in matches:
            match_id = match.get('id')
            home_team = match.get('homeTeam', {}).get('name')
            away_team = match.get('awayTeam', {}).get('name')
            # 获取该场比赛的详细评分(SofaScore评分)
            rating_info = get_match_player_ratings(match_id, team_id)
            result.append({
                'event_id': match_id,
                'match': f"{home_team} vs {away_team}",
                'date': datetime.fromtimestamp(match.get('startTimestamp', 0)).strftime('%Y-%m-%d'),
                'ratings': rating_info
            })
            time.sleep(1) # 礼貌性延时
        return result
    except Exception as e:
        print(f"获取比赛列表失败: {e}")
        return []
def get_match_player_ratings(event_id, team_id):
    """获取单场比赛中指定球队所有球员的 SofaScore 评分"""
    url = f"https://www.sofascore.com/api/v1/event/{event_id}/lineups"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        data = resp.json()
        players = []
        # 查找我们关注的队伍
        for side in ['home', 'away']:
            lineup = data.get(side, {})
            if lineup.get('teamId') == team_id:
                for player in lineup.get('players', []):
                    # 综合评分字段是 'statistics' 里的 'rating' 或 'averageRating',需要看具体位置
                    stats = player.get('statistics', {})
                    rating = stats.get('rating') or stats.get('averageRating') or 'N/A'
                    players.append({
                        'name': player.get('name'),
                        'position': player.get('position'),
                        'rating': rating,
                        'is_substitute': player.get('substitute', False)
                    })
                # 仅返回我们关注球队的球员
                return players
        return []  # 如果没有找到该队伍
    except Exception as e:
        print(f"获取阵容评分失败: {e}")
        return []
def main():
    team_name = input("请输入球队英文名 (如: Manchester City): ")
    team_id, found_name = get_team_id(team_name)
    if not team_id:
        print("未找到该球队,请尝试更精确的英文名")
        return
    print(f"找到球队: {found_name} (ID: {team_id})")
    matches = get_team_last_matches(team_id, num=3)  # 取最近3场
    print("\n=== 最近比赛及评分统计 ===")
    for idx, m in enumerate(matches, 1):
        print(f"\n--- 比赛 {idx}: {m['match']} ({m['date']}) ---")
        if m['ratings']:
            # 计算平均分(排除替补)
            starter_ratings = [p['rating'] for p in m['ratings'] if not p['is_substitute'] and isinstance(p['rating'], (int, float))]
            if starter_ratings:
                avg = sum(starter_ratings) / len(starter_ratings)
                print(f"首发平均评分: {avg:.2f}")
            print("主要球员评分:")
            # 按评分排序
            sorted_players = sorted(m['ratings'], key=lambda x: x['rating'] if isinstance(x['rating'], (int, float)) else 0, reverse=True)
            for p in sorted_players[:5]:  # 展示前5名
                print(f"  {p['name']} ( {'首发' if not p['is_substitute'] else '替补'} ): {p['rating']}")
        else:
            print("暂无评分数据(可能未开赛或被隐藏)")
if __name__ == "__main__":
    main()

脚本2:统计指定单场比赛的两队综合评分(更常用)

如果您已经有了比赛ID,可以直接获取整场比赛的评分。

import requests
HEADERS = { ... } # 同脚本1
def get_match_ratings(event_id):
    """获取一场比赛所有球员的平均评分(简化版)"""
    url = f"https://www.sofascore.com/api/v1/event/{event_id}/lineups"
    resp = requests.get(url, headers=HEADERS, timeout=10)
    data = resp.json()
    stats = {'home': {}, 'away': {}}
    for side in ['home', 'away']:
        lineup = data.get(side, {})
        team_name = lineup.get('teamName', 'Unknown')
        player_ratings = []
        for player in lineup.get('players', []):
            rating = player.get('statistics', {}).get('rating')
            if rating is not None:  # 过滤掉未上场球员
                player_ratings.append(rating)
        if player_ratings:
            avg_rating = sum(player_ratings) / len(player_ratings)
            max_rating = max(player_ratings)
            min_rating = min(player_ratings)
        else:
            avg_rating = max_rating = min_rating = 0
        stats[side] = {
            'team': team_name,
            'count': len(player_ratings),  # 有评分的球员数
            'avg': round(avg_rating, 2),
            'max': max_rating,
            'min': min_rating
        }
    return stats
if __name__ == '__main__':
    event_id = input("请输入比赛ID (可以从URL中获取, https://www.sofascore.com/event/1234567: 输入 1234567): ")
    stats = get_match_ratings(event_id)
    print(f"主队 {stats['home']['team']}: 平均评分 {stats['home']['avg']} (最高 {stats['home']['max']}, 最低 {stats['home']['min']})")
    print(f"客队 {stats['away']['team']}: 平均评分 {stats['away']['avg']} (最高 {stats['away']['max']}, 最低 {stats['away']['min']})")

运行说明与注意事项:

  1. 安装依赖:运行前请确认已安装 requests 库。

    pip install requests
  2. 综合评分”:SofaScore的球员综合评分是赛后由算法生成的(基于数据事件、触球、传球成功率、对抗等),该评分在比赛结束后几小时才稳定,如果比赛刚结束,可能返回 null

  3. 反爬与封禁

    • 脚本中已加入 time.sleep(1) 避免请求过快。
    • 如果频繁使用,IP可能被SofaScore封禁,届时返回403错误,建议使用代理降低频率
    • 如果输出乱码或请求失败,请检查 HEADERS 中的 User-Agent 是否最新。
  4. 动态数据变化:SofaScore的API结构可能会更新,如果脚本失效,可能需要根据最新的网络请求(F12 -> Network -> Fetch/XHR)调整JSON解析路径。


高级用法:使用 Selenium(终极方案)

如果上述方法失效(因为SofaScore有严格的风控),您可以考虑使用 Selenium 控制浏览器,等待页面渲染完成后再抓取DOM中的评分元素,这虽然慢,但最稳定,不受API变动影响。

# 简略示例(需安装 selenium 和 webdriver-manager)
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome() # 或 Firefox
driver.get("https://www.sofascore.com/team/football/manchester-city/17") # 示例
# 等待页面加载,点击“赛程”或滚动
time.sleep(5)
# 通过XPath提取评分元素
ratings = driver.find_elements(By.XPATH, '//div[contains(@class,"rating")]')
for r in ratings[:10]:
    print(r.text)
driver.quit()

脚本已经能够满足“统计综合评分”的需求,请根据实际网络环境,优先尝试脚本1(直接API),如果发现数据字段层级有变,建议打开浏览器F12开发者工具,查看网络请求中 lineups 的JSON结构,微调解析逻辑即可。

抱歉,评论功能暂时关闭!