HTML'den Veri Ayıklamak: BeautifulSoup ile Web Kazıma

Bu derste ne yapacağız?

Bu derste bir web sayfasının HTML kodunun içinden başlık, fiyat veya bağlantı gibi belirli verileri seçip ayıklamayı öğreneceğiz. Bunun için Python'ın en yaygın web kazıma kütüphanelerinden biri olan BeautifulSoup'u kullanacağız. Dersin sonunda, bir sayfadan çektiğimiz verileri bir önceki derste openpyxl ile öğrendiğimiz yöntemle otomatik olarak bir Excel dosyasına kaydedeceğiz; böylece iki dersi birleştirip uçtan uca çalışan küçük bir araç ortaya çıkaracağız.

Ön koşul olarak şunları bilmeniz beklenir: temel Python söz dizimi (değişkenler, döngüler, listeler, fonksiyonlar), dosyalarla çalışma mantığı ve bir önceki derste işlediğimiz openpyxl ile Excel'e veri yazma. Ayrıca bilgisayarınızda Python'ın kurulu olması ve bir komut satırından (terminal veya PowerShell) pip komutunu çalıştırabiliyor olmanız gerekir. HTML hakkında hiçbir bilgi gerekmiyor; sayfanın yapısını birlikte inceleyeceğiz.

Kavram

Bir web sayfası, tarayıcınızın yorumladığı HTML adlı bir metin biçimindedir. HTML, sayfadaki her öğeyi (başlık, paragraf, resim, tablo, bağlantı) etiketlerle işaretler; örneğin bir başlık <h1>Merhaba</h1> şeklinde, bir bağlantı ise <a href="...">metin</a> şeklinde yazılır. Web kazıma (web scraping), bir sayfanın HTML kodunu indirip bu etiketlerin içindeki bilgileri programatik olarak ayıklama işlemidir.

Bunu bir markete benzetebilirsiniz: Market rafları (HTML etiketleri) ürünleri (verileri) belirli bir düzende tutar. Siz manuel olarak her rafı tek tek dolaşıp ürün adını ve fiyatını deftere yazmak yerine, bir yardımcıya (BeautifulSoup) "bana sadece kırmızı etiketli rafların üzerindeki fiyatları getir" dersiniz. Yardımcı, rafların düzenini anlar ve istediğiniz bilgiyi süzüp size verir. BeautifulSoup da tam olarak bunu yapar: HTML metnini analiz eder, onu bir ağaç yapısına (etiketlerin iç içe geçmiş hâli) dönüştürür ve siz belirli etiket adı, sınıf (class) ya da kimlik (id) vererek istediğiniz veriyi seçebilirsiniz.

Web kazımanın iki temel adımı vardır: birincisi sayfanın HTML içeriğini indirmek (bunun için requests kütüphanesini kullanırız), ikincisi bu HTML içeriğini ayrıştırıp içinden istediğimiz parçaları çekmek (bunun için BeautifulSoup kullanırız). Bu iki kütüphane genellikle birlikte kullanılır ve web kazımanın standart ikilisidir.

Önemli bir uyarı: Her sitenin kazınmasına izin verilmez. Bir siteyi kazımadan önce sitenin kullanım şartlarını ve robots.txt dosyasını kontrol etmek, aşırı sıklıkta istek göndererek sunucuyu yormamak ve yalnızca herkese açık, kazımaya izin veren veya kendi kontrolünüzde olan sayfalarla pratik yapmak önemlidir. Bu derste örnek olarak basit, statik ve eğitim amaçlı yapılmış bir HTML sayfası üzerinde çalışacağız.

Adım adım uygulama

  1. Gerekli kütüphaneleri kurun. Terminal veya PowerShell'i açın ve şu komutu çalıştırın:
    pip install requests beautifulsoup4 openpyxl
    Bu komut üç kütüphaneyi birden kurar: sayfa indirmek için requests, HTML'i ayrıştırmak için beautifulsoup4 ve bir önceki dersten hatırlayacağınız Excel dosyası oluşturmak için openpyxl.
  2. Örnek bir HTML sayfası oluşturun. Gerçek bir siteyle uğraşmadan önce mantığı öğrenmek için kendi bilgisayarınızda basit bir HTML dosyası hazırlayalım. Bir metin düzenleyicide (Not Defteri, VS Code gibi) yeni bir dosya açın, adını urunler.html koyun ve şu içeriği yazıp kaydedin:
    <html>
    <body>
      <div class="urun">
        <h2>Kablosuz Kulaklık</h2>
        <span class="fiyat">450 TL</span>
        <a href="urun1.html">Detay</a>
      </div>
      <div class="urun">
        <h2>Bluetooth Hoparlör</h2>
        <span class="fiyat">620 TL</span>
        <a href="urun2.html">Detay</a>
      </div>
      <div class="urun">
        <h2>Akıllı Saat</h2>
        <span class="fiyat">1350 TL</span>
        <a href="urun3.html">Detay</a>
      </div>
    </body>
    </html>
    Bu sayfada üç adet ürün kutusu (div class="urun") var; her kutunun içinde bir ürün adı (h2), bir fiyat (span class="fiyat") ve bir bağlantı (a) bulunuyor.
  3. HTML dosyasını Python'da açıp BeautifulSoup ile ayrıştırın. Aynı klasörde kazima.py adında yeni bir Python dosyası oluşturun ve şunu yazın:
    from bs4 import BeautifulSoup
    
    with open("urunler.html", "r", encoding="utf-8") as dosya:
        icerik = dosya.read()
    
    soup = BeautifulSoup(icerik, "html.parser")
    print(soup.prettify())
    Satır satır ne yaptığını inceleyelim: from bs4 import BeautifulSoup satırı kütüphaneyi projemize dahil eder. with open(...) bloğu HTML dosyasını okur ve içeriğini icerik değişkenine metin olarak alır. BeautifulSoup(icerik, "html.parser") satırı bu ham metni analiz edilebilir bir ağaç yapısına dönüştürür; "html.parser" Python'ın kendi dahili HTML ayrıştırıcısıdır ve ek kurulum gerektirmez. soup.prettify() ise HTML'i girintili, okunaklı bir biçimde ekrana yazdırır; bu, yapıyı görsel olarak anlamak için kullanışlıdır.
  4. Belirli etiketleri seçin. Şimdi tüm ürün kutularını bulup içlerindeki bilgileri çekelim. kazima.py dosyasını şu şekilde güncelleyin:
    urun_kutulari = soup.find_all("div", class_="urun")
    
    for kutu in urun_kutulari:
        ad = kutu.find("h2").text
        fiyat = kutu.find("span", class_="fiyat").text
        link = kutu.find("a")["href"]
        print(ad, "-", fiyat, "-", link)
    soup.find_all("div", class_="urun") sayfadaki class değeri "urun" olan tüm div etiketlerini bir liste olarak döndürür (Python'da class anahtar kelime olduğu için BeautifulSoup'ta class_ yazılır, sonuna alt çizgi eklenir). for kutu in urun_kutulari: döngüsü her ürün kutusunu tek tek gezer. kutu.find("h2").text o kutunun içindeki ilk h2 etiketini bulur ve yalnızca yazı içeriğini (.text) alır. kutu.find("span", class_="fiyat") yine kutunun içinde, sınıfı "fiyat" olan span etiketini bulur. kutu.find("a")["href"] ise kutudaki bağlantı etiketini bulup href özniteliğinin değerini (yani bağlantının adresini) alır; burada köşeli parantez kullanmamızın sebebi, bir etiketin bir özniteliğine sözlük gibi erişebilmemizdir.
  5. Gerçek bir web sayfasından veri çekmeyi deneyin. Kendi kontrolünüzde olan veya kazımaya açık, basit bir test sayfası varsa requests ile indirebilirsiniz:
    import requests
    from bs4 import BeautifulSoup
    
    adres = "https://ornek-site.com/urunler"
    cevap = requests.get(adres, timeout=10)
    cevap.raise_for_status()
    
    soup = BeautifulSoup(cevap.text, "html.parser")
    requests.get(adres, timeout=10) belirtilen adrese bir istek gönderir ve sunucudan gelen yanıtı bekler; timeout=10 sunucu 10 saniye içinde cevap vermezse programın sonsuza kadar beklemesini önler. cevap.raise_for_status() sunucudan hata kodu (örneğin sayfa bulunamadı) geldiyse programı anlamlı bir hatayla durdurur. cevap.text sunucudan gelen HTML içeriğini metin olarak verir ve bunu doğrudan BeautifulSoup'a besleriz. Buradan sonrası bir önceki adımdaki find_all ve find mantığıyla aynıdır; yalnızca gerçek sitenin etiket adları ve sınıf isimleri farklı olacağı için tarayıcınızın "Öğeyi denetle" özelliğiyle önce o sayfanın yapısını incelemeniz gerekir.
  6. Çekilen verileri bir Excel dosyasına kaydedin. Şimdi bir önceki derste öğrendiğimiz openpyxl'i devreye sokalım. Örnek HTML dosyamızdan çektiğimiz verileri kaydeden tam kodu yazalım:
    from bs4 import BeautifulSoup
    from openpyxl import Workbook
    
    with open("urunler.html", "r", encoding="utf-8") as dosya:
        icerik = dosya.read()
    
    soup = BeautifulSoup(icerik, "html.parser")
    urun_kutulari = soup.find_all("div", class_="urun")
    
    kitap = Workbook()
    sayfa = kitap.active
    sayfa.title = "Urunler"
    sayfa.append(["Ürün Adı", "Fiyat", "Bağlantı"])
    
    for kutu in urun_kutulari:
        ad = kutu.find("h2").text
        fiyat = kutu.find("span", class_="fiyat").text
        link = kutu.find("a")["href"]
        sayfa.append([ad, fiyat, link])
    
    kitap.save("urunler_listesi.xlsx")
    print("Excel dosyası oluşturuldu: urunler_listesi.xlsx")
    Bu kodda yeni olan kısımları inceleyelim: Workbook() boş bir Excel çalışma kitabı oluşturur. kitap.active o kitaptaki aktif çalışma sayfasını seçer. sayfa.append([...]) satırı, verdiğimiz listeyi Excel'de yeni bir satır olarak ekler; önce başlık satırını ("Ürün Adı", "Fiyat", "Bağlantı") ekliyoruz, sonra döngü içinde her ürün için bir satır daha ekliyoruz. kitap.save("urunler_listesi.xlsx") son olarak dosyayı diske kaydeder. Bu kodu çalıştırdığınızda, çalıştığınız klasörde urunler_listesi.xlsx adında, üç ürünün adı, fiyatı ve bağlantısını içeren bir Excel dosyası oluşacaktır.
  7. Sonucu kontrol edin. Oluşan urunler_listesi.xlsx dosyasını Excel veya benzeri bir programla açın ve verilerin doğru satır ve sütunlara yerleştiğinden emin olun. Eğer bir hücre boş veya yanlış görünüyorsa, ilgili HTML etiketinin adını veya sınıfını tekrar kontrol edin.

Sık karşılaşılan sorunlar

Hata / SorunOlası Sebep ve Çözüm
ModuleNotFoundError: No module named 'bs4'BeautifulSoup kurulu değil. Terminalde pip install beautifulsoup4 komutunu çalıştırın; sanal ortam kullanıyorsanız ortamın etkin olduğundan emin olun.
AttributeError: 'NoneType' object has no attribute 'text'find aradığınız etiketi bulamadı ve None döndürdü. Etiket adının veya sınıf isminin doğru yazıldığını, sayfanın yapısının beklediğiniz gibi olduğunu kontrol edin; tarayıcının "Öğeyi denetle" aracıyla gerçek HTML'e tekrar bakın.
requests.exceptions.ConnectionError veya zaman aşımıİnternet bağlantısı yok, adres yanlış yazılmış veya sunucu erişime kapalı. Adresi tarayıcıda açarak test edin, timeout süresini artırmayı deneyin.
Excel dosyası oluşuyor ama tüm hücreler boşDöngü içinde sayfa.append çağrısı yanlış konumda veya listeler boş geliyor olabilir. find_all sonucunun boş liste dönüp dönmediğini print(len(urun_kutulari)) ile kontrol edin.
Sitenin HTML yapısı beklenenden çok farklı, veriler karışık geliyorModern siteler JavaScript ile içerik oluşturabilir; bu durumda requests ile indirilen HTML'de veri hiç bulunmayabilir. Bu, bu dersin kapsamı dışındadır ve tarayıcı otomasyonu gerektiren farklı bir konudur.
Kazıma sırasında "403 Forbidden" hatası alınıyorSite otomatik isteklere izin vermiyor olabilir. Bu, sitenin kullanım şartlarına saygı gösterilmesi gereken bir sinyaldir; o siteyi kazımaktan vazgeçip yalnızca izin verilen kaynaklarla çalışın.

Mini görev

Bu derste kullandığımız urunler.html dosyasına iki ürün daha ekleyin (aynı div class="urun" yapısını kullanarak). Ardından Python kodunu, bu beş ürünün tamamını okuyup fiyatı 600 TL'nin üzerinde olanları ayrı bir Excel dosyasına (pahali_urunler.xlsx) kaydedecek şekilde güncelleyin. İpucu: fiyat metnindeki " TL" ifadesini kaldırıp geri kalan kısmı sayıya çevirmeniz (int() veya benzeri) gerekecek.

Kontrol listesi:

  • HTML dosyasında toplam beş ürün kutusu var mı?
  • Kod, fiyat metnindeki "TL" ifadesini temizleyip sayısal karşılaştırma yapabiliyor mu?
  • Sadece 600 TL üzeri ürünler pahali_urunler.xlsx dosyasına yazılıyor mu?
  • Excel dosyasında başlık satırı (Ürün Adı, Fiyat, Bağlantı) doğru şekilde yer alıyor mu?
  • Kodu ikinci kez çalıştırdığınızda hata almadan yeniden çalışıyor mu?

Kendini sına

1. BeautifulSoup'un temel görevi nedir?

2. soup.find_all("div", class_="urun") satırı ne döndürür?

3. Bir etiketin metin içeriğini almak için hangi öznitelik kullanılır?

4. Bir bağlantı etiketinin (<a>) hedef adresine nasıl erişilir?

5. Bir siteyi kazımadan önce kontrol edilmesi gereken, sitenin izinlerini belirten dosyanın adı nedir?

Cevaplar

1. HTML metnini analiz edilebilir bir ağaç yapısına dönüştürüp, etiket adı, sınıf veya kimlik gibi kriterlerle istenen verilerin seçilmesini sağlamaktır.

2. Belirtilen etiket adına ve sınıfına (class_="urun") sahip tüm eşleşen etiketlerin bir listesini döndürür.

.text özniteliği kullanılır.

4. Etiketin href özniteliğine köşeli parantez ile erişilir: etiket["href"].

5. robots.txt dosyasıdır.

Bir önceki derste openpyxl ile Excel dosyalarını sıfırdan oluşturmayı, veri yazmayı ve biçimlendirmeyi öğrenmiştik; bu derste ise web sayfalarından veri çekip o bilgiyi doğrudan Excel'e aktararak iki beceriyi birleştirdik. Kursun son dersinde, şimdiye kadar öğrendiğimiz dosya işleme, Excel otomasyonu ve web kazıma tekniklerini bir araya getirerek uçtan uca çalışan küçük bir otomasyon aracı geliştireceğiz.

Bu dersi kayıt olmadan izleyebilirsin. İlerlemeni kaydetmek, sertifika almak ve puan tablosuna girmek için ücretsiz üye ol: Kayıt Ol