الخطوات الأولى
جميع الاستدعاءات تأتي من نفس قاعدة البيانات وترجع JSON. لا تتطلب نقاط النهاية العامة المصادقة؛ تتطلب تلك الخاصة مفتاح الوصول الخاص بك.
العنوان الأساسي
/ar-sa/api بادئة اللغة هي جزء من عنوان URL (ar-sa), ولكنها لا تغير البيانات التي تم إرجاعها - فالسجلات تأتي من البنك تمامًا كما تم تسجيلها في الميدان.
curl -G -d "municipality=Ponta Pora" --data-urlencode "country=Brasil" \
/ar-sa/api/lastcountingpublic إذا كانت الاستجابة عبارة عن قائمة JSON، فهذا يعني أن التكامل يعمل بالفعل.
key تتم قراءته من سلسلة الاستعلام (?key=SUA_CHAVE). إرساله فقط في نص النموذج يعود 404 "Wrong key". تستمر الحقول الأخرى في الظهور في نص الطلب. استشارة البيانات العامة
نقطة النهاية /api/lastcountingpublic إرجاع أحدث أعداد البيض مع خطوط الطول والعرض الوبائية والأسبوع والسنة. وهي نقطة البداية للخرائط واللوحات والدراسات.
/api/lastcountingpublicعامcurl -G \
--data-urlencode "municipality=Ponta Pora" \
--data-urlencode "date_start=2025-01-01" \
--data-urlencode "date_end=2025-12-31" \
/ar-sa/api/lastcountingpublic import requests
BASE = "/ar-sa/api"
resposta = requests.get(
BASE + "/lastcountingpublic",
params={
"municipality": "Ponta Pora",
"date_start": "2025-01-01",
"date_end": "2025-12-31",
},
timeout=60,
)
resposta.raise_for_status()
for contagem in resposta.json():
print(contagem["date"], contagem["ovitrap_id"], contagem["eggs"]) const BASE = "/ar-sa/api";
const params = new URLSearchParams({
state: "MS",
date_start: "2025-01-01",
});
const resposta = await fetch(BASE + "/lastcountingpublic?" + params);
const contagens = await resposta.json();
console.log(contagens.length, "contagens"); نفس معلمات الموقع (country, state, municipality) وهي تنطبق على نقاط النهاية العامة الأخرى: مصائد البيض، والكتل، وEDL، وصيانة EDL والنقاط الاستراتيجية. مجرد تغيير مسار نقطة النهاية يؤدي بالفعل إلى تغيير مجموعة البيانات.
تصفح كافة الصفحات
دعم نقاط النهاية المرقّمة page من 1 إلى 100. وفوق ذلك، تستجيب واجهة برمجة التطبيقات (API) بالنص "Maximum pagination is 100" والحالة 200 — أي أن النص لم يعد قائمة. تحقق دائمًا من النوع قبل التكرار.
import requests
BASE = "/ar-sa/api"
def baixar_tudo(endpoint, **filtros):
"""Percorre as paginas ate a API devolver uma pagina vazia."""
registros = []
for pagina in range(1, 101):
resposta = requests.get(
BASE + endpoint,
params=dict(filtros, page=pagina),
timeout=60,
)
resposta.raise_for_status()
dados = resposta.json()
# limite de paginacao atingido: a API devolve uma string, nao uma lista
if not isinstance(dados, list):
print("Aviso:", dados)
break
if not dados:
break
registros.extend(dados)
return registros
ovitrampas = baixar_tudo("/getmunicipalityovitrapspublic", municipality="Ponta Pora")
print(len(ovitrampas), "ovitrampas") date_start e date_end لتقسيم الفترة إلى فترات أصغر. مزامنة تزايدية
للحفاظ على قاعدة معكوسة، لا تقم بتنزيل كل شيء مرة أخرى مع كل تشغيل. نقطة النهاية /api/lastcountingpublic مقبول id, الذي يُرجع فقط الأعداد من هذا المعرف، وأيضًا date (تاريخ الادراج) e date_collect (data de coleta).
import json
import os
import requests
BASE = "/ar-sa/api"
ESTADO = "ultimo_id.json"
def ultimo_id_lido():
if os.path.exists(ESTADO):
with open(ESTADO) as arquivo:
return json.load(arquivo)["counting_id"]
return 0
def sincronizar():
ultimo = ultimo_id_lido()
novas = []
for pagina in range(1, 101):
resposta = requests.get(
BASE + "/lastcountingpublic",
params={"municipality": "Ponta Pora", "id": ultimo, "page": pagina},
timeout=60,
)
resposta.raise_for_status()
dados = resposta.json()
if not isinstance(dados, list) or not dados:
break
novas.extend(dados)
if novas:
maior = max(item["counting_id"] for item in novas)
with open(ESTADO, "w") as arquivo:
json.dump({"counting_id": maior}, arquivo)
return novas
print(len(sincronizar()), "contagens novas") احتفظ دائمًا بالأكبر counting_id تم الاستلام، وليس تاريخ التنفيذ: قد يشير العدد الذي تم إدخاله في الحقل اليوم إلى أسبوع سابق، ولا يسمح عامل التصفية حسب المعرف بإفلات هذه السجلات.
تصدير إلى CSV
تأتي التعدادات العامة بالفعل مع الإحداثيات، لذا يمكنك إنشاء جدول بيانات أو تغذية خريطة دون أي انضمام إضافي.
import csv
import requests
BASE = "/ar-sa/api"
COLUNAS = [
"counting_id",
"municipality",
"state_code",
"ovitrap_id",
"latitude",
"longitude",
"week",
"year",
"eggs",
"date",
"date_collect",
]
resposta = requests.get(
BASE + "/lastcountingpublic",
params={"state": "MS", "date_start": "2025-01-01"},
timeout=60,
)
contagens = resposta.json()
with open("contagens.csv", "w", newline="", encoding="utf-8") as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=COLUNAS, extrasaction="ignore")
escritor.writeheader()
escritor.writerows(contagens)
print("Arquivo contagens.csv gerado com", len(contagens), "linhas") إرسال البيانات
تستخدم الأمثلة التالية واجهة برمجة التطبيقات الخاصة وتتطلب مفتاحًا. يحدد النطاق الجغرافي للمفتاح ما يمكنه تسجيله - لا يسجل مفتاح البلدية إلا في البلدية نفسها.
/api/postcountingخاصإرسال قراءة ovitrap الموجودة
يرسل عدد البيض لمصيدة البيض المسجلة بالفعل. يقع Ovitrap بجانب ovitrap_group_id ضمن بلدية المفتاح، ويتم حساب الأسبوع الوبائي من الميدان date.
curl -X POST \
-d "ovitrap_group_id=97" \
-d "ovitrap_lat=-7.000000" \
-d "ovitrap_lng=-8.000000" \
-d "date=2025-01-20" \
-d "counting_observation_id=1" \
-d "counting_eggs=5" \
"/ar-sa/api/postcounting?key=SUA_CHAVE" import requests
BASE = "/ar-sa/api"
CHAVE = "SUA_CHAVE"
resposta = requests.post(
BASE + "/postcounting",
params={"key": CHAVE}, # a chave vai na URL
data={ # os dados vao no corpo
"ovitrap_group_id": 97,
"ovitrap_lat": -7.000000,
"ovitrap_lng": -8.000000,
"date": "2025-01-20",
"counting_observation_id": 1,
"counting_eggs": 5,
},
timeout=60,
)
print(resposta.status_code, resposta.json())
# 200 "Contagem registrada" /api/postcountingخاصتثبيت ovitrap جديد بجانب القراءة
إذا ovitrap_group_id غير موجود في البلدية بعد، يتم إنشاء مصيدة البيض بنفس الطلب. أرسل أيضًا العنوان والنوع إن أمكن (ovitrap_type_id: 1 الحضرية، نمط; 2 rural).
import requests
BASE = "/ar-sa/api"
CHAVE = "SUA_CHAVE"
resposta = requests.post(
BASE + "/postcounting",
params={"key": CHAVE},
data={
"ovitrap_group_id": 96,
"ovitrap_address_district": "Centro",
"ovitrap_address_street": "Rua das Flores",
"ovitrap_address_number": "123",
"ovitrap_address_complement": "",
"ovitrap_address_sector": "Setor 04",
"ovitrap_responsable": "Maria Souza",
"ovitrap_block_id": "12",
"ovitrap_type_id": 2, # 1 = urbana (padrao), 2 = rural
"ovitrap_lat": -7.000000,
"ovitrap_lng": -8.000000,
"date": "2025-01-20",
"counting_date_collect": "2025-01-27",
"counting_observation_id": 1,
"counting_eggs": 5,
},
timeout=60,
)
print(resposta.status_code, resposta.json()) 400— نقصovitrap_lat,ovitrap_lngouovitrap_group_id.400—ovitrap_type_idيختلف عن 1 أو 2404— يوجد بالفعل إحصاء لهذا البيض، السنة والأسبوع.500— يقع تاريخ الإرسال في أسبوع وبائي مستقبلي أو غير صالح.
/api/postactionخاصسجل زيارة جماعية
يستخدم block_id لبدء الزيارة في كتلة مسجلة بالفعل. إذا لم تكن الكتلة موجودة بعد، أرسل block_group_id مع بيانات الكتلة ويتم إنشاؤها تلقائيًا داخل البلدية الرئيسية.
import requests
BASE = "/ar-sa/api"
CHAVE = "SUA_CHAVE"
visita = {
"block_id": 97,
"date": "2025-01-20",
"block_land_residence": 10,
"action_land_residence_out": 2,
"action_land_residence_breedings": 1,
"action_land_residence_treated": 1,
"action_deposit_a1_quantity": 4,
"action_deposit_a1_eliminated": 2,
"action_deposit_a1_treated": 1,
"action_deposit_a1_larvicid": 10,
"action_observation": "Foco encontrado em pneus nos fundos do imovel.",
}
resposta = requests.post(
BASE + "/postaction", params={"key": CHAVE}, data=visita, timeout=60
)
if resposta.status_code == 409:
print("Ja existe visita para esse quarteirao nessa semana")
else:
print(resposta.status_code, resposta.json()) visita = {
"block_group_id": 97,
"date": "2025-01-20",
"block_address_district": "Centro Historico",
"block_address_sector": "Setor 04 - Norte",
"block_coordinates": "[[-7.123, -34.845], [-7.124, -34.846]]",
"block_lat": -7.123456,
"block_lng": -34.845678,
"block_responsable": "Joao da Silva",
"block_land_residence": 10,
"action_land_residence_out": 2,
"action_land_residence_breedings": 1,
"action_land_residence_treated": 1,
"action_observation": "Area com alta densidade de recipientes descartaveis.",
}
resposta = requests.post(
BASE + "/postaction", params={"key": CHAVE}, data=visita, timeout=60
)
print(resposta.status_code, resposta.json()) القائمة الكاملة لمجالات العقارات والودائع (a1, a2, b, c, d1, d2, e) هو في مرجع نقطة النهاية. تفترض الحقول الرقمية غير المرسلة صفرًا، ولكن أي قيمة ليست رقمًا تُرجع 400.
إزالة السجلات
تعتبر عمليات الإزالة نهائية وتقتصر دائمًا على البلدية الرئيسية.
# leitura de uma ovitrampa (identificada pela ovitrampa + data)
curl -X POST -d "ovitrap_group_id=97" -d "date=2025-01-20" \
"/ar-sa/api/postdeletecounting?key=SUA_CHAVE"
# a ovitrampa inteira
curl -X POST -d "ovitrap_group_id=97" \
"/ar-sa/api/postdeleteovitrap?key=SUA_CHAVE"
# visita de um quarteirao (quarteirao + data)
curl -X POST -d "block_group_id=97" -d "date=2025-01-20" \
"/ar-sa/api/postdeleteaction?key=SUA_CHAVE"
# o quarteirao inteiro
curl -X POST -d "block_group_id=97" \
"/ar-sa/api/postdeleteblock?key=SUA_CHAVE" /api/postdeletecounting وإرسالها مرة أخرى مع /api/postcounting — تؤدي إعادة الإرسال إلى إرجاع خطأ مكرر.معالجة الأخطاء
نص الاستجابة دائمًا عبارة عن سلسلة JSON مع الرسالة. ومن الجدير التعامل مع كل حالة، لأنه ليس كل خطأ يستحق محاولة أخرى:
| الموقف | شفرة | ما يجب القيام به |
|---|---|---|
"Wrong key" | 404 | تأكد من أن المفتاح موجود في سلسلة الاستعلام وليس في النص الأساسي. |
| العد المزدوج | 404 | هناك بالفعل قراءة لمصيدة البيض هذا الأسبوع؛ يرجى الإزالة قبل إعادة الإرسال. |
| زيارة مكررة | 409 | هناك بالفعل زيارة للكتلة هذا الأسبوع. |
| خارج النطاق | 403 | الكتلة لا تنتمي إلى بلدية تشافي. لا تكرر. |
| الحقل المطلوب مفقود | 400 | تصحيح التقديم؛ التكرار يرجع نفس الخطأ |
| أسبوع أو سنة غير صالحة | 500 | يقع التاريخ خارج الأسبوع الوبائي المقبول. تصحيح المجال date. |
import time
import requests
NAO_REPETIR = {400, 403, 404, 409}
def enviar(url, chave, dados, tentativas=3):
for tentativa in range(tentativas):
try:
resposta = requests.post(
url, params={"key": chave}, data=dados, timeout=60
)
except requests.RequestException as erro:
print("Falha de rede:", erro)
time.sleep(5 * (tentativa + 1))
continue
if resposta.status_code in NAO_REPETIR:
print("Erro definitivo:", resposta.status_code, resposta.json())
return None
if resposta.ok:
return resposta.json()
# 500 e demais erros de servidor: espera progressiva e tenta de novo
time.sleep(5 * (tentativa + 1))
return None الممارسات الجيدة
- قم بالتصفية حسب البلدية أو الولاية كلما أمكن ذلك - بدون تصفية، يقوم الاستعلام بمسح البلد بأكمله.
- تفضل المزامنة المتزايدة بواسطة
idخفض القاعدة بأكملها كل يوم. - إرسال الطلبات في سلسلة. لم يتم تصميم واجهة برمجة التطبيقات (API) لعشرات المكالمات المتزامنة لكل عميل.
- تأكد من أن الاستجابة عبارة عن قائمة قبل التكرار: تأتي رسائل حد الترحيل بالحالة 200.
- احفظ
counting_idوblock_idالمستلمة - فهي التي تسمح لك بمطابقة سجلات Conta Ovos مع تلك الموجودة في نظامك. - تعامل مع الأسبوع الوبائي باعتباره المجال الحاسم: تقبل Conta Ovos قراءة واحدة فقط لكل بيضة في الأسبوع، وزيارة واحدة لكل كتلة في الأسبوع.
- اتبع الصفحة mudanças قبل تحديث التكامل الخاص بك.