Bir sayfayı modele yedirme işini çoğumuz aynı şekilde çözüyoruz: file_get_contents, biraz strip_tags, üstüne iki regex, sonra gönder gitsin. Sonuç da hep aynı oluyor. Model cevabın yarısını üst menüden, çeyreğini KVKK metninden topluyor, geri kalanı da “Sepetim (0)” yazısından ibaret kalıyor.
Geçen aylarda modelin hafızasının Dory’ye dönmesini konuşmuştuk. Bu haftanın radar konusu aynı balık metaforunun öbür ucunda duruyor: modele ne hatırlatacağın değil, ne yedireceğin. Crawl4AI, HTML’i kılçığından ayırıp LLM’in önüne fileto koymayı iş edinmiş açık kaynak bir crawler. Kurdum, çalıştırdım, ölçtüm; aşağısı saha notu.
Crawl4AI nedir?
Crawl4AI, sayfayı gerçek bir tarayıcıyla (Playwright üzerinden Chromium) açıp içeriği doğrudan Markdown’a çeviren, Apache-2.0 lisanslı bir Python crawler’ı. Yani “HTML indir” değil, “sayfayı aç, çalıştır, oku, temizle, modele verilebilir hale getir” iddiası var.
Eylül 2026 itibarıyla depo 80,9 bin yıldızda, 8,4 bin çatalda ve 34 açık konuyla duruyor. Son sürüm 0.9.3, 31 Ağustos 2026’da çıkmış. Python 3.10 ve üzerini istiyor. Rakamları da sürümü de yazarken deposundan aldım; bu tür veriler üç ayda eskiyor, siz de okurken bir bakın.
Kurulum gerçekten üç komut mu?
Evet, üç komut. Temiz bir Python 3.11 ortamında pip install tarafı bende 22,5 saniye sürdü; asıl zaman crawl4ai-setup adımında tarayıcı indirilirken gidiyor.
pip install -U crawl4ai
crawl4ai-setup
crawl4ai-doctor
Buradaki ilk tuzak: crawl4ai-doctor, sağlık testi için gidip projenin kendi sitesini taramaya çalışıyor. Proxy arkasındaki makinemde bu adım net::ERR_TUNNEL_CONNECTION_FAILED ile düştü, çünkü ortam değişkenindeki proxy ayarını Python tarafı biliyor, Chromium bilmiyor. Kurumsal ağdaysanız proxy’yi tarayıcıya ayrıca söylemek gerekiyor: BrowserConfig(proxy="http://..."). Doctor’ın düşmesi kurulumun bozuk olduğu anlamına gelmiyor, ilk seferde adamı boşuna korkutuyor.
Komut satırı aracı da kutudan çıkıyor:
crwl https://example.com -o markdown-fit
Kılçık nerede ayrılıyor: raw_markdown ve fit_markdown
İşin can alıcı yeri burası ve varsayılan davranış yanıltıcı. -o markdown dediğinizde ya da result.markdown.raw_markdown okuduğunuzda menüyü, kenar çubuğunu, reklam alanını ve footer’daki altı linki aynen alıyorsunuz. Temizlik istiyorsanız içerik filtresini siz kurmak zorundasınız.
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
async def main():
md_gen = DefaultMarkdownGenerator(
content_filter=PruningContentFilter(threshold=0.48, threshold_type="fixed"),
options={"ignore_links": True},
)
cfg = CrawlerRunConfig(cache_mode=CacheMode.BYPASS, markdown_generator=md_gen)
async with AsyncWebCrawler(config=BrowserConfig(headless=True)) as crawler:
res = await crawler.arun("https://example.com", config=cfg)
print(len(res.markdown.raw_markdown), len(res.markdown.fit_markdown))
asyncio.run(main())
Ölçmek için kendi makinemde yerel bir sunucuya tipik bir e-ticaret ürün sayfası koydum: üst menü, filtre çubuğu, iki reklam bloğu, ürün metni ve altı maddelik footer. Sonuç:
| Aşama | Karakter | İçinde ne var |
|---|---|---|
| Ham HTML | 2.190 | Her şey |
raw_markdown | 1.268 | Ürün metni + menü + filtreler + footer |
fit_markdown | 805 | Yalnızca ürün başlığı, açıklama ve üç bölüm |
Sayfada 18 iç link vardı, filtrelenmiş çıktıda sıfırı kaldı. Tarama süresi yerel sayfada 0,26 saniye. Küçük bir sayfada bile ham çıktının üçte birinden fazlası gürültü; bunu bin ürünle çarpın, faturayı da bağlam penceresini de siz doldurmuş olursunuz.
Çok sayfalı tarama için BFSDeepCrawlStrategy, DFSDeepCrawlStrategy ve BestFirstCrawlingStrategy var; max_depth, max_pages ve FilterChain ile sınırlandırılıyor (derin tarama dokümantasyonu). Derinlik vermeden çalıştırıp sonra “neden hâlâ tarıyor” diye sormayın.
Ne zaman işe yarar, ne zaman yaramaz?
Yarar: İçeriği JavaScript ile gelen sayfalarda, toplu tarama gerektiren işlerde ve verinin dışarı çıkmasını istemediğiniz durumlarda. Her şey kendi sunucunuzda döndüğü için sayfayı üçüncü bir servise göndermiyorsunuz.
Yaramaz: Statik HTML’den tek sayfa metin çekeceksiniz diye makineye Chromium kurmanın anlamı yok; o iş trafilatura ile 30 MB bellekte biter. Paylaşımlı hostingde de unutun, tarayıcı çalıştırmanız gerekiyor. Bir de şu var: proje hızlı gidiyor ve API adları sürümler arasında oynuyor, dokümantasyondaki bazı sınıf adları depodaki kaynakla birebir tutmuyor. Sürümü sabitleyin.
Bakım ve güvenlik durumu: burası parlak değil
Lisans Apache-2.0, geliştirme aktif, sürümler sık geliyor. Buraya kadar iyi. Ama GitHub’daki güvenlik danışma listesinde yayımlanmış 10 kayıt var ve bunların dördü kritik: Chromium başlatma argümanı enjeksiyonuyla kimlik doğrulamasız uzaktan kod çalıştırma, dizin geçişiyle rastgele dosya yazma, AST sandbox kaçışı ve Docker API’sindeki çoklu açıklar. Tamamı kütüphanenin kendisinde değil, Docker API sunucusunda.
0.9.0 sürümü (18 Haziran 2026) bu yüzden “varsayılan olarak güvenli” diye duyuruldu ve kimlik doğrulamayı varsayılan açık hale getirdi. Buna rağmen dokümantasyonun Docker dağıtım sayfası hâlâ jwt_enabled: false örneğiyle duruyor. İkisi çelişiyor. Pratikteki karşılığı net: sunucuyu ayağa kaldırdıktan sonra kendi config.yml dosyanızı okuyun ve 11235 portunu internete açmayın. /playground ucu da dahil.
0.9.3 zaten bir güvenlik sürümü olarak etiketlenmiş; depo PDF işleme ve Docker Playground tarafında beş danışma kaydının kapatıldığını söylüyor. Yazdığım gün bu beş kaydın kendisi danışma listesinde ayrı ayrı yayımlanmış değildi, o yüzden detayını buraya yazamıyorum.
Bu işi kim yapıyor?
Crawl4AI’ı yazan ve sürdüren kişi GitHub’da UncleCode adıyla geçiyor. Deponun LICENSE dosyasındaki atıf notu da aynı adı veriyor: “This product includes software developed by UncleCode as part of the Crawl4AI project.” Profilinde Singapur ve Kidocode’un kurucusu olduğu yazıyor, X hesabı @unclecode. Arkada bir şirket görünmüyor; projeyi bir bakımcı ve topluluk taşıyor.
Yukarıdaki güvenlik tablosunu bu bilgiyle birlikte okuyun. Tek bakımcılı bir projede 80 bin yıldızlık ilgi, Docker sunucusunu internete açan binlerce kurulum demek; danışma kayıtlarının hepsinin orada toplanması tesadüf değil. Suçlama değil, kapasite meselesi. Kurarken hesaba katın.
Ticari taraf da saklanmamış. Kütüphane Apache-2.0 ve ücretsiz, API anahtarı istemiyor; ama dokümantasyonda “Crawl4AI Cloud API — Closed Beta” diye duyurulan barındırılan bir sürüm hazırlanıyor ve proje sponsorluk kabul ediyor. Bugün bedava olanın yarın ücretli bir kardeşi olacak. Kötü bir şey değil, sadece bilerek karar verin.
Alternatiflerle karşılaştırma
| Araç | Lisans | Yıldız | Şu iş için | Zayıf yanı |
|---|---|---|---|---|
| Crawl4AI | Apache-2.0 | 80,9 bin | JS’li sayfalar, toplu tarama, veri sizde kalsın | Docker sunucusunun güvenlik geçmişi ağır; tarayıcı bağımlılığı |
| Firecrawl | AGPL-3.0 (SDK’lar MIT) | 166,2 bin | Altyapıyla uğraşmadan hemen başlamak | Kendi sunucunuza kurarken AGPL yükü; barındırılan tarafı ücretli |
| Jina Reader | Apache-2.0 | 12 bin | Tek sayfa, hızlı deneme | Anonim trafik sert sınırlanıyor; sayfa üçüncü tarafa gidiyor |
| trafilatura | Apache-2.0 | 6,6 bin | Statik HTML’den ucuz metin çıkarımı | JavaScript ile gelen içeriği göremez |
Yıldız sayıları 22 Eylül 2026’da depolardan alındı. Yıldız kalite ölçüsü değil, ilgi ölçüsü; tabloyu lisans ve zayıf yan sütunlarından okuyun.
Bu araçların arkasındaki isimler de belli: Firecrawl’ı Firecrawl (eski adıyla Mendable AI) adlı ABD merkezli şirket geliştiriyor, Reader’ı Jina AI yayınlıyor, trafilatura ise Adrien Barbaresi‘nin akademik kökenli projesi. Dördünün de kodu açık; ikisinin arkasında şirket, ikisinde kişi var. Bu ayrım bakım sürekliliğini doğrudan etkiliyor.
Phalcon tarafında somut senaryo
PHP projesine Python crawler’ı gömmenin yolu yok, gerek de yok. Stok tahmini yazısında kurduğumuz desen burada da çalışıyor: Crawl4AI’ı kendi ağında bir servis olarak kaldır, Phalcon tarafından HTTP ile konuş.
docker run -d --name crawl4ai -p 127.0.0.1:11235:11235 --shm-size=1g unclecode/crawl4ai:latest
Port bağlamasındaki 127.0.0.1 yazım hatası değil, bilerek. Servisi dışarı açmıyoruz.
<?php
declare(strict_types=1);
namespace App\Service;
use RuntimeException;
final class Crawl4AiClient
{
public function __construct(
private readonly string $baseUrl = 'http://127.0.0.1:11235',
private readonly int $timeout = 60
) {
}
/**
* @param list<string> $urls
* @return array<string, mixed>
*/
public function crawl(array $urls): array
{
$payload = [
'urls' => $urls,
'browser_config' => ['type' => 'BrowserConfig', 'params' => ['headless' => true]],
'crawler_config' => ['type' => 'CrawlerRunConfig', 'params' => ['cache_mode' => 'bypass']],
];
$ch = curl_init($this->baseUrl . '/crawl');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error = curl_error($ch);
// PHP 8.5'te curl_close() deprecated; handle kapsamdan cikinca kapaniyor.
if ($body === false) {
throw new RuntimeException('Crawl4AI istegi basarisiz: ' . $error);
}
if ($status !== 200) {
throw new RuntimeException('Crawl4AI HTTP ' . $status . ' dondu.');
}
return json_decode((string) $body, true, 512, JSON_THROW_ON_ERROR);
}
}
Bunu bir service provider’a bağlayıp DI container’dan çağırdığınızda, tedarikçi sayfasından ürün açıklaması toplama ya da rakip fiyat sayfasını modele özetletme işi tek servise iniyor. Kuyruğa alın, doğrudan istek içinde çalıştırmayın; tarayıcı açan bir servis 60 saniyelik timeout’u rahatlıkla görür.
Kılçıksız balık mı, KVKK metni mi?
Crawl4AI’ın iyi yaptığı iş belli: sayfayı tarayıcıyla açıp modele verilebilir bir metne indiriyor ve bunu kendi sunucunuzda yapıyor. Kötü yaptığı iş de belli: Docker sunucusunu güvenli kurmayı size bırakıyor ve o kapıyı açık unutanlar için geçmişi kabarık.
Sürümü sabitleyin, portu dışarı açmayın, fit_markdown kullanın. Üçünü de yaparsanız modelinize kılçıksız balık gitmiş olur. Yapmazsanız, modeliniz KVKK metnini ezberler.
Ajanların bu tür araçlara standart bir kapıdan bağlanması meselesini ayrıca konuşmuştuk: MCP ve Plugged.in yazısı o tarafta duruyor.
Teknolojiyle kalın, portları kapalı tutun.