"""YÖK İstatistik Excel'lerinden src/lib/yok-istatistik.ts sabitini üretir. Kullanım (yılda bir, YÖK İstatistik Mart'ta yayımlayınca): python3 scripts/yok-istatistik-uret.py 2025-2026 Girdi: data/kaynak/yok-istatistik-{ogrenci,ogretim-elemani}-sayilari-.xls (istatistik.yok.gov.tr'den tarayıcıyla indirilir, API yok). Bağımlılık: xlrd. Kurallar: - Öğrenci = örgün öğrenci (BİRİNCİ Ö. + İKİNCİ Ö.), tüm düzeyler. UZAKTAN Ö. ve AÇIK Ö. dışarıda: açıköğretimli üç büyük üniversitede oranı anlamsız kılar ve kampüste okuyan öğrenciyi anlatmaz. - Öğretim üyesi = Profesör + Doçent + Doktor Öğretim Üyesi (YÖK tanımı). - Anahtar: /universite/[slug] sayfa slug'ı; yalnız yokatlas.db'de sayfası olan üniversiteler yazılır, eşleşmeyenler ekrana basılır. """ import sqlite3 import sys import unicodedata import re from pathlib import Path import xlrd KOK = Path(__file__).resolve().parent.parent DONEM = sys.argv[1] if len(sys.argv) > 1 else "2025-2026" def slugify(s: str) -> str: # src/lib/slug.ts turkishSlugify ile aynı kural. s = s.replace("I", "ı").replace("İ", "i").lower() for a, b in [("ı", "i"), ("ş", "s"), ("ğ", "g"), ("ü", "u"), ("ö", "o"), ("ç", "c"), ("â", "a"), ("î", "i"), ("û", "u")]: s = s.replace(a, b) s = unicodedata.normalize("NFKD", s) s = re.sub(r"[̀-ͯ]", "", s) s = re.sub(r"[^a-z0-9]+", "-", s) return s.strip("-") def sayfa_slug(ad: str) -> str: return slugify(re.sub(r"\s*\([^)]*\)\s*$", "", ad).strip()) def tamsayi(v) -> int: return int(float(v)) if v not in ("", None) else 0 def sayfa(ad: str): return xlrd.open_workbook( KOK / "data" / "kaynak" / f"yok-istatistik-{ad}-sayilari-{DONEM}.xls" ).sheet_by_index(0) # Öğrenci: sütun 1 ad, 4 öğrenim türü, 19 genel toplam (T). ogrenci: dict[str, int] = {} s = sayfa("ogrenci") for r in range(4, s.nrows): v = s.row_values(r) ad, tur = str(v[1]).strip(), str(v[4]).strip() if not ad or ad == "TOPLAM": continue if tur in ("BİRİNCİ Ö.", "İKİNCİ Ö."): k = sayfa_slug(ad) ogrenci[k] = ogrenci.get(k, 0) + tamsayi(v[19]) # Akademisyen: T sütunları Prof 6, Doç 9, Dr. Öğr. Üyesi 12, genel toplam 21. akademik: dict[str, tuple[int, int]] = {} s = sayfa("ogretim-elemani") for r in range(4, s.nrows): v = s.row_values(r) ad = str(v[1]).strip() if not ad or ad == "TOPLAM": continue uye = tamsayi(v[6]) + tamsayi(v[9]) + tamsayi(v[12]) akademik[sayfa_slug(ad)] = (uye, tamsayi(v[21])) db = sqlite3.connect(KOK / "data" / "yokatlas.db") sayfalar = {sayfa_slug(a) for (a,) in db.execute("SELECT DISTINCT universite FROM programs")} satirlar = [] for k in sorted(sayfalar): if k not in ogrenci or k not in akademik: continue uye, toplam = akademik[k] if ogrenci[k] == 0 or uye == 0: continue satirlar.append(f' "{k}": {{ ogrenci: {ogrenci[k]}, ogretimUyesi: {uye}, akademisyen: {toplam} }},') oranlar = sorted(ogrenci[k] / akademik[k][0] for k in sayfalar if ogrenci.get(k) and akademik.get(k, (0, 0))[0]) medyan = round(oranlar[len(oranlar) // 2]) eksik = sorted(sayfalar - {l.split('"')[1] for l in satirlar}) print(f"{len(satirlar)}/{len(sayfalar)} sayfa eşleşti. Eşleşmeyen {len(eksik)}:", file=sys.stderr) for k in eksik: print(" -", k, file=sys.stderr) for k in sorted(set(ogrenci) - sayfalar): print(" Excel'de var, sayfası yok:", k, file=sys.stderr) cikti = f'''// YÖK İstatistik {DONEM}: üniversite başına örgün öğrenci ve öğretim üyesi sayısı. // // ÜRETİLMİŞ DOSYA — elle düzenleme. Kaynak Excel'ler data/kaynak/ altında; // yeniden üretmek için: python3 scripts/yok-istatistik-uret.py {DONEM} // // Öğrenci = örgün (birinci + ikinci öğretim), tüm düzeyler; uzaktan ve açık // öğretim dahil değil. Öğretim üyesi = Prof. + Doç. + Dr. Öğr. Üyesi. // Anahtar: /universite/[slug] sayfa slug'ı. Burada olmayan üniversitenin // YÖK İstatistik satırı yok (KKTC/yurt dışı ya da öğrencisi/üyesi 0). export const YOK_ISTATISTIK_DONEM = "{DONEM}"; export const YOK_ISTATISTIK_KAYNAK_URL = "https://istatistik.yok.gov.tr/"; /** Sayfası olan üniversitelerde öğretim üyesi başına öğrencinin medyanı — kıyas çizgisi. */ export const OGRENCI_BASINA_UYE_MEDYAN = {medyan}; export type UniIstatistik = {{ /** Örgün öğrenci (ön lisans + lisans + yüksek lisans + doktora) */ ogrenci: number; /** Profesör + doçent + doktor öğretim üyesi */ ogretimUyesi: number; /** Tüm akademik personel (öğretim görevlisi ve araştırma görevlisi dahil) */ akademisyen: number; }}; export const YOK_ISTATISTIK: Record = {{ {chr(10).join(satirlar)} }}; /** Üniversite sayfa slug'ının YÖK İstatistik satırı; yoksa null. */ export function uniIstatistikBul(slug: string): UniIstatistik | null {{ return YOK_ISTATISTIK[slug] ?? null; }} /** Öğretim üyesi başına örgün öğrenci, tam sayıya yuvarlanmış. */ export function ogrenciBasinaUye(i: UniIstatistik): number {{ return Math.round(i.ogrenci / i.ogretimUyesi); }} ''' (KOK / "src" / "lib" / "yok-istatistik.ts").write_text(cikti, encoding="utf-8")