- BeautifulSoup ne işe yarar, ne yapmaz?
- Sayfayı indirip çözümlemek: ilk çalışan örnek
- find, find_all ve select: doğru aramayı seçmek
- Metin, öznitelik ve gezinme: veriyi çıkarmak
- Birden çok sayfa, hata önleme ve nazik tarama
- Sık yapılan hatalar
- Bu beceriyi Mindset programlarında nerede çalışırsınız?
- Sık sorulan sorular
BeautifulSoup ile HTML sayfa çözümleme: adım adım uygulama
BeautifulSoup ile HTML sayfa çözümlemeyi örneklerle öğrenin: parser seçimi, find, find_all, CSS seçiciler, öznitelikler, hata önleme ve veriyi tabloya dökme.
BeautifulSoup ne işe yarar, ne yapmaz?
BeautifulSoup (bs4), HTML ya da XML metnini ağaç yapısına çevirip içinde gezinmeyi ve arama yapmayı sağlayan bir Python kütüphanesidir. Sayfayı indirmez; indirme işini requests gibi bir istemci yapar. BeautifulSoup elinizdeki metni etiket, öznitelik ve metin düğümleri olarak okunabilir hale getirir.
Güçlü olduğu yer, sunucudan hazır HTML olarak gelen sayfalardır: haber listesi, tablo, ürün katalog sayfası. Zayıf olduğu yer, içeriğin tarayıcıda JavaScript ile sonradan oluşturulduğu sayfalardır. İndirdiğiniz HTML'de veri yoksa BeautifulSoup'un yapabileceği bir şey yoktur; bu durumda ya sayfanın veri aldığı API çağrısına doğrudan gidersiniz ya da tarayıcıyı otomatikleştiren bir araç (Selenium gibi) kullanırsınız.
Kurulum paketi beautifulsoup4, içe aktarma adı bs4'tür: pip install beautifulsoup4 ve sonra from bs4 import BeautifulSoup. Kurulumu sanal ortam içinde yapmak, bağımlılıkları projeye özel tutar.
Kullanmadan önce hukuki ve etik çerçeveyi gözden geçirin: sitenin kullanım koşulları, robots.txt dosyası ve kişisel veri düzenlemeleri. Hızlı ve yoğun istek atmak, hem karşı sunucuya zarar verir hem de erişimin engellenmesine yol açar.
Sayfayı indirip çözümlemek: ilk çalışan örnek
En küçük çalışan akış şöyledir: indir, çözümle, ara.
import requests from bs4 import BeautifulSoup
yanit = requests.get(adres, timeout=ZAMAN_ASIMI) yanit.raise_for_status() sayfa = BeautifulSoup(yanit.text, "html.parser")
timeout vermeyi unutmayın; verilmezse yanıt gelmeyen bir sunucuda programınız sonsuza kadar bekleyebilir. raise_for_status, hata kodlu yanıtlarda hemen istisna fırlatır; böylece hatalı sayfayı sessizce çözümlemezsiniz.
Belgeye göre BeautifulSoup'a verdiğiniz ikinci bağımsız değişken parser adıdır. "html.parser" Python'la gelen yerleşik çözümleyicidir ve ek kurulum gerektirmez. "lxml" daha hızlıdır ama ayrıca kurulmalıdır. İstediğiniz parser kurulu değilse BeautifulSoup başka bir parser'a geçmez, hata verir; bu davranışı bilmek hata ayıklamayı kolaylaştırır. Bozuk HTML'de parser'lar farklı sonuçlar verebilir; beklenmeyen bir ağaç görürseniz parser'ı değiştirip karşılaştırın.
Çözümlenmiş ağacı incelemeye sayfa.title ile başlayabilirsiniz; ilk eşleşen etiketi verir. Etikete ait metin için .get_text() kullanılır. Karmaşık sayfada önce ağacın bir kısmını print(sayfa.prettify()) ile okunabilir yazdırıp yapıyı tanıyın.
find, find_all ve select: doğru aramayı seçmek
Belgeye göre ağaçta aramak için başlıca araçlar şunlardır:
- sayfa.find("a"): Eşleşen ilk etiketi döndürür, bulamazsa None verir.
- sayfa.find_all("a", limit=n): Eşleşen tüm etiketlerin listesini verir; limit ile sayıyı sınırlayabilirsiniz.
- sayfa.select("div.product a"): CSS seçici ile eşleşen etiketlerin listesini verir.
- sayfa.select_one("#ana-baslik"): CSS seçiciyle eşleşen ilk etiketi verir, yoksa None.
Sınıfa göre aramak için find ve find_all'da class_ anahtar sözcüğünü kullanırsınız (class Python'da ayrılmış sözcük olduğu için alt çizgi eklenir): sayfa.find_all("div", class_="product"). Tarayıcıdaki geliştirici araçlarında gördüğünüz CSS seçicileri doğrudan select'e verebilmek, çoğu zaman en pratik yoldur: Tarayıcıda öğeyi inceleyin, seçicinin yapısını anlayın ve select ile deneyin.
Hangisi ne zaman? Basit bir etiket ve sınıf araması için find_all yeterlidir. İç içe yapıyı tek ifadeyle tarif etmeniz gerekiyorsa (bir bölümün içindeki bağlantılar gibi) select daha kısa ve okunur olur. Sayfada tek bir öğe bekliyorsanız find ya da select_one kullanın, ama sonucun None olabileceğini unutmayın.
Seçicileri mümkün olduğunca kararlı özniteliklere dayandırın: anlamlı sınıf adları, veri öznitelikleri, kimlik. Otomatik üretilmiş rastgele görünümlü sınıf adlarına bağlı seçiciler, sitenin bir sonraki güncellemesinde kırılır.
Metin, öznitelik ve gezinme: veriyi çıkarmak
Etiketi bulduktan sonra verinin farklı türlerini çıkarırsınız: metin, öznitelik ve komşu öğeler.
Metin için get_text kullanılır. Belgeye göre get_text() tüm metni tek dize olarak verir; ayırıcı verip strip=True ile fazla boşlukları kırpabilirsiniz: etiket.get_text(" ", strip=True). Temizlenmemiş HTML metninde satır sonu ve boşluk kalıntıları olur; strip=True çoğu sorunu çözer.
Öznitelik için sözlük gibi erişilir: etiket["href"]. Belgeye göre öznitelik yoksa bu yazım KeyError fırlatır. etiket.get("href") ise None döndürür. Eksik olabilecek alanlarda get tercih edilir. etiket.attrs tüm özniteliklerin sözlüğünü verir.
Gezinme için etiket.parent kapsayıcıyı, etiket.next_sibling aynı seviyedeki sonraki düğümü verir. Belge uyarır: next_sibling çoğunlukla etiket değil, boşluk ya da satır sonu metni döndürür; bu yüzden bazen arka arkaya çağırmak gerekir. Bunun yerine find_next_sibling gibi etiket arayan yöntemler daha güvenlidir.
Bağlantıları toplarken göreli adreslere dikkat: href="/product/pen" gibi değerleri urllib.parse.urljoin ile sayfanın adresine eklemeden istek atmayın.
Küçük bir örnek, kurgusal HTML üzerinde:
for kart in sayfa.select("div.product"): ad = kart.select_one("h2").get_text(strip=True) baglanti = kart.select_one("a").get("href") kayitlar.append({"ad": ad, "baglanti": baglanti})
Birden çok sayfa, hata önleme ve nazik tarama
Gerçek işte tek sayfa yetmez. Liste sayfalarında sayfalama (pagination) bağlantısını izleyin: "sonraki" bağlantısı olduğu sürece döngüyü sürdürün ve bağlantı kalmayınca durun. Sayfa numarasını adrese ekleyerek de ilerleyebilirsiniz, ama bitiş koşulunu açıkça tanımlayın; aksi halde döngü sonsuza gidebilir.
Hata önleme için kural basittir: Her seçimden sonra None olabileceğini varsayın.
baslik = kart.select_one("h2") ad = baslik.get_text(strip=True) if baslik else None
Bu kontrol, bir kartta başlık eksik olduğunda programın "AttributeError: NoneType" ile çökmesini engeller. Eksik alanları boş bırakıp sonradan sayarak sayfa yapısı değişimini yakalayabilirsiniz: Aniden çok sayıda eksik alan görüyorsanız site değişmiş demektir.
İstekler arasında bekleyin (time.sleep), tek oturumda requests.Session kullanın, kendinizi açıkça tanıtan bir User-Agent başlığı koyun ve robots.txt kurallarına uyun. Hata veren isteği yeniden denerken bekleme süresini artırın. Giriş gerektiren, ücretli ya da kişisel veri içeren sayfaların toplanması hukuki risk taşır; kuşkunuz varsa sitenin sahibinden izin isteyin ya da resmî API'yi tercih edin.
Çıktıyı pandas DataFrame'e dökmek için sözlük listesini pd.DataFrame(kayitlar) ile tabloya çevirebilir, sonra temizlik ve kayıt adımlarına geçebilirsiniz.
Sık yapılan hatalar
BeautifulSoup ile en sık yaşanan sorunlar şunlardır:
- Boş sonuç alıp seçiciyi suçlamak. Önce indirilen HTML'de aradığınız verinin gerçekten bulunduğunu kontrol edin (yanit.text içinde arayın). Yoksa veri JavaScript ile geliyor demektir.
- Kodlama sorunu. Türkçe karakterler bozuk geliyorsa yanıtın kodlamasını kontrol edin; yanit.encoding değerini doğru ayarlamak ya da ham baytı (yanit.content) vermek çözebilir.
- Her şeyi tek seçiciye sığdırmak. Önce kapsayıcıyı seçin, sonra her kapsayıcının içinde arama yapın; böylece her kayıt kendi alanlarıyla eşleşir.
- Tarayıcı ile gelen HTML'in farklı olduğunu unutmak. Geliştirici araçlarındaki ağaç, JavaScript'ten sonraki halidir; BeautifulSoup'a gelen ise sunucunun ilk yanıtıdır. Karşılaştırmak için "sayfa kaynağını görüntüle" ile bakın.
- İstekleri aralıksız göndermek. Engellenme riskini artırır ve nezaketsizdir.
- Uzun regex'lerle HTML çözmek. Etiketler için ağaç yapısını kullanın; regex yalnızca çıkarılan metnin içindeki küçük örüntülerde işe yarar.
- Test yazmamak. Kaydedilmiş bir HTML dosyasıyla çalışan küçük testler, site değiştiğinde kırılmayı erken gösterir.
Pratik bir yöntem: Beğendiğiniz bir sayfanın HTML'ini dosyaya kaydedin, çözümleme kodunu önce bu yerel dosya üzerinde geliştirin ve sonra canlı siteye bağlayın. Böylece hem siteyi yormazsınız hem de hata ayıklama kolaylaşır.
Bu beceriyi Mindset programlarında nerede çalışırsınız?
HTML çözümleme; rakip ve pazar izleme, ilan ve katalog verisi derleme, kamuya açık raporlardan tablo çekme ve veri ekibine ham veri toplama gibi işler yapan analist, veri mühendisi ve araştırmacılar için temel bir beceridir. Düzenli çalışması gereken veri toplama işinde kodun site değişikliklerine dayanıklı ve hukuken sağlam olması gerekir.
Python ile Web Scraping ve Veri Toplama programının modül başlıkları arasında web scraping temelleri ve yasal çerçeve, BeautifulSoup ile statik sayfa çözümleme, Selenium ile dinamik ve JavaScript içerik çekme, API entegrasyonu ve JSON veri toplama, veri depolama, otomasyon ve boru hattı ile sektörel vaka çalışmaları yer alır. Daha geniş bir veri kazıma ve madencilik yolu arayan ekipler için Data Scraping ve Veri Madenciliği Programı da inceleme listesine eklenebilir. Kurumsal bir ekipte hangi veri toplama işinin izne, hangisinin API'ye dayanması gerektiğini ortak kurala bağlamak da bu eğitimlerde işlenen yasal çerçeve başlığının pratik karşılığıdır.
İlgili Mindset programı
Python ile Web Scraping ve Veri Toplama
Sık sorulan sorular
find ile find_all arasındaki fark nedir?
find eşleşen ilk etiketi döndürür; yoksa None verir. find_all eşleşen tüm etiketleri liste olarak döndürür; yoksa boş liste verir. Tek bir öğe bekliyorsanız find, çok sayıda kayıt bekliyorsanız find_all kullanın. find sonucunu kullanmadan önce None kontrolü yapmayı unutmayın.
html.parser ile lxml arasında hangisini seçmeliyim?
html.parser Python ile gelir ve ek kurulum istemez; çoğu küçük iş için yeterlidir. lxml ayrıca kurulur ve genellikle daha hızlıdır, bozuk HTML'e farklı yaklaşabilir. Çok sayıda sayfa işliyorsanız lxml düşünün; beklenmeyen sonuç alırsanız parser'ı değiştirip ağacı karşılaştırın.
BeautifulSoup JavaScript ile yüklenen içeriği okur mu?
Hayır. Yalnızca verdiğiniz HTML metnini çözümler; JavaScript çalıştırmaz. İndirdiğiniz sayfada veri yoksa sayfanın veri çektiği API çağrısını bulup doğrudan çağırın ya da tarayıcıyı otomatikleştiren Selenium gibi bir araçla sayfayı yükleyip ortaya çıkan HTML'i BeautifulSoup'a verin.
tag["href"] ile tag.get("href") arasındaki fark nedir?
Köşeli parantez yazımı öznitelik yoksa KeyError fırlatır. get yöntemi ise None döndürür. Her sayfada bulunmayabilecek öznitelikler için get daha güvenlidir; mutlaka olması gereken öznitelikte hatayı görmek istiyorsanız köşeli parantez de bilinçli bir seçim olabilir.
Web sayfasından veri çekmek yasal mıdır?
Duruma göre değişir. Sitenin kullanım koşulları, robots.txt, telif hakkı ve kişisel verilerin korunması mevzuatı belirleyicidir. Herkese açık olması serbestçe toplanıp kullanılabileceği anlamına gelmez. Belirsizlik varsa site sahibinden izin alın, mümkünse resmî API kullanın ve hukuk ekibine danışın.
İlgili rehberler
İlgili eğitimler
Kategori: Veri Analitiği ve İş Zekası, Veri Mühendisliği ve MLOps