← كل الأدلة

روزنامة الموسم والسباق القادم والنتائج

ابنِ روزنامة سباقات مع عدّاد تنازلي «للسباق القادم» وصفحة نتائج لكل جولة، باستخدام Python.

8 دقائق قراءة

يحتاج كل تطبيق سباقات إلى روزنامة. يبني هذا الدليل ثلاثة أشياء من نقاط نهاية السباقات:

  1. روزنامة الموسم الكاملة بترتيب الجولات.
  2. السباق القادم، لعدّاد تنازلي أو إشعار فوري.
  3. النتائج المصنّفة لجولة منتهية.

الروزنامة

يعيد GET /races/seasons/{year} جميع جولات موسم لفئة واحدة:

{
  "round_number": 12,
  "name": "Qatar Airways Grand Prix of Great Britain",
  "circuit_name": "Silverstone Circuit, Silverstone",
  "country": "United Kingdom",
  "flag": "🇬🇧",
  "category": "MOTOGP",
  "race_date": "2026-08-09",
  "season_year": 2026
}

لا تُعاد الجولات مرتبة، لذا رتّبها بحسب round_number:

import os
from datetime import date

import requests

HOST = "motogp-api-championship-data-statistics.p.rapidapi.com"
HEADERS = {"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"], "X-RapidAPI-Host": HOST}


def get(path: str, **params):
    res = requests.get(f"https://{HOST}{path}", headers=HEADERS, params=params, timeout=10)
    res.raise_for_status()
    return res.json()["data"]


def calendar(year: int, category: str = "MOTOGP") -> list[dict]:
    races = get(f"/races/seasons/{year}", category=category)
    return sorted(races, key=lambda r: r["round_number"])


for race in calendar(2026):
    print(f"R{race['round_number']:>2}  {race['race_date']}  {race['flag']}  {race['name']}")
...
R 6  2026-05-17  🇪🇸  Monster Energy Grand Prix of Catalunya
...
R12  2026-08-09  🇬🇧  Qatar Airways Grand Prix of Great Britain
...

السباق القادم

race_date تاريخ بصيغة ISO (YYYY-MM-DD)، لذا يمكن ترتيبه ومقارنته كسلسلة نصية أو تحليله بـ date.fromisoformat:

def next_race(races: list[dict], today: date) -> dict | None:
    upcoming = [r for r in races if date.fromisoformat(r["race_date"]) >= today]
    return upcoming[0] if upcoming else None


race = next_race(calendar(2026), date.today())
if race:
    days = (date.fromisoformat(race["race_date"]) - date.today()).days
    print(f"Next: {race['name']} at {race['circuit_name']} in {days} days")
else:
    print("Season finished")

نتائج جولة

بعد إقامة الجولة، تتوفر نتائجها بحسب الموسم والجولة:

def results(year: int, round_number: int, category: str = "MOTOGP") -> list[dict]:
    rows = get(f"/races/seasons/{year}/round/{round_number}/results", category=category)
    return sorted(rows, key=lambda r: r["position"])


for row in results(2026, 1)[:3]:
    print(f"P{row['position']}  {row['rider_name']:<22} {row['team_name']:<32} +{row['points']} pts")
P1  Marco Bezzecchi        Aprilia Racing                   +25 pts
P2  ...
P3  Raúl Fernández         SuperFile Trackhouse MotoGP Team +16 pts

لكل صف حقل status: القيمة FINISHED للسائقين المصنّفين، وقيم مثل DNF أو DNS لغيرهم. اعرض من لم يُنهِ السباق أسفل السائقين المصنّفين.

الاستطلاع الدوري بعد السباق

تُضاف النتائج بعد كل نهاية أسبوع سباق. إذا كنت ترسل إشعارات «صدرت النتائج»، فاستطلع نقطة نهاية النتائج لآخر جولة كل 30 إلى 60 دقيقة بعد تاريخ السباق بدلًا من كل بضع ثوانٍ: القائمة الفارغة تعني «ليس بعد»، والاستطلاع البطيء يُبقيك ضمن حصتك بسهولة. وتعيد الجولة غير الموجودة في الروزنامة الحالة 404.

def results_ready(year: int, round_number: int) -> bool:
    return len(results(year, round_number)) > 0

Moto2 وMoto3

مرّر category="MOTO2" أو category="MOTO3" إلى أي من الدوال أعلاه. تتبع أرقام الجولات والتواريخ الروزنامة نفسها، لذا فإن عرض الأسبوع المجمّع هو دمج على round_number.

الدليل التالي → احتساب نقاط دوري MotoGP الفانتازي