2026’da BeautifulSoup: En Dost Canlısı HTML Ayrıştırıcı Aynı Zamanda En Yavaş Olanı mı? (12–17 Kat)

Son güncelleme: July 17, 2026
2026’da BeautifulSoup: En Dost Canlısı HTML Ayrıştırıcı Aynı Zamanda En Yavaş Olanı mı? (12–17 Kat)
AI Özeti
Bu inceleme, BeautifulSoup’u Python’daki en erişilebilir HTML ayrıştırıcı olarak ele alıyor ve bu dost canlılığın net maliyetini ölçüyor. bs4’yi C tabanlı ayrıştırıcılarla hız, bozuk HTML toleransı, CSS seçici kapsamı, nesne tutma davranışı ve kodlama kurtarma açısından karşılaştırıyor. Makale, BeautifulSoup’un 12 ila 17 kat arasında değişen oranlarda ciddi biçimde daha yavaş olduğunu gösterirken, geliştiricilerin neden hâlâ onu tercih ettiğini de açıklıyor: okunabilir API’ler, affedici ayrıştırma, güçlü soupsieve seçici desteği ve dağınık tek seferlik kazıma işleri için mükemmel ergonomi. Hız vergisinin ne zaman kabul edilebilir olduğunu, ne zaman daha hızlı bir ayrıştırıcının daha doğru mühendislik seçimi olduğunu anlatan pratik bir rehber.

BeautifulSoup, Python’da bir web sayfasını ilk kez kazıyanların neredeyse hepsinin elini uzattığı kütüphanedir ve ciddi HTML ayrıştırıcılar arasında gerçekten de en yavaş olanıdır. Bu iki ifade de doğrudur; ikisi de eleştiri değildir. Asıl ilginç olan şu: “en yavaş” ifadesi, bir his değil, ölçülebilir ve satın alınabilir bir değere dönüşüyor.

bs4’yi (beautifulsoup4, sürüm 4.15.0, Haziran 2026’da yayımlandı, MIT lisanslı) hem yeni yetenek testlerinden hem de aynı benchmark düzeneğinden yeniden kullanılan zamanlama verilerinden geçirince tablo tutarlı çıktı: en dost canlısı API ve sahadaki en güçlü hata toleransı karşılığında yaklaşık bir büyüklük mertebesi hız kaybı ödüyorsunuz. Bu takasın akıllıca olup olmadığı tamamen iş yükünüze bağlı; bu inceleme de bu yüzden meselenin iki tarafını birlikte ele alıyor.

BeautifulSoup Aslında Nedir, Nedir Değildir?

Çoğu eğitim içeriği en önemli kısmı atlar: BeautifulSoup HTML ayrıştırmaz. O bir sarmalayıcıdır. Perde arkasında dokümanınızı üç gerçek ayrıştırıcıdan birine verir — Python’un yerleşik html.parserı, lxml ya da html5lib — ardından onların ürettiği ağacı tek, çok kullanışlı bir gezinme ve arama API’siyle sarar. bs4’nin işi ayrıştırmak değil; ortaya çıkan yapıyı rahatça dolaşılabilir hâle getirmektir.

Kütüphanenin yazarı onu bir zamanlar “screen-scraping library” diye tarif eder; yaklaşım başından beri aynıdır: tarayıcının yüzünü buruşturacağı kadar bozuk HTML’ye bile yöneltin, yine de istediğiniz veriyi çıkarır. Bu ün hak edilmiştir; bir küçük istisna var, birazdan ona geleceğiz.

Başlamadan önce netleştirmeye değer birkaç bilgi:

AlanDeğer
Paketbeautifulsoup4 (bs4 olarak import edilir)
Test edilen sürüm4.15.0 (2026-06-07 yüklendi)
Python gereksinimi>=3.7.0
LisansMIT
Resmî ana sayfacrummy.com/software/BeautifulSoup
Kaynak + hata takipçisiLaunchpadGitHub değil
Bakım durumuAktif (Haziran 2026’da 4.15.0, son bir yılda altı sürüm)

“GitHub değil” notu göründüğünden daha önemli. bs4, crummy.com ve Launchpad üzerinde yaşayan 20 yıllık bir kütüphane; dolayısıyla alışılmış GitHub yıldız sayısı hissi burada işe yaramaz. Sağlığını sürüm sıklığına bakarak değerlendirin; bu ölçüte göre gayet canlı.

Lisans konusunda küçük ama önemli bir ayrıntı var, özellikle uyum ekibine hesap vermek zorunda olanlar için: sarmalayıcının kendisi MIT lisanslıdır; fakat “bs4 kullanmak” aslında bağımlılık ağacınıza hangi arka ucu kurduğunuza göre değişir. html.parser Python standart kütüphanesinin parçasıdır (PSF lisansı, ekstra bağımlılık yok). lxml BSD lisanslıdır, ama libxml2/libxslt üzerine oturur — yani derlemeniz ya da önceden hazırlanmış tekerlekten (wheel) çekmeniz gereken harici bir C bağımlılığıdır. html5lib saf Python ve MIT’dir. En temiz bağımlılık ayak izi istiyorsanız yerleşik html.parser bunu sağlar — ki tesadüfen, en büyük yakalama da onda vardır. Az sonra.

Hız Vergisi, Sayıyla

Önce rakamı koyalım; çünkü manşet bu ve bunu saklamak dürüst olmaz. Gerçekçi bir “ayrıştır-sonra-çıkar” işinde — string’i ayrıştır, her <h3 class="title"> öğesini ve her <a href> bağlantısını çek — BeautifulSoup bu karşılaştırmada en yavaşıdır ve aradaki fark küçük değildir.

BeautifulSoup hız vergisi: 232 ms karşısında 15 ms C ayrıştırıcıları

Bu zamanlamalar selectolax benchmark düzeneğinden yeniden kullanıldı (aynı makine, aynı 3 çalıştırmalı yöntem, 2026-07-13 itibarıyla); bu inceleme CPU çakışmasını ve tekrar işi önlemek için kendi zamanlama benchmark’ını yeniden çalıştırmıyor. Milisaniye cinsinden p50 medyan gecikme:

Sayfa boyutubs4 (html.parser)bs4 (lxml)selectolax-Lexborlxmlbs4-hp ne kadar yavaşbs4-lxml ne kadar yavaş
1 KB0.3230.2810.0270.03612.0x10.5x
10 KB2.0491.7050.1600.16612.8x10.7x
100 KB20.59916.5401.4641.42314.1x11.3x
1 MB232.558181.85514.90114.17715.6x12.2x
10 MB2788.7462261.557159.935172.93317.4x14.1x

Yani bs4(html.parser), selectolax-Lexbor gibi bir C ayrıştırıcıdan yaklaşık 12–17x daha yavaş; lxml arka ucuna geçmek bile bunu ancak 10.5–14x seviyesine indiriyor — hâlâ tam bir büyüklük mertebesi geride. Bunun nedeni bir hata değil, yapısal: ayrıştırmayı hangi arka uç yaparsa yapsın, bs4 her tek düğüm için tam bir Python nesnesi (Tag ya da NavigableString) oluşturur. Bu nesneleştirme katmanının maliyeti, C ayrıştırıcılarının hiç ödemediği bir vergidir.

Sayfalar büyüdükçe çarpanın artmasına dikkat edin — 1 KB’de 12.0x, 10 MB’de 17.4x. Bu da sorunun sabit bir başlangıç maliyeti olmadığını, sonradan amorti edebileceğiniz bir masraf olmadığını gösterir. Bu, oluşturduğunuz düğüm sayısıyla doğrusal büyüyen düğüm başı bir vergidir.

Şimdi bakış açısını değiştirelim; çünkü “10x daha yavaş” ifadesi çoğu zaman olduğundan korkunç duyulur. 1 MB’lik bir sayfada fark 232 ms ile 15 ms arasındadır. İşiniz “birkaç yüz ila birkaç bin, birkaç yüz KB’lik sayfayı kazımak” ise bu mutlak fark görünmezdir — hissetmezsiniz, ortadan kaldırmaya çalışmak size hiçbir şey kazandırmaz. İşiniz milyon sayfalık bir boru hattıysa aynı oran, işin bitmesiyle bitmemesi arasındaki farktır. Aynı sayı, ters sonuç. Benchmark’a değil, gerçek hacminize bakın.

Hayır, Arka Ucu Değiştirmek Bunu Çözmüyor

Yaygın bir yanlış inanış var: bs4’e lxml arka ucunu verirseniz lxml hızını alırsınız. Alamazsınız; nedenini bilmek önemli. 100.000 düğümlük bir CSS sorgusunda (her <a> öğesini seçip href’ini okumak, ağaç önceden oluşturulmuşken) verim farkı çok nettir:

AyrıştırıcıSorgu p50Düğüm/sn
lxml33.30 ms3,002,646
selectolax-Modest34.19 ms2,924,550
selectolax-Lexbor39.46 ms2,534,027
bs4 (lxml)250.56 ms399,111

bs4(lxml) saniyede yaklaşık 399.000 düğüm işliyor — kendi arka ucu lxml olmasına rağmen, üç C motorundan kabaca 6.3–7.5x daha yavaş. Arka uç ağaç oluşturmayı hızlandırır. Ama sorgulama ve dolaşma hâlâ soupsieve üzerinden bs4 Tag nesnelerine gider; eşleşen her düğüm yine Python içinde kutulanır. Dolayısıyla “bs4’ye lxml verince lxml kadar hızlı olur” zihinsel modeli yanlıştır: arka uç yalnızca bir aşamayı hızlandırır; en yavaş aşama zaten o aşama değildir.

Bellek kullanımı ve soğuk başlangıç da maliyete eklenir. 10 MB’lik bir dokümanda bs4, selectolax ya da lxml’e göre yaklaşık 1.5–1.75x daha fazla çalışan bellek kullanır (218–226 MB karşısında 129–145 MB) — aynı kök neden, düğüm başına bir Python nesnesi. Ayrıca bs4 içe aktarımı lxml.html’e göre yaklaşık 33.4 ms sürer; bu da 2.36x daha yavaştır. Uzun süre çalışan bir süreç için bu küçük bir ayrıntıdır; ama sürekli soğuk başlayan bir CLI aracı ya da serverless fonksiyon için, bilinmesi gereken gerçek bir maliyettir.

Neden Daha Fazla Thread Kurtarmaz

Yavaş, CPU ağırlıklı bir işte içgüdünüz “thread ekle gitsin” ise, bs4 bu içgüdüyü cezalandırır. 1 MB’lik bir sayfa 48 kez ayrıştırılırken tek thread ile dört thread karşılaştırması:

Ayrıştırıcı1 thread4 threadHızlanma
selectolax-Lexbor0.563 s0.159 s3.54x
lxml0.459 s0.378 s1.21x
bs4 (lxml)6.945 s26.842 s0.26x

Alt satırı iki kez okuyun. Dört thread, bs4’ü hızlandırmak yerine yaklaşık 3.9x daha yavaş yaptı. Deneysel sinyal şu: büyük ihtimalle GIL’i bırakmıyor; bs4’nin ağaç oluşturma kısmı saf Python olduğu için Global Interpreter Lock altında seri çalışıyor ve üzerine thread yığmak, gerçekten paralel çalışamayan bir işe yalnızca zamanlama yükü ekliyor. selectolax yaklaşık 3.5x hızlanmasını C çekirdeğinin kilidi bırakması sayesinde alıyor; bs4’de böyle bir alan yok.

Free-threading döneminde pratik çıkarım şu: BeautifulSoup’u paralelleştirmeniz gerekiyorsa thread yerine multiprocessing (ProcessPoolExecutor) kullanın. selectolax ve lxml thread’lerle ölçeklenebilir; bs4 ölçeklenemez. Bir not: bu sonuç tek bir thread sayısında (4) ve tek bir sayfa boyutunda (1 MB) yapılan tek bir gözleme dayanıyor; “GIL’i tutuyor” mekanizması, kilidi hangi kod yolunun tuttuğunu enstrümante ederek doğruladığım bir şey değil, çalışma süresine bakarak çıkardığım bir hipotez. Yön net; tam mekanizma ise geçici.

Varsayılan Arka Uç Tuzağıdır. Bunu Önce Okuyun.

Bu incelemeden tek bir şey alacaksanız, onu alın. İkinci argüman vermeden kullanılan düz BeautifulSoup(html), varsayılan olarak html.parserı kullanır; html.parser ise HTML5’in isteğe bağlı kapanış etiketi kurallarını uygulamaz. Bu kulağa akademik gelebilir; ta ki verinizi sessizce bozuncaya kadar.

BeautifulSoup arka uç tolerans matrisi: html.parser 12/15, lxml ve html5lib 15/15

Önceden tanımlanmış, arka uçtan bağımsız yapısal bir doğrulama ile 15 kasıtlı bozuk HTML örneğini üç arka ucun tamamından geçirdim (böylece sonucu sonradan kimse seçemiyor). Skorlar:

Arka uçBeklentiyi karşılayan / 15
lxml15
html5lib15
html.parser12

Üç hatanın kökü aynı. Kapalı olmayan bir tablo düşünün: <table><tr><td>a<td>b<tr><td>c<td>d</table>. html.parser altında çıkarılan hücre metni ['abcd','bcd','cd','d'] olarak gelir — her <td> kendinden sonrasını yutar; çünkü ayrıştırıcı hücreleri kapatmak yerine iç içe geçirir. lxml ve html5lib ise doğru şekilde ['a','b','c','d'] döndürür. Düz liste öğeleri de aynı davranır: <li>a<li>b<li>c ifadesi html.parser altında iç içe ['abc','bc','c'] üretir; diğer ikisi ise temiz ['a','b','c'] verir. Yinelenen öznitelikler de tersine döner — <div id="first" id="second"> ifadesi html.parser altında "second"ı tutar; lxml/html5lib altında "first"i tutar; oysa HTML5 spesifikasyonu ilkini korumanızı söyler.

Bunu sadece can sıkıcı olmaktan çıkarıp tehlikeli yapan şey şu: hata vermeden olur. Düşünmeden BeautifulSoup(html) kullanan ve kapanmamış bir tabloya ya da listeye denk gelen bir kazıyıcı — eski sitelerde, elle yazılmış HTML’de ve kapanış etiketi unutulmuş şablonlarda bu çok yaygındır — bitişik hücre metinlerini tek alanda birleştirir, size kirli veri verir ve tek bir kez bile şikâyet etmez. Çözüm tek bir argüman: BeautifulSoup(html, "lxml") ya da BeautifulSoup(html, "html5lib").

html.parser adına hakkını teslim edelim: diğer 15 bozuk örneğin 12’sinde üç arka uç da aynı sonucu verdi — <b><i></b></i> gibi yanlış iç içe geçmiş etiketler, eksik html/body iskeleti, tırnaksız öznitelikler, yalnız kalan kapanış etiketleri, kapatılmamış yorumlar, iç içe formlar, karışık büyük/küçük harf ve daha fazlası. bs4’nin toleransı gerçekten de genel olarak güçlü; ayrışmanın yoğunlaştığı yer neredeyse tamamen isteğe bağlı kapanış etiketi ailesi. Üstelik bunların hiçbiri yeni bir keşif değil — bs4’nin kendi “Differences between parsers” dokümantasyonu zaten html.parserın “less lenient” olduğunu açıkça söyler. Bozuk HTML matrisinin eklediği şey, bu “daha az hoşgörülü” hâlin hangi tekrar üretilebilir örneklerde yanlış çıktıya dönüştüğüdür.

Ne Kaybetmezsiniz: API ve CSS, En Güzel Kısımlar

Öyleyse bs4 yavaş, tek thread’li ve varsayılan arka uç tuzağı var. İnsanlar yine de onu tercih ediyor; çünkü “dost canlısı” tarafı gerçekten var — ve testlerde bunu doğruladık.

BeautifulSoup soupsieve CSS kapsamı 41/41 artı 20/20 ile önde

Arama, CSS, ağaç gezintisi, metin çıkarımı ve DOM değiştirme kapsayan 29 API denemesi yaptım. 29’unun 29’u da geçti; her denemenin sonucu, göz kararıyla değil beklenen değerle gerçek dönüşün karşılaştırılmasıyla hesaplandı. Bu yeteneklerin ikisi, C ayrıştırıcıların sunmadığı ergonomik avantajlar:

  • find / find_all içinde fonksiyon predikatları. soup.find(lambda t: t.name == "a" and "btn" in t.get("class", [])) yazıp karmaşık bir koşulu tek satır Python ile ifade edebilirsiniz — “her şeyi seç, sonra filtrele” şeklinde iki adımlı bir çözüm gerekmez.
  • İsimlendirilmiş, çift yönlü ağaç gezintisi. .parent, .next_sibling, .find_parent, .stripped_strings, .descendants — dolaşım ifadeleri İngilizce gibi okunur ve iki yöne de gider. selectolax bunların bazısı için birkaç adım ister ya da hiç sunmaz.

İşte “geliştirici zamanını satın alır” tarafının somut hâli. Pazarlama değil; 29 yeşil işaret.

Adil bir inceleme iki tarafı da anmalıdır; not edilmesi gereken iki tuzak var. Birincisi, boolean öznitelikler: <input disabled> bs4’de disabled için boş string "" döndürür (selectolax None döndürür). İkisi de falsy’dir; dolayısıyla if node.get("disabled") ifadesi, aslında iki kütüphanede de mevcut olan boolean bir özniteliği sessizce kaçırır — güvenli kontrol "disabled" in tag.attrs olmalıdır. İkincisi, get_text(strip=True) düğüm metinlerini ayırıcı olmadan birleştirir; yani strip sonrası "...with " + "link1" ifadesi "withlink1" olur. Kelime sınırları gerekiyorsa separator=" " verin. Bu tuzakların hiçbiri bs4’ye özel değildir; ikisi de kütüphaneler arası ortak ayak sürçmeleridir.

Ve şimdi çoğu kişiyi şaşırtan kısım: bs4 seçmek CSS kapsamından ödün vermek değildir. CSS motoru soupsieve, bu karşılaştırmadaki en eksiksiz uygulamadır. 41 durumlu temel matriste (selectolax düzeneğinden yeniden kullanıldı) soupsieve 41/41 aldı — sahadaki tek tam skor; selectolax-Lexbor’ın 39/41’inin ve cssselect’in (lxml/parsel) 37/41’inin önünde. Ardından dokümantasyonun desteklediği 20 ek genişletilmiş durumu çalıştırdım ve 20/20 geçti; Lexbor’ın düpedüz reddettiği seçiciler dahil: :lang(en), yalnızca soupsieve’ye özgü :-soup-contains('featured'), :is(), :where() ve :has(> a). Gerçek eksikler yalnızca XPath (soupsieve sadece CSS’tir) ve Scrapy uzantısı olan parsel’in ::text / ::attr() sözde öğeleridir. XPath dünyasında yaşıyorsanız, bu geçiş can yakar.

Bu bölümün hükmü net: BeautifulSoup seçerek ödediğiniz bedel hızdır. API ergonomisi değildir; CSS kapsamı hiç değildir.

Üretimde Bütçelenmesi Gereken İki Önemli Tuzağa Dikkat

Varsayılan arka uç dışında, uzun çalışan ya da UTF-8 dışı iş yüklerinde özellikle iki davranış başınızı ağrıtabilir.

Referans Döngüleri: Uzun Döngülerde decompose() Çağırın

Her bs4 Tag nesnesi hem ebeveyne hem de çocuklarına referans tutar; bu da bir referans döngüsü oluşturur. CPython’un referans sayımı böyle bir döngüyü tek başına geri kazanamaz — bunu jenerasyonel çöp toplayıcı yapar. Bunun ne kadar önemli olduğunu görmek için, GC kapalıyken ağacı 300 kez oluşturup sildim ve hâlâ bellekte duran Tag nesnelerinin sayısını saydım:

BeautifulSoup referans döngüleri GC kapalıyken 120.900 nesne, açıkken 0 nesne tutuyor

Senaryodel sonrası tutulan Tag sayısı
GC kapalı120,900 (300 döngü, hiçbir şey geri kazanılmadı)
GC açık26,598 (jenerasyonel GC döngü ortasında çalıştı)
Zorunlu gc.collect() sonrası0 (hepsi geri kazanıldı)
Döngüsüz kontrol (string listesi, GC kapalı)delta 0

GC kapalıyken del soup hiçbir şeyi geri kazanmadı — 120.900 nesnenin tamamı bellekte kaldı; çünkü referans döngüsü, referans sayımını boşa çıkarıyor. Tek bir gc.collect() hepsini temizledi. Döngüsüz kontrol grubu (döngüsü olmadığı bilinen düz bir string listesi) sıfır delta verdi; bu da birikimin ölçüm gürültüsünden değil bs4’nin döngüsünden kaynaklandığını kanıtlıyor. bs4’nin kendi dokümanı da nesnelerin “densely interconnected ... exactly the sort a garbage collector would have trouble with” olduğunu söyler; yani bu belgelenmiş davranıştır. Testin eklediği şey, tutulan nesne sayısı ve collect() çağrısının bunu sıfırladığının kanıtıdır.

Pratik kural şudur: Çok sayıda büyük sayfayı sıkı döngüde ayrıştıran bir boru hattında, eğer kodunuz (ya da yüksek verimli bir ayarınız) GC’yi kapatıyorsa veya yeterince sık tetiklemiyorsa, bs4 ağaçları ortada asılı kalır ve bellek yükselir. Her sayfadan sonra soup.decompose() çağırın — bs4 bunu tam da döngüyü kırıp erken geri kazanım sağlamak için sunar. selectolax ve lxml’in C ağaçlarında bu problem yoktur.

Kodlama: UnicodeDammit, bs4’nin Sessiz Avantajı

bs4, hızlı ayrıştırıcılarda olmayan bir bileşenle gelir: UnicodeDammit. Bu bileşen bir dokümanın kodlamasını sezerek onu otomatik olarak Unicode’a dönüştürür. Ona 8 durumlu bir “bildirilen kodlama vs. gerçek kodlama” matrisi verdim:

BeautifulSoup UnicodeDammit 8 kodlama durumunun 5’ini kurtarıyor

DurumGerçek kodlamaUnicodeDammit tahminiKurtarıldı mı?
utf8_no_declutf-8utf-8Evet
utf16_bomutf-16utf-16leEvet
gbk_chinesegbkgb18030Evet (üst küme)
shiftjisshift_jiscp932Evet (üst küme)
latin1_declared_utf8latin-1 (utf-8 olarak bildirilmiş)iso-8859-1Evet (yalanı yok saydı)
latin1_no_decllatin-1cp720Hayır
cp1252_no_declcp1252cp862Hayır
utf8_declared_latin1utf-8 (latin-1 olarak bildirilmiş)iso-8859-1Hayır (yalanı takip etti)

Sekiz durumun beşinde kurtarma sağlandı. UTF-8, BOM’lu UTF-16, GBK, Shift-JIS ve yanlış etiketlenmiş latin-1 doğru döndü; üst küme tahminleri (GBK→gb18030, Shift-JIS→cp932) yine de düzgün çözüldü. İki başarısızlık türü bilmeye değer: kısa latin-1/cp1252 bayt örnekleri DOS kod sayfaları olarak yanlış tahmin edilir; çünkü istatistiksel algılayıcı kısa girdilerde güvenilir değildir ve DOS kutu çizgisi karakterleri Latin-1’in kod noktalarıyla örtüşür. Bir de <meta charset> beyanı düpedüz yanlışsa, UnicodeDammit beyana güvenir. bs4 dokümanı da bunu açıkça belirtir — örnek o kadar kısa olabilir ki “Unicode, Dammit can't get a lock on it”; ayrıca daha çok veri daha iyi tahmin demektir.

selectolax ile karşılaştırınca, onun UTF-8 dışı baytları sessizce bozup bunları sizin kendiniz çözmenizi beklemesi yerine, bs4 en azından kodlamayı tahmin etmeye çalışır ve çoğu zaman başarılı olur. Ama bu bir garanti değildir. Bilinen bir kodlama varsa tahmin etmeyin; açık yazın: BeautifulSoup(bytes, from_encoding="...").

Arka Uçlar Gerçek Sayfalarda Hiç Ayrışıyor mu?

Bozuk HTML matrisi, arka uçların kasıtlı bozuk girdide ayrıştığını gösteriyor. Mantıklı bir sonraki soru, bunun gerçek dünyada önemli olup olmadığıdır; bu yüzden üç arka ucun tamamını BBC, Wikipedia, Craigslist, MDN, old.reddit, Python docs, Hacker News, Books to Scrape, webscraper.io, whitehouse.gov ve JS ile render edilen bir alıntılar sayfası gibi 11 gerçek çekilmiş sayfa üzerinde çalıştırıp bağlantı, başlık ve görsel sayılarını karşılaştırdım.

Üçü de 11 sayfanın tamamında aynı sonucu verdi. Sıfır ayrışma. Bu da tuzak bölümündeki arka uç anlaşmazlığının yalnızca kasıtlı olarak bozuk HTML’de ortaya çıktığı anlamına geliyor; modern bir üretim sitesi yeterince düzgün yapılandırılmışsa — “karışık” olsa bile — arka uç seçimi çıkaracağınız şeyi değiştirmiyor. Pratik okuma şu: ana akım, düzgün biçimlenmiş siteler için html.parser gayet yeterlidir ve bağımlılığı ortadan kaldırır. Arka uç seçimi yalnızca belirgin biçimde standart dışı, elle yazılmış ya da eski HTML kazırken sonuçlarınızı oynatmaya başlar; o zaman da lxml ya da html5lib’e geçersiniz.

Bu çalışmadan bir kenar notu daha, çünkü gerçek bir uç durum. MDN sayfasında bir <template> öğesi bulunuyordu ve tüm bs4 arka uçları 508 bağlantı döndürdü — yani bs4, <template> içeriğini ana ağaca düzleştiriyor. Bu, bs4’yi lxml ile aynı tarafa, selectolax-Lexbor’ın karşısına koyuyor; çünkü selectolax HTML5 spesifikasyonunu sıkı biçimde izliyor (<template> bir inert DocumentFragmenttır) ve içindeki 11 bağlantıyı sessizce atarak 497 döndürüyor. Yani bs4, <template> içindeki veriyi yakalar — kullanışlıdır; ama tarayıcının asla render etmeyeceği “hayalet” içeriği de alabilirsiniz. Davranışlardan hiçbiri yanlış değildir; bunlar farklı spesifikasyon yorumlarıdır ve hangisini aldığınızı bilmelisiniz.

BeautifulSoup Nereye Uyar, Nereye Uymaz?

Bütün bunları tek bir 0–100 puana sıkıştırmak yerine — ki bu tam da önemli takasları gizlerdi — işte boyut bazlı puan kartı; her satır için kısa bir notla birlikte:

BoyutTestlerin bulgusuOkuyucu notu
Kurulum / ilk çalıştırmaSaf sarmalayıcı, tarayıcı/kurulum yok; html.parser sıfır bağımlılık; tümü önceden hazırlanmış wheel’lerlxml arka ucu C bağımlılığı ister
C ayrıştırıcılara göre hız12–17x daha yavaş (html.parser) / 10.5–14x (lxml arka ucu), tüm boyutlardaTek düzeneğe dayanıyor; selectolax verisi yeniden kullanıldı
CSS sorgu verimi100k düğümde ~6–7.5x daha yavaş; lxml arka ucu bunu kurtarmıyorYeniden kullanıldı; Python Tag vergisini öder
Bellekselectolax/lxml’den 1.5–1.75x fazla; en ağır olanYeniden kullanıldı; RSS ile ölçüldü
İçe aktarma soğuk başlangıcı2.36x daha yavaş (33.4 vs 14.1 ms)Yeniden kullanıldı; küçük ama gerçek
Thread ölçeklenmesibs4-lxml, 4 thread’de ~3.9x daha yavaş (GIL tutuyor)Tek gözlem; multiprocessing kullanın
API ergonomisi29/29 deneme; fonksiyon-predikatlı find + çift yönlü gezinmeBoş string boolean özniteliği ve strip kelime sınırı tuzakları
CSS kapsamısoupsieve en güçlü: 41/41 temel + 20/20 genişletilmiş; :lang desteklerXPath yok, ::text yok
3 arka uç toleransılxml/html5lib 15/15; html.parser 12/15Ayrışma yalnızca bozuk HTML’de
Gerçek sayfa tutarlılığı3 arka uç 11/11 aynı; hepsi <template>’i düzleştiriyor (508)Düzgün sitelerde arka uç fark etmez
Referans döngüsü GCAğaç döngüdür; 300 döngü 120.900 nesneyi tuttu, collect hepsini sıfırladıUzun döngülerde decompose() gerekir
KodlamaUnicodeDammit 8 durumun 5’ini kurtardı; kısa örnekleri yanlış tahmin ediyor, kötü beyanlara uyuyorTek gözlem
BakımAktif (4.15.0, Haziran 2026); MITcrummy/Launchpad üzerinde, GitHub’da değil

Öyleyse BeautifulSoup kim için? Okunabilir bir API ve hoşgörülü ayrıştırmayı, ham verime göre daha çok önemseyen; orta hacimde çalışan; prototipler, tek seferlik kazımalar, iç araçlar ve geliştirici zamanının çalışma zamanından pahalı olduğu ekipler için. Kim başka yere bakmalı? Milyon sayfalık hatlarda hız vergisi gerçek paraya dönüşenler, thread düzeyinde paralelliğe ihtiyaç duyanlar ve XPath’a bağlı olanlar.

Bunun gerçek bir scraping yığınında nereye oturduğuna ve kendi aracımızın nerede devreye girdiğine dair bir not. BeautifulSoup, HTML’ye zaten sahip olduğunuzu varsayar. Sayfa çekmez, JavaScript render etmez ve bot önleme ya da CAPTCHA sorunlarıyla uğraşmaz — bunlar bütünüyle ayrı ve modern web’de gerçekten zor bir iştir. AI destekli bir scraping API’si işte burada farklı bir katmanda durur: Thunderbit'in geliştirici yığını — bir REST API, bir MCP sunucusu ve bir CLI — çekme işlemini, JS render’ını ve anti-bot sorununu halleder; ardından siz selector yazmadan temiz Markdown (POST /distill) ya da şemaya uyan yapılandırılmış JSON (POST /extract) döndürür. İkisi rakip değil, tamamlayıcıdır. bs4 zaten elinizde olan HTML’yi ayrıştırır; Thunderbit’in API, MCP ve CLI’si ise ilk etapta kolay ulaşılamayan HTML’yi size getirir. Darboğazınız ayrıştırmaysa, bs4 iyi bir cevaptır. Darboğazınız edinim ise, mesele diğer katmandadır.

Web Verisi Çekmek İçin Thunderbit’i Deneyin

Son Söz

BeautifulSoup size en dost canlısı API’yi, bozuk HTML’ye karşı en güçlü toleransı ve bu karşılaştırmadaki en eksiksiz CSS motorunu sunar — bedeli ise yaklaşık bir büyüklük mertebesi hız vergisi ve en ağır bellek ayak izidir. Takas tam olarak budur. Varsayılan html.parser arka ucu, tek gerçek tuzaktır: kapanmamış tablo ve listeleri sessizce bozar; bu yüzden girdiniz kötü olabilecekse her zaman "lxml" ya da "html5lib" verin. Thread’lerle hızlanmaz; multiprocessing ile hızlanır. Ve uzun çalışan döngülerde, referans döngülerinin birikmesini önlemek için her sayfada decompose() çağırın.

Kapanışta iki sınırlama notu. Buradaki her şey tek bir platformda ölçüldü (macOS arm64, Python 3.14, önceden hazırlanmış wheel’ler) ve zamanlama çarpanları yeniden çalıştırılmak yerine selectolax düzeneğinden yeniden kullanıldı (aynı benchmark, 2026-07-13 itibarıyla) — dolayısıyla bu tek platform sınırlamasını devralıyorlar; Linux x86_64 ya da kaynaktan derlenmiş bir kurulum tam rakamları değiştirebilir. Ayrıca bu sonuçlarda yeni bir keşif yok: bs4 20 yıllık bir kütüphane; dolayısıyla test edilen her davranış ya belgelenmiş ya da kamuya açık biçimde kayıtlı. Değer, bir haber çıkarmak değil. Dokümantasyonun yalnızca nitel olarak anlattığı takaslara gerçek sayı koymak.

Sık Sorulan Sorular

BeautifulSoup yavaş mı? Evet, ölçülebilir biçimde. Ayrıştırma + çıkarma işinde, varsayılan html.parser arka ucu ile selectolax-Lexbor gibi bir C ayrıştırıcıdan yaklaşık 12–17x, lxml arka ucu ile de 10.5–14x daha yavaş çalışır; çünkü her düğüm için bir Python nesnesi oluşturur. Bunun ne kadar önemli olduğu ölçeğe bağlıdır: 1 MB’lik bir sayfada 232 ms ile 15 ms arasındadır; birkaç bin sayfada önemsizdir, milyon sayfalık bir boru hattında ise belirleyicidir.

Hangi BeautifulSoup ayrıştırıcısını kullanmalıyım — html.parser, lxml yoksa html5lib mi? İyi biçimlendirilmiş, ana akım siteler için varsayılan html.parser yeterlidir ve ek bağımlılık getirmez. Ancak HTML5’in isteğe bağlı kapanış etiketlerini uygulamaz; bu yüzden kapanmamış tablo ya da listelerde hata vermeden bitişik metni birbirine katar. Girdiniz bozuk, elle yazılmış ya da eski olabiliyorsa "lxml" ya da "html5lib" seçeneğini açıkça verin — bozuk HTML matrisinde ikisi de 15/15 alırken html.parser 12/15 aldı.

BeautifulSoup thread’lerle paralel ayrıştırma yapabilir mi? Hayır. bs4’nin ağaç oluşturma kısmı saf Python’dur ve GIL’i tutar; bu yüzden thread eklemek hızlandırmaz, yavaşlatır — testte 4 thread, 1 MB’lik bir ayrıştırmayı tek thread’e göre yaklaşık 3.9x daha yavaş çalıştırdı. bs4’yi paralelleştirmek için multiprocessing (ProcessPoolExecutor) kullanın. selectolax ve lxml gibi C çekirdeğine sahip kütüphaneler thread düzeyinde paralellikten fayda sağlar.

BeautifulSoup bozuk HTML’yi iyi işler mi? Genel olarak evet — yanlış iç içe geçmiş etiketler, eksik iskelet, tırnaksız öznitelikler ve daha fazlasını içeren bir dizi bozuk örnekte üç arka uç da temiz biçimde toparlandı. Tek zayıf nokta varsayılan html.parser ve isteğe bağlı kapanış etiketleridir: kapanmamış <td> / <li> öğeleri kapatılmak yerine iç içe geçirilir ve çıkarılan metni bozar. lxml ya da html5lib arka ucuna geçtiğinizde bu problem sınıfı ortadan kalkar.

BeautifulSoup vs lxml — hangisi daha iyi? Farklı araçlardır. lxml, hem ağaç oluşturma hem de sorgulamada çok daha hızlıdır ve XPath destekler. BeautifulSoup ise lxml dahil çeşitli ayrıştırıcıları çok daha dost canlısı bir API ile sarar ve soupsieve sayesinde CSS kapsamı daha geniştir. Sadece lxml arka ucunu vermek bs4’yi lxml kadar hızlı yapmaz — arka uç yalnızca ayrıştırmayı hızlandırır; sorgular ve gezinme hâlâ bs4’nin düğüm başı Python nesnesi maliyetini öder ve büyük toplu seçimlerde onu kabaca 6–7.5x daha yavaş bırakır.

Web Verisi Çekmek İçin Thunderbit’i Deneyin Get Started Free

Ke
Ke
Thunderbit’ta CTO | Kıdemli Veri Bilimci ve ML Uzmanı Makine öğrenimi ve veri bilimi alanında yaklaşık on yıllık deneyime sahip olan Ke Shen, Columbia University mezunu ve Walmart Labs’te eski Kıdemli Veri Bilimci’dir. Python, R, Java ve İstatistik konularında derin ve meslektaşları tarafından tanınan uzmanlığıyla, karmaşık yapay zekâ algoritmalarını teoriden üretim düzeyinde mimariye taşıma konusunda sahada test edilmiş içgörüler paylaşır.

Thunderbit'i dene

Potansiyel müşterileri ve diğer verileri sadece 2 tıkla topla. Yapay zekâ destekli.

Thunderbit'i al Ücretsiz
Yapay Zekâ ile Veri Çıkar
Verileri kolayca Google Sheets, Airtable veya Notion'a aktar
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week