شرح بسيط لـ Python Requests APIs (مع مخططات وكود حقيقي)

Python Requests APIs: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات عملية، مقتطفات من دورة مكونة من 30 درسًا.

شرح بسيط لـ Python Requests APIs (مع مخططات وكود حقيقي)

دليل مباشر إلى الهدف: Python Requests APIs مفكك مع مخططات وأمثلة عملية وأوامر مجربة. كل شيء من دورة منظمة من 10 فصول — إليك أفضلها.

tl;dr
  • مقدمة وتثبيت
  • أساسيات HTTP
  • استخدام requests
  • المصادقة
  • أنماط متقدمة
~$ cat ./parcours.md # Python Requests APIs — 10 فصول
01
المقدمة والتثبيت
→ ما هي واجهة برمجة التطبيقات REST ؟→ تثبيت requests و httpx+ 1 دروس أخرى
02
أساسيات HTTP
→ طرق HTTP→ رموز الحالة HTTP+ 1 دروس أخرى
03
استخدام requests
→ requests.get و post كاملين→ JSON والتسلسل+ 2 دروس أخرى
04
المصادقة
→ مفتاح API في الهيدر أو الاستعلام→ Basic Auth و Bearer Token+ 1 دروس أخرى
05
أنماط متقدمة
→ التصفح→ تحديد المعدل وإعادة المحاولة الذكية+ 1 دروس أخرى
06
غير متزامن
→ لماذا httpx async→ asyncio + httpx بالتوازي+ 1 دروس أخرى
07
واجهات برمجة التطبيقات العامة المفيدة
→ GitHub API - المستودعات والمشكلات→ OpenWeather و NewsAPI+ 1 دروس أخرى
08
Webhooks والبث
→ استقبال webhooks→ Server-Sent Events (SSE)+ 1 دروس أخرى
🏁
المشروع النهائي (+ 2 فصول في الطريق)
→ تعود بمشروع ملموس وقابل للعرض

CLI وجدولة cron

مشروع نهائي • argparse • cron • تصدير

NOTEالهدف — إنهاء المشروع: واجهة CLI كاملة، تصدير JSON/CSV وجدولة تلقائية عبر cron.

CLI باستخدام argparse

output
# app/cli.py
import argparse, asyncio, json, sqlite3, sys
from . import aggregator, config

def cmd_fetch(args):
    inserted = asyncio.run(aggregator.run_once())
    print(f"Nouveaux articles : {inserted}")

def cmd_list(args):
    conn = sqlite3.connect(config.DB_PATH)
    conn.row_factory = sqlite3.Row
    
    query = "SELECT * FROM articles WHERE 1=1"
    params = []
    if args.source:
        query += " AND source = ?"
        params.append(args.source)
    if args.search:
        query += " AND (title LIKE ? OR summary LIKE ?)"
        params.extend([f"%{args.search}%"] * 2)
    query += f" ORDER BY published_at DESC LIMIT {args.limit}"
    
    for row in conn.execute(query, params):
        print(f"[{row['source']}] {row['published_at'][:10]}")
        print(f"  {row['title']}")
        print(f"  -> {row['url']}\n")

def cmd_export(args):
    conn = sqlite3.connect(config.DB_PATH)
    conn.row_factory = sqlite3.Row
    rows = [dict(r) for r in conn.execute("SELECT * FROM articles")]
    
    if args.format == "json":
        with open(args.output, "w", encoding="utf-8") as f:
            json.dump(rows, f, ensure_ascii=False, indent=2)
    elif args.format == "csv":
        import csv
        with open(args.output, "w", newline="", encoding="utf-8") as f:
            w = csv.DictWriter(f, fieldnames=rows[0].keys())
            w.writeheader()
            w.writerows(rows)
    
    print(f"{len(rows)} articles -> {args.output}")

def main():
    p = argparse.ArgumentParser(prog="news", description="Agregateur de news")
    sub = p.add_subparsers(dest="cmd", required=True)
    
    sub.add_parser("fetch", help="Recuperer les articles").set_defaults(func=cmd_fetch)
    
    pl = sub.add_parser("list", help="Lister")
    pl.add_argument("--source", help="Filtrer par source")
    pl.add_argument("--search", help="Rechercher")
    pl.add_argument("--limit", type=int, default=20)
    pl.set_defaults(func=cmd_list)
    
    pe = sub.add_parser("export", help="Exporter")
    pe.add_argument("--format", choices=["json", "csv"], default="json")
    pe.add_argument("--output", default="export.json")
    pe.set_defaults(func=cmd_export)
    
    args = p.parse_args()
    args.func(args)

if __name__ == "__main__":
    main()

الاستخدام

output
python -m app.cli fetch
python -m app.cli list --limit 10
python -m app.cli list --source hackernews
python -m app.cli list --search "python"
python -m app.cli export --format csv --output news.csv

نقطة دخول وحدة التحكم

output
# pyproject.toml
[project.scripts]
news = "app.cli:main"
output
pip install -e .
news fetch
news list --limit 5

جدولة cron (لينكس/ماك)

output
crontab -e

# كل 30 دقيقة
*/30 * * * * cd /home/user/news_agg && \
  /home/user/.venv/bin/news fetch >> logs/news.log 2>&1

الجدولة على ويندوز (Task Scheduler)

output
# PowerShell
schtasks /Create /SC MINUTE /MO 30 /TN "NewsAgg" /TR "C:\path\to\python.exe -m app.cli fetch"

نظرة عامة على Stripe وSendGrid

NOTEالهدف — استكشاف Stripe (المدفوعات) وSendGrid (البريد الإلكتروني)، واختيار بين SDK الرسمي وrequests الخام.

Stripe: إنشاء دفعة (API HTTP خام)

output
import requests, os

STRIPE_KEY = os.getenv("STRIPE_SECRET_KEY")   # sk_test_...

# يستخدم Stripe المصادقة الأساسية مع المفتاح كمستخدم
r = requests.post(
    "https://api.stripe.com/v1/payment_intents",
    auth=(STRIPE_KEY, ""),
    data={
        "amount": 2000,           # 20.00 EUR
        "currency": "eur",
        "payment_method_types[]": "card",
        "description": "Commande #1234"
    },
    timeout=10
)
r.raise_for_status()
intent = r.json()
print(f"client_secret : {intent['client_secret']}")
# يستخدم الواجهة الأمامية client_secret لإكمال الدفع

Stripe: إنشاء عميل

output
r = requests.post("https://api.stripe.com/v1/customers",
                   auth=(STRIPE_KEY, ""),
                   data={"email": "alice@example.com",
                         "name": "Alice Dupont"})
customer = r.json()
print(customer["id"])   # cus_xxx

SDK Stripe الرسمي (موصى به)

output
pip install stripe

import stripe
stripe.api_key = STRIPE_KEY

# أكثر بايثونية
intent = stripe.PaymentIntent.create(
    amount=2000,
    currency="eur",
    payment_method_types=["card"],
    description="Commande #1234"
)
print(intent.id)
print(intent.client_secret)
TIPSDK مقابل requests
  • SDK الرسمي: إعادة المحاولة، الكتابة النوعية، webhooks الموقعة، مفاتيح idempotency تلقائية
  • requests: مفيد إذا لم يكن هناك SDK، أو لفهم المفاهيم
  • التوصية: SDK الرسمي لـ Stripe/Twilio/AWS، requests لـ APIs مخصصة

SendGrid: إرسال بريد إلكتروني (HTTP خام)

output
SENDGRID_KEY = os.getenv("SENDGRID_API_KEY")

payload = {
    "personalizations": [{
        "to": [{"email": "destinataire@example.com"}],
        "subject": "Hello depuis Python"
    }],
    "from": {"email": "contact@mondomaine.com", "name": "Mon App"},
    "content": [{
        "type": "text/html",
        "value": "<h1>Bonjour !</h1><p>Envoye via API.</p>"
    }]
}

r = requests.post(
    "https://api.sendgrid.com/v3/mail/send",
    json=payload,
    headers={"Authorization": f"Bearer {SENDGRID_KEY}"},
    timeout=10
)
print(r.status_code)   # 202 Accepted

SendGrid باستخدام قالب

output
payload = {
    "personalizations": [{
        "to": [{"email": "alice@example.com"}],
        "dynamic_template_data": {
            "name": "Alice",
            "order_id": "#1234",
            "total": "29.99 EUR"
        }
    }],
    "from": {"email": "orders@mondomaine.com"},
    "template_id": "d-xxxxx"     # تم إنشاؤه في SendGrid
}
requests.post("https://api.sendgrid.com/v3/mail/send",
               json=payload,
               headers={"Authorization": f"Bearer {SENDGRID_KEY}"})

SDKs الشائعة الأخرى

الخدمةالمكتبةالمجال
Stripestripeالمدفوعات
TwiliotwilioSMS، الصوت
SendGridsendgridالبريد الإلكتروني المعاملاتي
AWSboto3كل AWS (S3، SQS، SES...)
OpenAIopenaiGPT، التضمينات
Slackslack_sdkالرسائل، webhooks

أفضل ممارسة: مفتاح idempotency

output
import uuid

r = requests.post(
    "https://api.stripe.com/v1/charges",
    auth=(STRIPE_KEY, ""),
    headers={"Idempotency-Key": str(uuid.uuid4())},
    data={...}
)
# في حالة إعادة المحاولة، نفس المفتاح = لا فوترة مزدوجة

المصادقة الأساسية وBearer Token

NOTEالهدف — فهم HTTP Basic Auth، وBearer Tokens وJWT.

HTTP Basic Authentication

اسم المستخدم + كلمة المرور مشفرة بـ base64 في الترويسة Authorization.

output
import requests

# requests يقوم بذلك تلقائيًا مع auth=
r = requests.get(
    "https://api.example.com/me",
    auth=("alice", "mot_de_passe")
)

# الترويسة الخام المكافئة:
# Authorization: Basic YWxpY2U6bW90X2RlX3Bhc3Nl
output
from requests.auth import HTTPBasicAuth

r = requests.get(url, auth=HTTPBasicAuth("user", "pwd"))
WARNINGالقيود
  • يتم إرسال كلمة المرور بنص واضح (base64 = ليس تشفيرًا)
  • HTTPS إلزامي
  • لا يوجد إبطال بسيط
  • يُستخدم أقل فأقل لصالح Bearer

Bearer Token

يُرسل التوكن (الرمز) في الترويسة Authorization: Bearer .... هذا هو المعيار الحديث (OAuth، JWT...).

output
TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

r = requests.get(
    "https://api.github.com/user",
    headers={"Authorization": f"Bearer {TOKEN}"}
)

print(r.json())

JWT (JSON Web Token)

التنسيق الأكثر شيوعًا لـ Bearer. ثلاثة أجزاء مفصولة بـ .: header.payload.signature.

output
import jwt   # pip install PyJWT

token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.signature"

# فك التشفير بدون التحقق (للتصحيح)
payload = jwt.decode(token, options={"verify_signature": False})
print(payload)
# {'sub': '123', 'exp': 1700000000}

# فك التشفير مع التحقق
payload = jwt.decode(token, key="mon_secret", algorithms=["HS256"])

مصادقة مخصصة (وراثة AuthBase)

output
from requests.auth import AuthBase

class BearerAuth(AuthBase):
    def __init__(self, token):
        self.token = token
    def __call__(self, req):
        req.headers["Authorization"] = f"Bearer {self.token}"
        return req

# الاستخدام
r = requests.get(url, auth=BearerAuth(TOKEN))

تحديث التوكن تلقائيًا

output
import time

class TokenManager:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self._token = None
        self._expires_at = 0
    
    def get_token(self) -> str:
        if not self._token or time.time() > self._expires_at - 60:
            self._refresh()
        return self._token
    
    def _refresh(self):
        r = requests.post("https://auth.example.com/token", data={
            "grant_type": "client_credentials",
            "client_id": self.client_id,
            "client_secret": self.client_secret
        })
        r.raise_for_status()
        d = r.json()
        self._token = d["access_token"]
        self._expires_at = time.time() + d["expires_in"]

mgr = TokenManager(...)
r = requests.get(url, headers={"Authorization": f"Bearer {mgr.get_token()}"})
va-plus-loin

تغطي هذه المقالة المقتطفات الأكثر فائدة — الدورة الكاملة Python Requests APIs (10 فصول، 30 درسًا، تمارين مصححة ومشروع نهائي) تأخذك إلى النهاية.

./acceder-au-cours-complet cours gratuit : Vibe Coding

الأسئلة الشائعة

كم من الوقت يستغرق تعلم Python Requests APIs؟
مع تقدم منظم (10 فصول، 30 درسًا قصيرًا وعمليًا)، يمكن الوصول إلى مستوى تشغيلي في بضعة أسابيع بمعدل 30 إلى 60 دقيقة يوميًا. المهم هو تطبيق كل مفهوم فورًا.
هل هناك متطلبات مسبقة؟
تكفي أساسيات الحوسبة. إذا كنت تعرف استخدام الطرفية وقراءة كود بسيط، فأنت جاهز.
من أين نبدأ عمليًا؟
أعد إنتاج أوامر هذه المقالة، ثم تابع الدورة الكاملة Python Requests APIs: فهي تربط الـ 30 درسًا بالترتيب، مع تمارين ومشروع نهائي.

📬 هل تريد تلقي هذا النوع من الأدلة كل أسبوع؟ اشترك مجانًا — كود حقيقي، بدون كلام فارغ.