AI-crawl çağında blog mimarisi
Yapay zeka tarayıcıları çağında blog mimarisi: robots.txt ile bot yönetimi, makine okunabilir HTML, RSS/JSON besleme, arşiv sayfası ve kalıcı URL disiplini.
Yapay zeka tarayıcıları çağında blog mimarisi, birkaç yıl önce SEO diye konuştuğumuz konunun devamı değil; sorunun kendisi değişti. Eskiden tek soru vardı: Google beni buluyor mu? Şimdi siteme gelen botların önemli bir kısmı arama motoru değil. GPTBot, ClaudeBot, PerplexityBot, CCBot gibi kullanıcı ajanları içeriği ya bir modeli eğitmek ya da bir kullanıcının sorusuna anında cevap üretmek için çekiyor. Kendi sitemin sunucu günlüklerine baktığımda gördüğüm tablo bu; hangi botun ne sıklıkla geldiğini burada rakamla vermeyeceğim, çünkü her sitede farklı ve her ay değişiyor.
Bu yazıda kendi blogumu kurarken ve birkaç kez yeniden düzenlerken verdiğim kararları anlatacağım: robots.txt ile tarayıcıları nasıl yönettiğimi, içeriğin makine tarafından okunabilir olması için neye dikkat ettiğimi, RSS ve JSON beslemelerini neden hâlâ önemsediğimi, arşiv sayfalarını ve kalıcı URL disiplinini. Sonda da asıl tartışmaya geleceğim: neyi açık bırakmalı, neyi kapatmalı?
Baştan söyleyeyim, tek doğru cevap yok. Ama kararı bilinçli vermekle varsayılanlara bırakmak arasında büyük fark var. Varsayılan, çoğu zaman "her şey herkese açık" demek; bunu seçmek de bir karar, ama fark etmeden verilmiş olanı.
robots.txt ile tarayıcı yönetimi
robots.txt bir kapı değil, bir tabela. Protokol tamamen gönüllülük esasına dayanır; iyi niyetli botlar okur ve uyar, kötü niyetli olanlar hiç bakmaz. Bunu bilerek kullanmak gerekiyor: dosya, kimin ne yapmasını istediğinizi ilan ettiğiniz yerdir, güvenlik önlemi değildir.
Yapay zeka tarafında işin karışık kısmı, aynı şirketin birden fazla bot kimliğiyle gelmesi. OpenAI'ın GPTBot'u model eğitimi için tarar, OAI-SearchBot ise arama sonuçları için. Anthropic'in ClaudeBot'u ile Claude-User'ı benzer şekilde ayrışır. Google'da durum daha da ince: Googlebot'u engellerseniz aramadan düşersiniz; yapay zeka eğitimini reddetmek için ayrı bir kimlik olan Google-Extended'ı kullanmanız gerekir. Bu ayrımları bilmeden yazılan bir robots.txt ya gereğinden fazla kapatır ya da hiçbir şey kapatmaz.
Bir ayrıntı daha: bot, dosyada kendisiyle eşleşen en özel bloğu okur ve diğer blokları yok sayar. Googlebot için ayrı bir blok açtıysanız, herkese kapattığınız taslak klasörünü o blokta da tekrar kapatmanız gerekir. Kendi dosyamda benimsediğim yaklaşım şu:
- Arama ve keşif amaçlı botlara makaleler açık; yazıların bulunmasını istiyorum.
- Eğitim amaçlı botlar için karar makale bazında değil, site bazında; içeriği zaten herkese açık yazdığım için kapatmıyorum ama bunu bilinçli seçtiğimi dosyada yorum satırıyla ve tarihiyle not ediyorum.
- Taslak, önizleme ve arama sonucu sayfaları herkese kapalı; bunlar ne insana ne makineye faydalı.
- Sitemap adresi dosyanın sonunda; botun "burada ne var" sorusuna en kısa cevap bu.
# robots.txt — ekremdegirmenci.com
# Bir bot yalnızca kendisiyle eşleşen EN ÖZEL bloğu okur;
# bu yüzden kapalı alanlar her blokta tekrar edilir.
# Arama/keşif botları: makaleler açık, taslaklar kapalı
User-agent: Googlebot
User-agent: Bingbot
User-agent: OAI-SearchBot
Disallow: /taslak/
Disallow: /onizleme/
Disallow: /arama
Allow: /
# Eğitim amaçlı botlar: 2026-09 itibarıyla bilinçli olarak AÇIK.
# Kapatmak için aşağıdaki bloğun yorumunu kaldır.
# User-agent: GPTBot
# User-agent: ClaudeBot
# User-agent: CCBot
# User-agent: Google-Extended
# Disallow: /
# Diğer herkes
User-agent: *
Disallow: /taslak/
Disallow: /onizleme/
Disallow: /arama
Allow: /
Sitemap: https://ekremdegirmenci.com/sitemap.xml
Dosyanın gerçekten ne dediğini tahmin etmek yerine test etmek daha sağlıklı. Python'un standart kütüphanesindeki urllib.robotparser bunun için yeterli; hangi ajanın hangi yola girebildiğini tek tabloda görüyorsunuz:
from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url("https://ekremdegirmenci.com/robots.txt")
rp.read()
kontrol = [
("Googlebot", "/blog/articles/ornek-yazi"),
("Googlebot", "/taslak/yeni-yazi"),
("GPTBot", "/blog/articles/ornek-yazi"),
("GPTBot", "/taslak/yeni-yazi"),
("CCBot", "/"),
]
for ajan, yol in kontrol:
izin = rp.can_fetch(ajan, yol)
print(ajan.ljust(14), yol.ljust(32), "ACIK" if izin else "KAPALI")
Bir de gerçekte kimin geldiğine bakmak gerekiyor. robots.txt'de ne yazarsa yazsın, sunucu günlüğü asıl tabloyu gösterir. Günlük ve kaynak takibini nasıl betikleştirdiğimi PowerShell ile sistem izleme betiği yazısında anlatmıştım; aynı mantık web sunucusunun erişim günlüğüne de uygulanabilir: kullanıcı ajanına göre grupla, saatlik dağılıma bak, sürpriz bir isim görürsen robots.txt'ye dön.
İçeriğin makine tarafından okunabilirliği
Bir tarayıcıya kapıyı açmak yetmiyor; içeri girdiğinde anlayabileceği bir şey bulması gerekiyor. Burada gördüğüm en yaygın hata, içeriğin yalnızca JavaScript çalıştıktan sonra ekrana gelmesi. Googlebot bir süredir sayfaları tarayıcı gibi işliyor, ama yapay zeka botlarının çoğu ham HTML'i alıp geçiyor. Sunucu tarafında üretilmiş, JavaScript kapalıyken bile okunan bir sayfa bu yüzden hâlâ en güvenli seçenek. Kendi blogumu statik dosya olarak üretmemin bir nedeni de bu.
İkinci konu anlamlı işaretleme. Bir makine için sınıf adı "baslik" olan bir div ile gerçek bir h2 etiketi aynı şey değil. Şunlara dikkat ediyorum:
- Sayfada tek h1, altında hiyerarşik h2 ve h3; başlıklar görsel değil yapısal.
article,navvetimegibi anlamlı etiketler; yayın tarihi yalnızca metinde değil,datetimeözniteliğinde de dursun.- Kod blokları
preiçindecodevelanguage-pythongibi bir sınıf adıyla; dil bilgisi işaretlemede taşınsın. - JSON-LD ile
Articleşeması: başlık, yazar, tarih, açıklama. Şema, sayfanın ne olduğunu tek blokta söyler.
Üçüncüsü, sayfanın kendini tekrarlamaması. Her makale sayfasına eklenmiş devasa menüler, "ilginizi çekebilir" listeleri ve yorum blokları, ana içeriğin sayfadaki payını düşürüyor. Bir model bu sayfayı özetlemeye kalktığında yarısı gürültüyle geçiyor. Sade şablon burada estetik bir tercih değil, teknik gereklilik.
RSS ve JSON besleme: eski araç, yeni iş
RSS'in öldüğünü çok duydum; bana göre hiçbir zaman bu kadar işe yaramamıştı. Besleme, sitenizin içeriğini tarayıcıya "sayfayı kazı" demeden, temiz ve yapılandırılmış biçimde vermenin en ucuz yolu. Okuyucu uygulamaları, haber toplayıcılar, otomasyon araçları ve pek çok bot önce beslemeye bakıyor. HTML'i kazımaya göre hem sizin sunucunuza hem onların işlem gücüne daha az yük.
Kendi kurulumumda iki besleme üretiyorum: klasik RSS 2.0 ve JSON Feed. JSON Feed'i özellikle seviyorum, çünkü herhangi bir betikten okunması XML ayrıştırmaya göre çok daha kolay. Makale listesi zaten bir articles.json dosyasında durduğu için besleme üretimi birkaç satır; aynı betik sitemap ve arşiv sayfasını da aynı kaynaktan üretiyor:
import json
from datetime import datetime, timezone
SITE = "https://ekremdegirmenci.com"
with open("articles.json", encoding="utf-8") as f:
makaleler = json.load(f)
makaleler.sort(key=lambda m: m["tarih"], reverse=True)
feed = {
"version": "https://jsonfeed.org/version/1.1",
"title": "Ekrem Değirmenci — Blog",
"home_page_url": SITE + "/",
"feed_url": SITE + "/feed.json",
"language": "tr",
"items": [],
}
for m in makaleler[:50]:
url = f"{SITE}/blog/articles/{m['slug']}"
yayin = datetime.fromisoformat(m["tarih"]).replace(tzinfo=timezone.utc)
feed["items"].append({
"id": url,
"url": url,
"title": m["baslik"],
"summary": m["ozet"],
"date_published": yayin.isoformat(),
"tags": m.get("etiketler", []),
})
with open("feed.json", "w", encoding="utf-8") as f:
json.dump(feed, f, ensure_ascii=False, indent=2)
print(len(feed["items"]), "makale feed.json dosyasina yazildi")
Beslemeyi ürettikten sonra sayfa başlığında link rel="alternate" ile ilan etmeyi unutmamak gerekiyor; JSON Feed için application/feed+json, RSS için application/rss+xml türü kullanılıyor. Keşfedilebilir olmayan besleme yok sayılır. Beslemede tam metin mi özet mi vereceğiniz ise son bölümün konusu.
Arşiv sayfaları ve kalıcı URL disiplini
Bir tarayıcı için en değerli sayfa, sitedeki her şeye tek adımda ulaştıran sayfadır. Sayfalandırılmış, sonsuz kaydırmalı, "daha fazla yükle" düğmeli listeler bu işi görmüyor. Benim tercihim, tüm makaleleri tek bir düz HTML sayfasında listeleyen bir arşiv: başlık, tarih, bir cümle özet, bağlantı. Birkaç yüz makaleye kadar bu sayfa hafif kalıyor ve insan için de en hızlı gezinme yolu bu.
Arşivin yanına sitemap.xml geliyor; ikisi birbirinin yerine geçmez. Sitemap botlara lastmod ile "ne değişti" bilgisini verir, arşiv ise bağlamı. İkisini de aynı üretim adımında, aynı kaynaktan çıkarıyorum ki birbirinden ayrışmasınlar. Elle güncellenen iki liste er ya da geç birbirini yalanlar.
Kalıcı URL konusu ise en pahalı hatanın yaşandığı yer. Bir makalenin adresi değiştiğinde yalnızca arama sıralaması kaybolmuyor; o adresi öğrenmiş her model, her besleme okuyucu, her yer imi kırılıyor. Yapay zeka araçlarının kaynak gösterdiği bir çağda kırık bağlantı, "kaynak bulunamadı" demek. Uyduğum kurallar:
- URL'de tarih yok:
/blog/articles/slugbiçimi. Tarihi adrese koyduğunuz an, yazıyı güncellemek adresi yalanlamaya başlıyor. - Slug yalnızca küçük harf ASCII ve tire; Türkçe karakter, boşluk, büyük harf yok. Yayınlandıktan sonra slug asla değişmez, başlık değişse bile.
- Değişmek zorundaysa 301 yönlendirme, ve yönlendirme listesi kaynak kodun parçası; sunucu panelinde elle girilen bir kayıt değil.
- Her makalede
canonicalbağlantısı; aynı içerik iki adresten sunuluyorsa hangisinin asıl olduğu belli olsun.
Bu disiplin, altyapı tarafındaki adlandırma disipliniyle aynı mantık. Docker Compose proje adlandırma yazısında "ad betikle üretilir, elle yazılmaz" demiştim; slug için de aynısı geçerli. Elle verilen ad bir gün mutlaka değişir.
Neyi açmalı, neyi kapatmalı?
Asıl tartışma bu. İki uç görüş var: "her şeyi kapat, emeğimi eğitim verisi yapmasınlar" ve "her şeyi aç, görünürlük her şeydir". Benim vardığım nokta ikisi de değil; karar, içeriğin türüne ve yazma amacına göre değişiyor.
- Açık bırakıyorum: teknik yazılar, rehberler, herkese açık düşünceler. Bunları zaten bulunsun diye yazıyorum. Bir yapay zeka aracı sorunun cevabını verirken beni kaynak gösteriyorsa bu benim için kazanç.
- Kapatıyorum: taslaklar, önizleme adresleri, arama sonuçları, etiket sayfalarının sonsuz kombinasyonları, hata döndüren eski uç noktalar. Bunlar ne insana ne makineye değer katıyor; sadece tarama bütçesi yiyor.
- Kısıtlıyorum: beslemede tam metin yerine ilk birkaç paragraf ve bağlantı. Böylece keşif kolay, ama tam içerik için siteye gelmek gerekiyor. Bu, hem trafik ölçümünü korumak hem de kaynağın "burası" olduğunu netleştirmek için işe yarıyor.
Bir de hız meselesi var. Bazı botlar robots.txt'ye uyuyor ama saniyede onlarca istek atıyor. Bunun cevabı robots.txt değil; sunucu ya da CDN katmanında kullanıcı ajanına göre istek sınırı. robots.txt tabela, hız sınırı kapıdır; ikisini karıştırmamak gerekiyor.
Son bir nokta: bu kararların hiçbiri kalıcı değil. Bot listesi sık değişiyor, yeni kullanıcı ajanları çıkıyor, bazıları kimlik değiştiriyor. Ben robots.txt'yi kaynak kodda tutuyorum ve değişiklik tarihlerini yorum satırında bırakıyorum; altı ay sonra "bunu neden kapatmıştım" sorusunun cevabı dosyanın içinde duruyor.
Toparlarsam: yapay zeka tarayıcıları çağında iyi bir blog mimarisi, birkaç yıl önce iyi olan mimariyle büyük ölçüde aynı; fark, artık varsayılanlara bırakılamayacak kadar çok karar olması. robots.txt'de bot ailelerini ayırın, içeriği JavaScript'siz okunur tutun, besleme üretin, düz bir arşiv ve değişmeyen adresler verin. Gerisi tabela ile kapıyı karıştırmamakta. Kendi siteniz için hangi botlara ne göstereceğinize karar vermek ya da mevcut kurulumu birlikte gözden geçirmek isterseniz, ana sayfadaki /#contact bölümünden bana ulaşabilirsiniz.