根据php项目,Whoscored评分对比?

wen PHP项目 1

PHP 项目:WhoScored 评分对比

你想做一个 WhoScored 评分对比的 PHP 项目,我帮你梳理一个完整的实现方案。

根据php项目,Whoscored评分对比?

需求理解

从 WhoScored 抓取球员/球队评分数据,做对比展示,核心模块:

  1. 数据采集(抓取 WhoScored 评分)
  2. 数据存储(MySQL 缓存评分数据)
  3. 对比展示(多球员/多球队评分图表对比)

技术栈建议

用途 推荐
后端 PHP 8.x + Composer
HTTP 抓取 GuzzleHttp
HTML 解析 symfony/dom-crawler(WhoScored 数据靠 JS 渲染,最好找 API)
数据库 MySQL / SQLite
前端图表 Chart.js / ECharts
框架 Laravel 或纯 PHP(视规模)

WhoScored 数据获取要点

WhoScored 反爬较强,官方页面数据由 JS 动态加载。推荐走其内部 API:

https://www.whoscored.com/StatisticsFeed/1/GetPlayerStatistics
  ?category=summary
  &subcategory=all
  &statsAccumulationType=0
  &isCurrent=true
  &isMinApp=true
  &page=1
  &includeZero=false
  &sortBy=Rating
  &field=Overall
  &teamId=
  &playerId=
  &stageId=
  &tournamentOptions=
  &stageId=

关键点:

  • 必须带 正确的 Referer 和 User-Agent,否则返回 403
  • 请求频率要低,建议加延时 + 缓存
  • 部分接口需要 Cookie(首次访问首页获取)

核心代码示例

抓取球员评分(Guzzle)

<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
class WhoScoredScraper
{
    private Client $client;
    public function __construct()
    {
        $this->client = new Client([
            'base_uri' => 'https://www.whoscored.com/',
            'timeout'  => 20,
            'headers'  => [
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                    . 'AppleWebKit/537.36 (KHTML, like Gecko) '
                    . 'Chrome/120.0 Safari/537.36',
                'Referer'    => 'https://www.whoscored.com/',
                'Accept'     => 'application/json, text/javascript, */*; q=0.01',
                'X-Requested-With' => 'XMLHttpRequest',
            ],
        ]);
    }
    public function getPlayerStats(int $page = 1, string $sortBy = 'Rating'): array
    {
        $res = $this->client->get('StatisticsFeed/1/GetPlayerStatistics', [
            'query' => [
                'category'              => 'summary',
                'subcategory'           => 'all',
                'statsAccumulationType' => 0,
                'isCurrent'             => 'true',
                'isMinApp'              => 'true',
                'page'                  => $page,
                'includeZero'           => 'false',
                'sortBy'                => $sortBy,
                'field'                 => 'Overall',
            ],
        ]);
        return json_decode($res->getBody()->getContents(), true)['playerTableStats'] ?? [];
    }
}

数据库表结构

CREATE TABLE players (
    id           INT PRIMARY KEY AUTO_INCREMENT,
    ws_player_id INT UNIQUE,
    name         VARCHAR(100),
    team         VARCHAR(100),
    position     VARCHAR(20),
    updated_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE ratings (
    id           INT PRIMARY KEY AUTO_INCREMENT,
    player_id    INT,
    rating       DECIMAL(3,2),
    minutes      INT,
    goals        INT,
    assists      INT,
    season       VARCHAR(20),
    recorded_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (player_id) REFERENCES players(id),
    INDEX (player_id, season)
);

评分对比控制器

class CompareController
{
    public function compare(array $playerIds): array
    {
        $in = implode(',', array_map('intval', $playerIds));
        $sql = "SELECT p.name, p.team, r.rating, r.goals, r.assists
                FROM players p
                JOIN ratings r ON r.player_id = p.id
                WHERE p.id IN ($in) AND r.season = '2024'
                ORDER BY r.rating DESC";
        return $this->db->query($sql)->fetchAll();
    }
}

前端对比图(Chart.js)

<canvas id="cmp"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
fetch('/api/compare?ids=1,2,3')
  .then(r => r.json())
  .then(data => {
    new Chart(document.getElementById('cmp'), {
      type: 'radar',
      data: {
        labels: ['评分', '进球', '助攻', '关键传球', '抢断'],
        datasets: data.map(d => ({
          label: d.name,
          data: [d.rating * 10, d.goals, d.assists, d.key_passes, d.tackles],
          fill: true,
        }))
      }
    });
  });
</script>

项目结构建议

whoscored-compare/
├── composer.json
├── config/
│   └── db.php
├── src/
│   ├── Scraper/WhoScoredScraper.php
│   ├── Repository/PlayerRepository.php
│   └── Service/CompareService.php
├── public/
│   ├── index.php
│   └── api/compare.php
├── storage/
│   └── cache/            # 抓取缓存,避免频繁请求
├── cron/
│   └── fetch_ratings.php # 定时抓取
└── views/
    └── compare.php

关键注意事项

  1. 反爬

    • 每次请求间隔 ≥ 2 秒
    • 失败重试 + 随机 UA
    • 数据落库做缓存(评分每日变,抓一次即可)
    • 有条件用代理池
  2. 合规

    • 仅做个人学习/分析用途
    • 遵守 robots.txt 与 ToS,勿商用
    • 高频抓取可能封 IP
  3. 数据准确性

    • 评分口径:WhoScored 的 rating 是 0–10,保留两位小数
    • 注意区分赛季、赛事、位置(前锋 vs 后卫评分不可直接比)
    • 出场时间门槛(isMinApp=true 排除太少出场)
  4. 对比维度建议

    • 同位置对比才有意义(前锋 vs 前锋)
    • 雷达图维度用 同位置分位数 标准化,避免进球数碾压防守数据

后续可扩展

  • ⭐ 主客场评分拆分
  • ⭐ 时间序列(近 5 场评分趋势)
  • ⭐ 同位置分位数排名
  • ⭐ 爬虫队列化(Laravel Horizon / Redis)
  • ⭐ 导出 Excel / PDF 对比报告

需要我进一步提供具体哪一块的完整可运行代码?

  • 带缓存的完整抓取类
  • 雷达图标准化对比算法
  • Laravel 版本的完整实现
  • 反爬绕过方案

告诉我你的项目规模(脚本级 / 小型站 / 完整系统),我给你更贴合的方案。

上一篇根据php项目,金靴争夺会影响比赛吗?

下一篇当前分类已是最新一篇

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

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝