تخطَّ إلى المحتوى
MoroccanDevs

أول طلب لك إلى SerpApi في خمس دقائق

دليل عملي لإرسال أول طلب إلى SerpApi بـ Python و JavaScript و cURL، وقراءة بنية استجابة JSON، والتعامل مع المفاتيح والأخطاء بشكل صحيح.

نُشر في 3 دقائق قراءة

في المقال السابق رأينا لماذا يُعدّ استخراج نتائج البحث بنفسك قراراً مكلفاً. الآن سنكتب أول طلب فعلي ونقرأ ما يعود إلينا.

قبل أن نبدأ

تحتاج إلى مفتاح API. سجّل حساباً مجانياً على serpapi.com، وستجد المفتاح في لوحة التحكم. الخطة المجانية تكفي تماماً لهذه السلسلة.

لا تضع المفتاح في الكود مباشرةً. ضعه في متغيّر بيئة، لأنّ المفتاح الذي يصل إلى مستودع Git عام يُعتبر مكشوفاً حتى لو حذفته في commit لاحق — سجلّ Git يحتفظ به.

export SERPAPI_KEY="ضع_مفتاحك_هنا"

أول طلب

import os
import serpapi

client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"])

results = client.search({
    "engine": "google",
    "q": "أفضل مقاهي الدار البيضاء",
    "google_domain": "google.co.ma",
    "gl": "ma",   # البلد
    "hl": "ar",   # لغة الواجهة
})

for result in results["organic_results"][:5]:
    print(f'{result["position"]:>2}. {result["title"]}')
    print(f'    {result["link"]}\n')

لاحظ استخدام --data-urlencode في مثال cURL. هذا ليس تفصيلاً تجميلياً: الاستعلام العربي يحتوي على أحرف غير ASCII ومسافات، ووضعه مباشرةً في الـ URL دون ترميز يعطي طلباً مشوّهاً أو خطأ.

قراءة بنية الاستجابة

الاستجابة كائن JSON واحد بمفاتيح عليا، أهمّها:

المفتاحما يحتويه
search_metadataحالة الطلب، معرّفه، والوقت المستغرق
search_parametersالمعاملات كما فُهمت فعلياً من طرف الخدمة
search_informationالعدد الإجمالي للنتائج ومعلومات الاستعلام
organic_resultsالنتائج الطبيعية، وهي ما يهمّنا غالباً
related_questionsصندوق «أسئلة ذات صلة»
knowledge_graphبطاقة المعلومات الجانبية، إن وُجدت
paginationروابط الصفحات التالية

وكل عنصر داخل organic_results له هذا الشكل:

{
  "position": 1,
  "title": "عنوان الصفحة",
  "link": "https://example.com/page",
  "displayed_link": "https://example.com › page",
  "snippet": "المقتطف النصّي الظاهر تحت العنوان"
}

نصيحة تشخيصية: حين لا تحصل على النتائج المتوقّعة، اقرأ search_parameters أولاً. هي تخبرك كيف فُهم طلبك فعلياً، وغالباً ما تكتشف أنّ معاملاً كتبته خطأ جرى تجاهله بصمت.

المعاملات التي تهمّ فعلاً

ثلاثة معاملات تحدّد أي نسخة من صفحة النتائج تحصل عليها، والخلط بينها مصدر شائع للأخطاء:

  • google_domain — أي نطاق Google تستعلم منه، مثل google.co.ma أو google.com.eg.
  • gl — رمز البلد المكوّن من حرفين، يحدّد التحيّز الجغرافي للنتائج.
  • hl — رمز اللغة، يحدّد لغة الواجهة وله أثر على النتائج نفسها.

بالإضافة إليها: location لتحديد مدينة بعينها، و device للتبديل بين desktop و mobile (وهما يعطيان ترتيبين مختلفين فعلاً)، و start للتصفّح عبر الصفحات.

انتبه هنا إلى تفصيل مهمّ: كان بالإمكان سابقاً طلب مئة نتيجة دفعة واحدة عبر المعامل num، لكنّ Google أوقفت دعم ذلك سنة 2025، وصارت معظم الطلبات تعيد عشر نتائج بغضّ النظر عن قيمته. النتيجة العملية أنّ أي أداة ما تزال تعتمد على num=100 تظنّ أنّها ترى مئة نتيجة وهي ترى عشراً، وتُبلغ خطأً بأنّ نطاقك غير موجود. الطريقة الصحيحة اليوم هي التصفّح بـ start صفحةً صفحة.

سنستعمل هذه المعاملات بجدّية في المقال القادم، لأنّها بالضبط ما يجعل قياس الترتيب في السوق العربي مختلفاً عمّا يفترضه معظم الناس.

التعامل مع الأخطاء

الخطأ الأكثر شيوعاً في الإنتاج هو 429 Too Many Requests، ويعني أنّك تجاوزت المعدّل المسموح. الاستجابة الصحيحة له ليست إعادة المحاولة فوراً، بل الانتظار بتباعد أُسّي:

import time
import requests

def search_with_retry(params, max_attempts=5):
    for attempt in range(max_attempts):
        response = requests.get("https://serpapi.com/search", params=params, timeout=30)

        if response.status_code == 429:
            # تباعد أُسّي: 1، 2، 4، 8 ثوانٍ
            wait = 2 ** attempt
            time.sleep(wait)
            continue

        response.raise_for_status()
        return response.json()

    raise RuntimeError("تعذّر إتمام الطلب بعد عدّة محاولات")

إعادة المحاولة فوراً بعد 429 تزيد الضغط ولا تحلّ شيئاً. التباعد الأُسّي يعطي الخدمة فرصة للتنفّس ويرفع احتمال نجاح المحاولة التالية.

الخطوة التالية

الآن نملك الأدوات الأساسية. في المقال القادم نستعملها في شيء لم يكتب عنه أحد بجدّية: كيف تختلف نتائج البحث العربية بين الدول العربية، وكيف تقيس ذلك بنفسك.

النشرة البريدية

مقال تقني جديد بالعربية كل أسبوع، حول واجهات برمجة التطبيقات واستخراج بيانات البحث. بدون رسائل مزعجة، وبإمكانك إلغاء الاشتراك في أي وقت.