e-Devlet Servisinden PHP ile Veri Çekme: Nöbetçi Eczane Örneğiyle Token, Cookie ve PRG Deseni
e-Devlet üzerindeki herkese açık bir sorgulama servisinden PHP ile veri çekmek için üç şeyi doğru yönetmek yeterlidir: sayfayla birlikte gelen oturum tokenini yakalamak, tüm istekleri aynı cookie seti ile göndermek ve form gönderiminden sonra gelen 302 yönlendirmesini takip etmek. Bu yazıda nöbetçi eczane sorgulama servisini örnek alarak bu üç adımı gerçek bir proje üzerinden anlatıyorum. Sürecin sonunda il ve ilçe bazlı sorgu yapabilen, SQLite önbellekli, tek sınıflık bir PHP istemcisi ortaya çıktı.
e-Devlet Servisi Arka Planda Nasıl Çalışır?
İşe kod yazarak değil, tarayıcıda servisi kullanıp Chrome geliştirici araçlarının Network sekmesini izleyerek başladım. Bu adım atlanmamalı, çünkü e-Devlet servisleri tek bir istekten oluşmaz; sayfa yüklemesi, arka plandaki AJAX çağrıları ve form gönderimi birbirine oturum bilgisiyle bağlı bir zincir oluşturur.
Nöbetçi eczane servisinde bu zincir dört halkadan oluşuyor:
- Sorgulama sayfası GET ile açılır; sunucu hem cookie seti gönderir hem de sayfa gövdesine bir oturum tokeni gömer.
- İl seçildiğinde bir AJAX ucu ilçe listesini JSON olarak döndürür.
- Sorgula butonuna basıldığında form POST edilir ve sunucu 302 kodu ile sonuç sayfasına yönlendirir.
- Sonuç sayfası eczane tablosunu klasik HTML olarak gösterir.
Oturum Tokeni Nasıl Yakalanır?
Token sayfada iki yerde birden bulunur: body etiketinin data-token özniteliğinde ve formun içindeki gizli input alanında. İkisi de aynı değeri taşır. Scraper tarafında her iki noktayı da kontrol eden bir yakalama mantığı kurmak ucuz bir sigortadır; sayfa şablonu değişip biri kaybolursa kod diğerinden devam eder.
Kritik nokta şudur: token tek başına anlamsızdır, sayfayla birlikte gelen cookie setine bağlı çalışır. Token değerini kopyalayıp başka bir HTTP oturumunda kullanmak işe yaramaz. Bunun pratikteki karşılığı, tüm isteklerin aynı cookie dosyası (cookie jar) üzerinden yapılmasıdır. PHP cURL kullanıyorsanız CURLOPT_COOKIEJAR ve CURLOPT_COOKIEFILE ayarlarını aynı dosyaya yönlendirmek bu işi kendiliğinden çözer.
İl ve İlçe Listeleri Nereden Gelir?
Sonuç sayfası HTML döndürse de il ve ilçe listeleri için düzgün JSON uçları vardır. Ortak bir AJAX işleyicisine form verisi olarak işlem tipi ve metot parametreleri gönderilir; il metodu 81 ilin listesini, ilçe metodu ise üst kimlik ile verilen ilin ilçelerini döndürür.
Burada dikkat edilmesi gereken bir ayrıntı var: il kimlikleri plaka kodu ile birebir aynıdır, ancak ilçe kimlikleri sistemin kendi iç numaralarıdır. Yani ilçe kimliklerini tahmin etmek mümkün değildir; mutlaka AJAX ucundan çekip yerel veritabanında saklamak gerekir. Ben bu listeleri SQLite tablosunda 30 gün geçerlilik süresiyle önbelleğe aldım. İdari yapı sık değişmediği için bu süre fazlasıyla güvenlidir.
PRG Deseni Nedir ve Scraper Bunu Nasıl Aşar?
Formu gönderdiğinizde sunucu sonucu doğrudan döndürmez. Bunun yerine 302 Found cevabı verir ve tarayıcıyı ayrı bir sonuç sayfasına yönlendirir. Web geliştirmede buna Post Redirect Get, kısaca PRG deseni denir; kullanıcı sayfayı yenilediğinde formun ikinci kez gönderilmesini engeller.
Scraper açısından bunun iki sonucu vardır:
- Yönlendirme takip edilmezse elinize boş bir cevap geçer, çünkü asıl veri yönlendirilen sayfadadır.
- 302 cevabı yeni cookie değerleri gönderebilir; sonuç sayfası bu güncel cookie seti olmadan doğru çalışmayabilir.
PHP cURL tarafında çözüm iki ayardan ibarettir: CURLOPT_FOLLOWLOCATION açılır ve CURLOPT_POSTREDIR sıfır bırakılır. Böylece yönlendirme sonrası istek otomatik olarak GET metoduna döner ve cookie jar zincir boyunca gelen tüm çerezleri kendiliğinden biriktirir. Aynı işi yapan Node.js tabanlı açık kaynak bir projede geliştirici bu çerez birleştirmesini elle yapmak zorunda kalmıştı; cURL bu kırılgan adımı tamamen ortadan kaldırır.
Formu incelerken güzel bir sürprizle de karşılaştım: adres bileşeninde yalnızca il seçimi zorunlu tanımlanmış. İlçe alanı boş bırakılıp ana kimlik alanına plaka kodu yazıldığında servis, ilin tamamındaki nöbetçi eczaneleri döndürüyor. Bu keşif mimariyi ciddi sadeleştirdi: il geneli tek sorgu atıp ilçe filtresini kendi tarafımda uyguluyorum. Hem kaynak sisteme giden istek sayısı düşüyor hem de arayüzde ilçeler arası geçiş anlık oluyor.
Bozuk HTML Neden Regex ile Değil DOMDocument ile Okunmalı?
Sonuç tablosunu incelerken ilginç bir durum fark ettim: bazı hücre etiketleri hiç kapatılmamış. Telefon ve nöbet başlangıç sütunlarının etiketleri açık bırakılmış; tarayıcı bunları kendisi topluyor. Düzenli ifade (regex) tabanlı bir ayrıştırıcı bu yapıda ya yanlış eşleşir ya da hiç eşleşmez.
PHP standart kütüphanesindeki DOMDocument tam bu noktada değer kazanır. Tarayıcıların hata toleransına benzer bir toparlama yaparak bozuk HTML ağacını düzeltir; üzerine XPath sorgusu ile tablo satırlarını çekmek güvenilir sonuç verir. İki pratik ipucu: yüklemeden önce içeriğin başına UTF-8 kodlama bildirimi eklemek Türkçe karakterlerin bozulmasını önler, satır başına en az yedi hücre şartı koymak da başlık ve boş satırların listeye karışmasını engeller.
Kibar Scraping İçin Hangi Önlemler Alınmalı?
Kamu servislerinden veri okurken iki ilke vazgeçilmezdir: kaynağı yormamak ve gerçek bir tarayıcı gibi davranmak. Bu projede uyguladığım önlemler şunlar:
- İstekler arasına 1,5 saniyelik bekleme koydum; toplu sorgularda bile sunucuya saniyede bir istekten fazlası gitmiyor.
- Gerçekçi bir tarayıcı kimliği (User-Agent) ve Türkçe ağırlıklı dil başlığı gönderiyorum.
- Sorgu sonuçlarını il, ilçe ve tarih anahtarıyla SQLite tablosuna yazıyorum; aynı sorgu üç saat içinde tekrar gelirse kaynağa hiç gitmeden önbellekten dönüyor.
- Önbellek temizliği için ayrı bir zamanlanmış görev kurmadım; her yazma işleminde eski kayıtlar silinerek tembel temizlik yapılıyor.
Üç saatlik önbellek süresi bilinçli bir tercihtir: nöbet listeleri il sağlık müdürlükleri tarafından zorunlu hallerde gün içinde güncellenebilir, günlük önbellek bu değişiklikleri kaçırabilirdi.
Saha Notu
Projenin en öğretici çıktısı teknik değil stratejikti. Scraper sorunsuz çalışmasına rağmen yaptığım karşılaştırmada bazı iller için verinin her gün aynı sağlıkta gelmediğini gördüm. Halihazırda işlettiğim, verisini doğrudan eczacı odaları kaynağından günlük alan API servisimle kıyasladığımda, kaynağa yakın verinin daha tutarlı olduğu netleşti. Nöbet listelerinin asıl sahibi meslek örgütüdür; e-Devlet bu veriyi onay katmanından geçirip yayınlayan bir aracıdır ve araya giren her katman gecikme ile eksik riski demektir.
Bu yüzden çalışma benim tarafımda üretim sistemi değil, belgelenmiş bir yedek plan olarak arşive girdi. Ana kaynak bir gün aksarsa devreye alınacak kod hazır bekliyor. Web scraping projelerinde kodu yazmadan önce sorulması gereken soru şudur: bu veri zincirinde kaynağa en yakın halka hangisi ve oraya erişimim var mı?
Sık Sorulan Sorular
e-Devlet servislerinden veri çekmek için giriş yapmak gerekir mi?
Nöbetçi eczane sorgulama gibi herkese açık servisler için gerekmez. Bu tür servisler giriş yapılmadan kullanılabildiği için token ve cookie akışı da anonim oturum üzerinden yürür. Kimlik doğrulama gerektiren servisler bu yazının kapsamı dışındadır.
Token her istekte yenilenir mi?
Hayır, token oturum bazlıdır. Sayfa ilk açıldığında cookie seti ile birlikte üretilir ve aynı oturum içindeki tüm AJAX ve form isteklerinde geçerlidir. Yine de oturumu uzun süre saklamaya çalışmak yerine her sorgu döngüsünde sayfayı çekip taze token almak daha sağlıklı sonuç verir.
Cheerio yerine neden PHP DOMDocument kullanıldı?
İkisi de aynı işi yapar. Cheerio, Node.js tarafında jQuery sözdizimi sunan bir HTML ayrıştırıcıdır; DOMDocument ise PHP standart kütüphanesinin parçasıdır. Mevcut altyapım PHP ve SQLite üzerine kurulu olduğu için ek bağımlılık getirmeyen DOMDocument doğal tercihti. Kapanmamış etiketleri toparlama konusunda iki kütüphane de başarılıdır.
İl geneli sorgu ile ilçe bazlı sorgu arasında fark var mı?
Kaynak sistem açısından ikisi de tek istektir. Asıl kazanç istemci tarafındadır: il geneli tek sorgu atıp ilçe filtresini kendi uygulamanızda yaparsanız, kullanıcı ilçeler arasında gezerken kaynağa yeni istek gitmez. Küçük ve orta ölçekli illerde bu yaklaşım hem hızlı hem de kibardır.
Bu yöntem başka e-Devlet servislerinde de çalışır mı?
Aynı altyapıyı kullanan sorgulama servislerinde akış büyük oranda ortaktır: sayfayla gelen token, ortak AJAX işleyicisi ve PRG deseni. Ancak her serviste form alanları ve sonuç yapısı farklıdır; geliştirici araçlarıyla istek akışını izleyip form alanlarını tek tek doğrulamak her servis için ayrıca yapılması gereken bir iştir.
Özet
e-Devlet üzerindeki herkese açık sorgulama servislerinden PHP ile veri çekmenin anahtarı üç kavramda toplanıyor: sayfayla gelen oturum tokenini yakalamak, tüm istekleri tek cookie jar üzerinden yürütmek ve form gönderimi sonrası gelen 302 yönlendirmesini takip etmek. Bozuk HTML için regex yerine DOMDocument, kaynak sistemi yormamak için SQLite önbellek ve istek aralığı bu yapının tamamlayıcılarıdır. Projenin asıl dersi ise şu oldu: en temiz kod bile yanlış kaynaktan beslenirse eksik veri üretir; scraping öncesi ilk iş, veri zincirinde kaynağa en yakın halkayı bulmaktır. Bu yazıdaki teknikler herkese açık kamu verisinin kişisel ve eğitim amaçlı okunması için anlatılmıştır; kaynak sistemlere yük bindirmeden kullanılması esastır.











Yorumlar
Henuz yorum yok. Ilk yorumu siz yazin.
Yorum Yap