IETT Verileri, OSM, SOAP
Moovit [4] benzeri bir uygulamayı nasıl yazarız sorusuna cevap, önce İETT baz seyahat verileri gerekli. Gerekli veriler açık kaynak OSM verisi, ya da IETT API servisi üzerinden alınabilir.
OSM
Open Street Map adresinde gönüllülerin oluşturduğu metro, otobüs hat verileri var. Bu veriler her ülke için mevcut ana OSM dosyaları içinde, onların tarama yöntemleri var, fakat bazı servisler ile bu veriyi sorgulayıp çıktıları JSON dosyası ile yazmak ta mümkün. Mesela alttaki siteye gidilebilir,
https://overpass-turbo.eu
Bu sitede sol kısımda kod girilen yere alttaki kod yazılır,
[out:json];
area[name="İstanbul"]->.a;
(
nwr["route"="subway"](area.a);
);
out body;
>;
out skel;
Bu sorgu Run
düğmesi ile işletilir, ardından Export
düğmesi ile mesela GeoJSON
çıktısı alınabilir. Bu çıktı içinde metro hatlarının durakları, durak kordinatları,
her hattın geçtiği durak listesi vardır.
Sitede sorgu işletmek yerine aslında program işleterek aynı sonuçları alabiliriz, işleri otomatikleştirme için bu daha iyi olur. Bunun için
https://overpass-api.de/api/interpreter
servisi var, istenen sorgu ?data=
sonrasında üstteki bağlantıya
verilebiliyor, arka plandaki servis sorguyu işletip sonucu
kayıtlamamızı sağlıyor. Tüm URL'in neye benzediği Export
ile gidilen
ekranda Overpass API
bağlantısında görülebilir. Üretilen string
basit aslında, üstteki sorgu kodunun kodlanmış hali, bu kodlamayı
Python ile biz de yapabiliriz, ve böylece çağrıyı otomatikleştirmiş
oluruz.
import urllib.parse, requests
base_url = "https://overpass-api.de/api/interpreter?data="
q = """
[out:json];
area[name="İstanbul"]->.a;
(
nwr["route"="bus"](area.a);
);
out body;
>;
out skel;
"""
safe_string = urllib.parse.quote_plus(q)
r = requests.get(base_url + safe_string)
fout = open("bus.json","w")
fout.write(r.text)
fout.close()
Artık üretilen bus.json
verisini işleyip hat verisini çıkartabiliriz,
alttaki örnekte kordinatı olan duraklar hat verisini ekleniyor ve bir tanesi
örnek olarak haritaya basılıyor.
import folium
import json
d = json.loads(open("bus.json").read())
lines = {}
nodes = {}
for e in d['elements']:
if 'lat' in e:
nodes[e['id']] = (e['lat'],e['lon'])
for e in d['elements']:
if e['type'] == 'relation':
if 'name' not in e['tags']: continue
line = [m['ref'] for m in e['members']]
lines[e['tags']['name']] = line
coords = [nodes[m] for m in lines['43R Rumelihisarüstü-Kabataş'] if m in nodes]
m = folium.Map(location=[41,29], tiles='Stamen Terrain', zoom_start=10)
folium.PolyLine(locations=coords, color="blue").add_to(m)
m.save("43r.html")
Bir diger sorgu, mesela bir kordinat etrafindaki tum hatlar icin
[out:json];
(
node(around:10000,40.25450, 28.94227);
way(around:10000,40.25450, 28.94227);
);
out geom;
Eğer kısayol algoritmaları işletmek istersek, ki bunun için
düğüm/kenar verisini (yani durak/hat) bir sözlük içinde tutmak lazım,
bu sözlük d['elements']
listesini gezerken bir G
sözlüğü için
alttaki gibi yaratılabilir,
...
for i in range(len(e['members'])-1):
src,dest = e['members'][i]['ref'], e['members'][i+1]['ref']
if src not in G: G[src] = {}
G[src][dest] = 1
Not olarak ekleyelim, OSM açık bir veri kaynağı olarak katkıcıların her türlü veriyi kaydetmesini sağlar, tüm taban içinde kafeler, sinemalar, benzin istasyonları, restoranlar gibi pek çok bilgi bulunmaktadır. Mesela bir noktaya en fazla 2 km yakındaki kafeler için
q = """
[out:json];
node["amenity"~"cafe"](around:2000,40.958905, 29.1020804);
out center;
"""
Bir kutu içine düşen, mesela alt sol 30,20 üst sağ nokta 32,22 olsun, tüm kamp alanlarını görmek için
[out:json];
node["tourism"="camp_site"]
(30,20,32,22); out; (._;>;);
out;
Yürüyüş (hiking) yolları bulmak için, yine bir kutu içinde, ki kutu dort sayı ile tanımlanıyor, ilk iki sayı kutunun sol alt köşesinin enlem, boylam sayıları, son iki sayı ise kutunun sağ üst köşesinin enlem ve boylamı.
[out:json];
way["highway"~"path|track|footway|steps|bridleway|cycleway"]
(30,20,32,22);
out;
IETT
IETT API'si hakkında belgeler [2]'de, örnek kod [1]'de.
Baz URL ve başlangıç ayarları,
import pandas as pd, json
from zeep import Client
base = "https://api.ibb.gov.tr/iett"
pd.set_option('display.max_columns', None)
Mesela tüm duraklar için (biraz zaman alabilir)
client = Client(wsdl=base + "/UlasimAnaVeri/HatDurakGuzergah.asmx?wsdl")
data_text=client.service.GetDurak_json(DurakKodu="")
df=pd.DataFrame(json.loads(data_text))
Bu verinin tam halini şuradan [3] alabilirsiniz.
Tek bir durak için
client = Client(wsdl=base + "/UlasimAnaVeri/HatDurakGuzergah.asmx?wsdl")
data_text=client.service.GetDurak_json(DurakKodu="113252")
df=pd.DataFrame(json.loads(data_text))
print (df)
SDURAKKODU SDURAKADI KOORDINAT ILCEADI \
0 113252 MASLAK POINT (29.0209720086216 41.1085509961235) Sariyer
SYON AKILLI FIZIKI DURAK_TIPI ENGELLIKULLANIM
0 LEVENT VAR KAPALI WALLMODERN Uygun Degil
Bir hat üzerindeki tüm otobüslerin durumu (canlı veri),
client = Client(wsdl=base + "/FiloDurum/SeferGerceklesme.asmx?wsdl")
data_text=client.service.GetHatOtoKonum_json(HatKodu="15B")
df=pd.DataFrame(json.loads(data_text))
print (df)
kapino boylam enlem hatkodu guzergahkodu \
0 C-231 29.1032215 41.0488515 15B 15B_G_D0
1 C-301 29.0284016666667 41.035909 15B 15B_D_D0
2 C-299 29.0548008333333 41.0486603333333 15B 15B_D_D0
3 C-230 29.1017951666667 41.0361956666667 15B 15B_G_D0
4 C-229 29.086476 41.0254901666667 15B 15B_G_D0
5 C-296 29.079965 41.030994 15B 15B_D_D0
6 C-228 29.079794 41.0324728333333 15B 15B_G_D0
7 C-294 29.0963016666667 41.0258851666667 15B 15B_D_D0
8 C-227 29.0490996666667 41.0459533333333 15B 15B_G_D0
9 C-226 29.0331556666667 41.0386985 15B 15B_G_D0
10 C-232 29.1069303333333 41.0502151666667 15B 15B_G_D0
11 C-304 29.0160465 41.0276185 15B 15B_D_D0
12 C-234 29.106912 41.0501541666667 15B 15B_G_D0
13 C-297 29.0764325 41.0453085 15B 15B_D_D0
hatad yon \
0 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
1 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
2 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
3 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
4 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
5 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
6 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
7 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
8 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
9 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
10 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
11 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
12 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR ÜSKÜDAR CAMİİ ÖNÜ
13 TOPAĞACI MAHALLESİ / GÜZELTEPE - ÜSKÜDAR KURAN KURSU
son_konum_zamani yakinDurakKodu
0 2023-01-23 12:41:54 215682
1 2023-01-23 12:41:55 219271
2 2023-01-23 12:41:52 219333
3 2023-01-23 12:41:51 217141
4 2023-01-23 12:41:53 222173
5 2023-01-23 12:41:56 223352
6 2023-01-23 12:41:58 223351
7 2023-01-23 12:41:57 261901
8 2023-01-23 12:41:57 219322
9 2023-01-23 12:41:57 219282
10 2023-01-23 12:41:53 223901
11 2023-01-23 12:41:56 404091
12 2023-01-23 12:41:52 223901
13 2023-01-23 12:41:52 220111
O andaki tüm otobüslerin durumu,
client = Client(wsdl=base + "/FiloDurum/SeferGerceklesme.asmx?wsdl")
data_text=client.service.GetFiloAracKonum_json()
df=pd.DataFrame(json.loads(data_text))
print (df)
Operator Garaj KapiNo Saat Boylam \
0 OHO None A-001 12:42:58 29.045502
1 OHO None A-002 12:42:51 28.9921048333333
2 OHO None A-003 12:42:54 29.0243251666667
3 OHO None A-004 12:43:00 29.0538623333333
4 OHO None A-005 12:42:56 29.0375251666667
... ... ... ... ... ...
6585 IETT IKITELLIISLETTIRMEGARAJI2 T1104 12:42:58 28.953418
6586 IETT IKITELLIISLETTIRMEGARAJI2 T1105 12:42:54 28.7240793333333
6587 IETT IKITELLIISLETTIRMEGARAJI2 T1106 12:43:00 28.7477818333333
6588 IETT IKITELLIISLETTIRMEGARAJI2 T1107 12:42:54 28.7472726666667
6589 IETT IKITELLIISLETTIRMEGARAJI2 T1108 12:42:55 28.675459
Enlem Hiz Plaka
0 41.0786255 24 34 HO 1000
1 41.0373373333333 3 34 HO 1001
2 41.0480058333333 0 34 HO 1002
3 41.099348 15 34 HO 1003
4 41.1275815 0 34 HO 1004
... ... .. ...
6585 41.0119565 26 34KT9714
6586 40.9862843333333 0 34KT9728
6587 41.0615378333333 36 34LD0364
6588 41.1065363333333 0 34LD0369
6589 41.0843873333333 0 34CFK810
[6590 rows x 8 columns]
API'de olmayan bir veri çeşidi bir hattın geçtiği tüm durakların listesi. Hat üzerinde giden otobüslerin o anda yakın olduğu duraklar canlı olarak paylaşılıyor fakat statik hat verisi yok, önce şu durak sonra şu durak gibi..
Bazı Eksikler
API servisi yazılalı bayağı zaman geçmiş herhalde, SOAP diye bir paylaşım tekniği kullanılmış, bu sistem artık yerini daha basit, daha sağlam bir teknik olan REST tekniğine bıraktı. Basit Web URL'leri üzerinde gerekirse JSON ile veri alınıp verilip bilgi paylaşımı yapılabiliyor.
Ayrıca bazen hatalı durumlar ortaya çıktığında ekranda görülen ORA-
türü mesajlara bakınca arka plandaki veri tabanının Oracle olduğu
anlaşılıyor. Bu bir ticari tabandır, her ne kadar sağlam bir yazılım
olsa da, lisansları pahalıdır, kamu hizmeti veren bir servis açık
yazılım, bedava ve bir o kadar sağlam Postgresql tabanını kullanarak
daha iyi (ve ucuz) hizmet verebilir.
Kaynaklar
[1] https://github.com/hakanatak/dataibbgovtr_python
[2] https://data.ibb.gov.tr/dataset/3e32bb5d-2936-41eb-bdc7-65b843487e99/resource/6821f452-f6ff-49e9-940a-d4ebfc78f03e/download/iett-web-servis-kullanm-dokumanv.1.2.pdf
[3] https://drive.google.com/uc?export=view&id=1ATNV5qtW0gJoPuz2BKWBevakIe0mUiWF
[4] https://moovitapp.com/istanbul-1563/lines/14b/21021537/6467401/en
Yukarı