Navvo
الأدلّة

مكتبة بايثون (Python SDK)

ثبّت واستخدم عميل بايثون الرسمي navvo لخدمات الترميز الجغرافي والمسارات والأماكن وحركة المرور والمزيد من جهة الخادم.

مكتبة بايثون (Python SDK)

عميل بايثون الرسمي navvo هو غلاف من جهة الخادم لخدمة Navvo على الويب. وهو مكتوب بأنواع محدّدة، ويعيد المحاولة تلقائيًا، وبلا تبعيات — افتراضيًا يستخدم مكتبة بايثون القياسية فقط، فيُثبَّت ويعمل في أي بيئة؛ وإذا كانت httpx مُثبَّتة فسيستخدمها تلقائيًا لتجميع الاتصالات. لا يحتوي على واجهة خرائط ولا جلب بلاطات — لعرض خريطة في المتصفح استخدم خرائط Navvo.

يتطلّب: بايثون 3.8+ · عنوان الأساس: https://navvo.io/api/v1

التثبيت

pip install navvo
# نقل HTTP مجمّع اختياري:
pip install "navvo[httpx]"

المصادقة

تُرسَل كل طلبات الاستدعاء عبر ترويسة x-api-key. يُقرأ المفتاح من متغيّر البيئة NAVVO_API_KEY افتراضيًا، أو مرّره صراحةً:

from navvo import NavvoClient

navvo = NavvoClient()                       # يستخدم $NAVVO_API_KEY
navvo = NavvoClient("nvvo_your_key_here")   # صراحةً

لا تضع المكتبة المفتاح في الرابط أبدًا — باستثناء style_url() التي تبني رابط نمط خريطة يُجلب من المتصفح، حيث يجب تمرير المفتاح كـ ?api_key= (لا يمكن للمتصفحات إضافة ترويسات على طلبات النمط/البلاطات).

بداية سريعة

from navvo import NavvoClient, LatLng, BBox

with NavvoClient() as navvo:
    # ترميز جغرافي أمامي — تُحوَّل الإحداثيات النصية إلى أرقام تلقائيًا
    hits = navvo.geocode("مستشفى العبدلي، عمّان", limit=5)
    print(hits[0].lat, hits[0].lng, hits[0].display_name)

    # خطّط مسارًا — تمرّر lat/lng والمكتبة تُسلسل lon/lat على الشبكة
    plan = navvo.route(locations=[
        {"lat": 31.95, "lng": 35.91, "name": "A"},
        {"lat": 31.99, "lng": 35.95, "name": "B"},
    ], costing="auto")
    print("الوقت المتوقّع بالثواني:", plan.trip["summary"]["time"])
    path = plan.geometry()          # خطّ مرمّز مفكوك -> list[LatLng]

    # بيانات حيّة وفق الظروف
    wx = navvo.weather_point(31.95, 35.91)
    inc = navvo.incidents(bbox=BBox(35.85, 31.9, 35.99, 31.99), limit=10)

الإحداثيات — لن تنقلب أبدًا

تمرّر النقاط دائمًا كـ LatLng(lat=..., lng=...) (أو قاموس {"lat":.., "lng":..} أو صفّ (lat, lng)). تتولّى المكتبة كل اختلافات صيغة الشبكة: {lon, lat} لـ route()/traffic_route()، و{lat, lon} لحمولات تمرير المسارات، ومعاملات lat/lon منفصلة للترميز العكسي، وwest,south,east,north لـ BBox، و[lng, lat] لـ GeoJSON، وصيغة WKT POINT(lng lat) لمركز المكان (فُكّها عبر place.center_latlng).

إعادة المحاولة والأخطاء

تُعاد المحاولة على الأعطال العابرة (5xx، 429/الحصّة، انقطاعات الشبكة) بتراجع أُسّي مع تشويش كامل، مع احترام Retry-After؛ ولا يُعاد على أخطاء العميل (400/401/403/404). كل الأخطاء ترث من NavvoError:

from navvo.errors import (
    NavvoRateLimitError, NavvoForbiddenError, NavvoServiceUnavailableError,
)

try:
    r = navvo.geocode("مستشفى العبدلي، عمّان")
except NavvoRateLimitError as e:
    print("تجاوز الحدّ، أعد المحاولة بعد", e.retry_after, "ثانية")
except NavvoForbiddenError as e:
    print("مشكلة نطاق/حصّة:", e.reason or e.message)
except NavvoServiceUnavailableError:
    print("محرّك الترميز معطّل مؤقتًا — استخدم بديلًا")

يُفكّ غلاف الترميز/المسارات ({provider, available, data}) من أجلك تلقائيًا، ويُعيد slug مكان غير معروف القيمة None (قيمة فارغة ناعمة، وليست خطأً).

البحث

تُعيد search() استجابة GET /search في كائن SearchResponse بأنواع محدّدة، بما فيها query_id الذي تشير إليه أحداث النقر اللاحقة. ولا يُضاف إلى الطلب أيّ خيار لم تمرّره:

from navvo import NavvoClient, LatLng

navvo = NavvoClient()
res = navvo.search(
    "pharmacy",
    near=LatLng(lat=31.9539, lng=35.9106),  # رتّب الأماكن الأقرب أولًا (أو lat=… و lon=…)
    radius_km=3, sort="distance",           # كلاهما يحتاج نقطة أصل
    open_now=True, min_rating=4,
    amenities=["wheelchair-accessible-entrance"],
    facets=["category", "amenities"],       # res.facets.category و res.facets.amenities
    highlight=True,                         # hit.highlight.name_en / name_ar
)
res.query_id                                # لاستخدامه مع send_search_event()
for hit in res.places.items:                # بأنواع محدّدة: distance_km و image_url و highlight و promoted
    print(hit.position, hit.name_en, hit.distance_km)
res.did_you_mean, res.suggestions           # عند انعدام النتائج فقط: تصحيح إملائي وأماكن شائعة

navvo.search("rumi caf", mode="typeahead")                           # أثناء الكتابة
navvo.search("quiet place to work with good coffee", semantic="on")  # المطابقة حسب المعنى
navvo.search("pharmacy", analytics=False)                            # أبقِ هذا الاستدعاء خارج التحليلات
navvo.search_suggestions("pha", limit=6)                             # GET /search/suggestions
navvo.similar_places(slug="jordan-museum-994700", limit=6)           # GET /search/similar ← items و source
  • ما زالت SearchResponse قاموس الاستجابة نفسه، فتبقى الشيفرة المكتوبة للإصدار 0.1 (res["places"]["items"]) تعمل. والحقول الموثّقة متاحة أيضًا خصائصَ بأنواع محدّدة، ويحتفظ كل كائن بالحمولة الأصلية في .raw.
  • مع مفتاح API لا تعمل المطابقة حسب المعنى إلا إذا مرّرت semantic="on"، ولا تعمل أبدًا مع mode="typeahead". وتكون قيمة res.index.mode هي "hybrid" عندما تُسهم فيها.
  • تُعيد search_suggestions() باستعلام فارغ قائمة بداية من التصنيفات اليومية والأماكن المعروفة. وتُعيد similar_places() الحقلين items وsource ("vectors": مقارنة حسب المعنى، أو "nearby": البديل الاحتياطي)، والمكان غير المعروف يرفع NavvoNotFoundError.
  • تتحقّق الحزمة من الوسائط قبل الإرسال: الاستعلام الفارغ، أو قيمة غير معروفة لـ mode أو sort أو semantic أو لاسم وجه، أو إحداثيات خارج الكرة الأرضية، أو معرّف جلسة غير صالح، كلها ترفع NavvoValidationError دون إرسال أي طلب.

تصل الإبرازات مُهرَّبة بترميز HTML، والكلمات المطابقة محاطة بالوسم <em>. وتقسم parse_highlight() الإبراز إلى مقاطع (text, match)، فتعرضها نصًّا بدل الوثوق بالسلسلة على أنها ترميز:

from navvo import parse_highlight

for hit in res.places.items:
    if hit.highlight and hit.highlight.name_en:
        print([(seg.text, seg.match) for seg in parse_highlight(hit.highlight.name_en)])

مرشّح السعر وتفاصيل النتيجة

منذ الإصدار 0.3.0 يحتفظ price بالأماكن التي تقع في أي من مستويات السعر المحدَّدة: 1 حتى 5 دنانير للشخص، و2 من 5 إلى 10، و3 من 10 إلى 20، و4 أكثر من ذلك. ويمكن أيضًا أن يحمل كل عنصر مكان ما تعرضه قائمة النتائج، وتكون قيمة كل حقل من هذه الحقول None إذا لم تتوفّر بياناته للمكان:

res = navvo.search("مقهى", near=LatLng(lat=31.9539, lng=35.9106), price=[1, 2])
for hit in res.places.items:
    print(hit.name_en, hit.category_name, hit.price_range, hit.price_level, hit.review_count)
    print(hit.address, hit.area, hit.highlights)
    if hit.hours:                            # اليوم، بتوقيت الأردن
        print(hit.hours.state, hit.hours.closes_at, hit.hours.opens_at, hit.hours.opens_day)
navvo.similar_places(slug="jordan-museum-994700", locale="ar")  # category_name و address بالعربية

تكون قيمة hours.state إما "open" أو "closing" (يغلق خلال 45 دقيقة) أو "closed". ويدلّ hours.always_open على مكان مفتوح على مدار الساعة، وhours.hours_may_vary على عطلة رسمية. ويرفع المستوى الواقع خارج 1–4 الخطأ NavvoValidationError قبل إرسال أي شيء. راجع تفاصيل النتيجة.

النقرات والتحويلات

لترى نسبة النقر والتحويلات لمشروعك في بوابة المطوّرين، أرسل معرّف جلسة مع البحث، واحدًا لكلّ جلسة مستخدم وفقط إذا وافق مستخدمك على ذلك. ثم أبلِغ عمّا فتحه المستخدم:

from navvo import SearchEvent, create_search_session_id

session = create_search_session_id()        # واحد لكل جلسة مستخدم، وبموافقة المستخدم فقط
res = navvo.search("rumi cafe", session=session)
hit = res.places.items[0]                   # النتيجة التي فتحها المستخدم

navvo.send_search_event(SearchEvent(query_id=res.query_id, type="click",
                                    place_id=hit.id, position=hit.position))
navvo.send_search_event(SearchEvent(query_id=res.query_id, type="conversion", name="directions",
                                    place_id=hit.id, position=hit.position))
  • تُقبل الأحداث خلال 7 أيام من البحث، وفقط إذا حمل البحث معرّف جلسة، وفقط بمفتاح API نفسه.
  • ترسل send_search_events() عدّة أحداث معًا، في طلبات لا يتجاوز كلٌّ منها 20 حدثًا و16 كيلوبايت. وأسماء التحويلات هي directions وnavigate وsave وcall وwebsite وshare.
  • ترفع search() الخطأ NavvoValidationError لمعرّف جلسة لا يطابق ^[A-Za-z0-9_-]{16,64}$ أو يحتوي على 6 أرقام متتالية؛ أمّا create_search_session_id() فتولّد دائمًا معرّفًا صالحًا.
  • يُبقي NavvoClient(search_analytics=False) كل ما يبحث عنه العميل خارج التحليلات، وتُرفض الأحداث التي يرسلها عميل كهذا، فأرسل النقرات من عميل أُنشئ دون هذا الخيار.

راجع أحداث البحث لمعرفة ما يُقبل ولماذا قد يُرفض حدث، وتحليلات البحث والخصوصية لمعرفة قواعد الموافقة وما تسجّله Navvo.

خريطة الدوال

المجالالدوال
البلاطات والإعدادstyles, style_url, map_config
البحث والأماكنsearch, search_suggestions, similar_places, send_search_event, send_search_events, geocode, reverse_geocode, geocode_batch, reverse_geocode_batch, places, iter_places, place, place_thumb, place_categories, place_facets, place_hours, place_popular_times, place_attributes, place_reviews_summary, place_photos, place_nearby, places_reachable
المساراتroute, simple_route, matrix, isochrone, map_match, optimize, routing_profiles
حركة المرور والحوادثtraffic_route, traffic_summary, incidents, incident_types, report_incident, road_edits, route_risk
الطقس وجودة الهواءweather_point, weather_forecast, weather_cities, air_quality_cities
الشحن الكهربائي والنقلev_stations, transit_stops, gbfs

تقابل كل دالة نقطة النهاية الموثّقة في مرجع الواجهة. تُعيد geocode وplaces وplace وroute وmatrix كائنات بأنواع محدّدة مع تحليل الحقول الشائعة والحفاظ على الحمولة الكاملة في .raw.

Copyright © 2026