
Merhaba,
Bazen bazı web sitelerinden verileri çekip çeşitli işlem yapmamız gerekebilir. Bir analiz, takip, karşılaştırma vb. işlemler için…
Bu gibi takiplerde verileri çekmek için normal bir browser ile sayfayı gezer gibi ziyaret etmek gerekiyor. Python’da bulunan Selenium kütüphanesi web uygulamalarının test edilmesi için bir araç bu aracı kullanarak veri çekmek istediğimiz sayfaları ziyaret ederek verileri toplayabiliriz.
Uygulamada kullandığımız kütüphaneler:
- Selenium İstediğimiz web sayfasını bir browser nesnesi oluşturup ziyaret etmek için.
- BeautifulSoup aldığımız verileri parselemek için kullanıyoruz.
- Diğer kütüphaneler, bekleme, dosya oluşturma-yazma vb. işlemler için sistem kütüphaneleri.
Şimdi kodları açıklayalım.
Kullanacağımız kütüphaneleri koduma dahil ediyoruz.
import sys #sistem işlemlerini kullanmak için ekranı yazı yazma vb. import os # Dosya işlemleri için kullanılır. import datetime # Tarih işlemleri için kullanılır. from bs4 import BeautifulSoup # HTML ve XML dosyalarının ayrıştırılması için kullanılır. from selenium import webdriver # Web tarayıcıları ile otomatik işlemler yapmak için kullanılır. import time # Zaman işlemleri için kullanılır.
İlk önce ziyaret edeceğimiz sayfanın url’sini almak gerekiyor. Bunu 2 yol ile yaptım eğer kod çalışırken zaten url yazıldı ise gerek olmadan çalışacak sok.exe http://sokmarket.com gibi eğer boş ise url sorulacak. Bunun için bir fonksiyon yazıyoruz.
def get_url() if len(sys.argv) > 1: return sys.argv[1] else: return input("Lütfen URL'yi girin veya Enter'a basarak varsayılan adres ile devam edin: "):
Ziyaret edeceğimiz url’yi öğrendikden sonra tarayıcı açıp sayfayı ziyaret edebiliriz. Ben tarayici_ac ve ziyaret_et diye 2 fonksiyon tanımladın çünkü farklı sayfaları ziyaret etmek isterseniz tarayıcı 1 kere açtıkdan sonra diğer sayfalarıda ziyaret edebilirsiniz.
Kodlarda yeterince açıklama yaptım ama bazı şeyleri neden yaptığımı belirtmekte fayda var. Bazı sayfalarda ssl hataları olmakta veya sayfa geç yüklenmektedir. Bu yüzden sayfayı açarken bazı parametreler göndermek sayfa açıldıktan sonrada tam yüklenmesini beklemek için bir süre beklemek zorunda kalabilirsiniz. Bu sebeple tarayıcı açılırken options kullanıldı ve time.sleep ile sayfa ziyaret edildikten sonra sayfada beklemesi sağlandı.
def tarayici_ac() yaz ("Tarayıcı açıldı.") """ Bu fonksiyon, Chrome tarayıcısını açar ve tarayıcı nesnesini döndürür. """ options = webdriver.ChromeOptions() options.add_argument('--ignore-certificate-errors') # Sertifika hatalarını görmezden gelir. options.add_argument('--ignore-ssl-errors') # SSL hatalarını görmezden gelir. options.add_experimental_option('excludeSwitches', ['enable-logging']) # Tarayıcı loglarını gizler. #sistem'de yüklü olan chrome ile kullanmak için. options.add_argument('--use-system-library') driver = webdriver.Chrome(options=options) driver.set_window_size(540, 540) return driver # Tarayıcı nesnesini döndürür. def sayfayi_ziyaret_et(driver, url): """ Bu fonksiyon, verilen tarayıcı nesnesiyle verilen URL'yi ziyaret eder. """ yaz (url+" sayfa ziyaret ediliyor...") driver.get(url) # URL'yi ziyaret eder. time.sleep(5) # 5 saniye bekler.:
Örnek aldığım web sitesi olan şok market ilk ziyaretden sonra sayfayı aşağıya kaydırdıkça ürün yüklemesi devam ediyordu. (Sonsuz sayfalama veya lazy load) bu sebeple sayfayı aşağı doğru birkaç kez kaydırarak tüm ürünlerin yüklenmesini sağladık.
def sayfayi_kaydir(driver, kez,saniye) """ Bu fonksiyon, verilen tarayıcı nesnesiyle verilen kez kadar sayfayı aşağı kaydırır ve her kaydırma işleminden sonra verilen saniye kadar bekler. """ for i in range(kez): # Verilen kez kadar döngü çalışır. driver.execute_script("document.body.scrollIntoView(false)") # Sayfayı aşağı kaydırır. time.sleep(saniye) # Verilen saniye kadar bekler.:
Artık tüm ürünleri yükledikten sonra sıra geldi mevcut sayfanın verilerini almaya bunu aşağıdaki kod ile yapıyoruz.
html_verileri = driver.page_source # Tarayıcıdan html verilerini alır.
Burada artık selenium’un işi bitti artık istediğimiz verileri BeuatifulSoup ile almamız gerekiyor. İlk önce selenium ile çektiğimiz verileri bir değişkene atıyoruz.
soup = BeautifulSoup(html_verileri, 'html.parser') # BeautifulSoup ile html verilerini parse eder.
Daha sonra aldığımız verileri daha okunaklı olsun diye ben bir verileri_al diye fonksiyon ile verileri çektim. Örnek olarak bu alan fiyatlari_cek, urunleri_cek vb. olarak dağıtılabilir ve daha okunaklı olur.
def verileri_al(soup) """ Bu fonksiyon, verilen BeautifulSoup nesnesi üzerinden verileri alır ve veri listesi olarak döndürür. """ yaz ("Veriler çekilmeye başlandı...") results_list = soup.find(class_='results-list') # 'results-list' sınıfını içeren ilk elementi bulur. li_elements = results_list.find_all('li') # 'li' elementlerini bulur. veri_listesi = [] # Boş veri listesi oluşturur. for li in li_elements: # Her bir 'li' elementi için döngü çalışır. pricetag = li.find(class_='pricetag') # 'pricetag' sınıfını içeren ilk elementi bulur. if pricetag is not None: # Eğer 'pricetag' elementi varsa: span_elements = pricetag.find_all('span') # 'span' elementlerini bulur. if len(span_elements) == 2: # Eğer 2 tane eski_fiyat = span_elements[0].text yeni_fiyat = span_elements[1].text elif len(span_elements) == 1: # Eğer sadece 1 tane span elementi varsa: eski_fiyat = "0" yeni_fiyat = span_elements[0].text else: # Eğer hiç span elementi yoksa: eski_fiyat = "0" yeni_fiyat = "0" else: # Eğer 'pricetag' elementi yoksa: eski_fiyat = "0" yeni_fiyat = "0" urun_ismi = li.find(class_='content-title') # 'content-title' sınıfını içeren ilk elementi bulur. if urun_ismi is not None: # Eğer 'urun_ismi' elementi varsa: urun_ismi = urun_ismi.text # Elementin metnini urun_ismi değişkenine atar. veri_listesi.append((urun_ismi,yeni_fiyat,eski_fiyat)) # Veri listesine tablo olarak ekler. return veri_listesi # Veri listesini döndürür.
BeautifulSoup ile verileri parselemek çok kolay işin açıkcası daha önceki makelelerimde bunu regex’le yaparken çok uğraşmıştım. Sadece dikkat etmeniz gereken verileri parselerken aynı düzende olmayabiliyor. İndirimli fiyat, fiyat vb. bu gibi durumlarda ana elementi aldıktan sonra bir if-else ile değerleri tanımlanız gerekiyor.
Veriler için boş bir array oluşturup verileri append ile eklerseniz kullanımı daha sonrası için oldukça kolay oluyor.
Verileri bir array’a aldıktan sonra sıra geldi aldığımız verileri bir yere kayıt etmeye linkteki kaynak kodda farklı şeyler var onları silmedim. İlk önce txt’ye kayıt ettim sonra dedim her çektiğimde bunları nasıl işleyeceğiz? Sonra vazgeçtim gün-gün adlandırılan bir excel’e çektim sonra dedim bu excelleri birleştirmek sorun. En son 1 excel dosyası oluşturup onları tarih-tarih sayfalara kayıt etmek işime geldi. Tabi eğer bunu kalıcı bir veri analizinde kullanmak daha sonra sunmak istiyorsanız bir sql veritabanına kayıt etmek çok daha akıllıca olacaktır.
Aşağıdaki kod ile verileri_al’dan döndürdüğümüz veri_listesini artık excel dosyasına yazıyoruz.
def excele_yaz(veri_listesi) """ Bu fonksiyon, verilen veri listesini mevcut tarih bazında Excel dosyasına yazar. Örneğin: veriler20230102.xlsx """ print("Veriler Excel dosyasına yazılıyor...") # openpyxl kütüphanesini import et from openpyxl import load_workbook from openpyxl import Workbook # Excel dosyasını aç try: workbook = load_workbook("veriler.xlsx") except FileNotFoundError: # Dosya mevcut değilse, dosyayı oluştur workbook = Workbook() # Sayfaya bir sütun adı ekle sayfa_adi = f"Sheet" if sayfa_adi in workbook.sheetnames: workbook.remove(workbook[sayfa_adi]) now = datetime.datetime.now() # Mevcut tarihi al sayfa_adi = f"Tarih {now.year}{now.month:02d}{now.day:02d}-{now.hour:02d}{now.minute:02d}" # Mevcut tarih bazında sayfa adı oluşturur. Örneğin: Veriler20230102 if sayfa_adi in workbook.sheetnames: # Eğer sayfa zaten mevcutsa: workbook.remove(workbook[sayfa_adi]) # Sayfayı sil # Yeni sayfa oluştur sayfa = workbook.create_sheet(title=sayfa_adi) sayfa["A1"] = "Ürün" sayfa["B1"] = "Yeni Fiyat" sayfa["C1"] = "Eski Fiyat" sayfa.column_dimensions["A"].width = 60 # A1 sütununu genişlet # Veri listesini gez for veri in veri_listesi: # Veriyi Excel sayfasına ekle sayfa.append(veri) # Excel dosyasını kaydet workbook.save("veriler.xlsx")
Excel dosyasına yazmak için openpyxl kütüphanesini kullandım başka kütüphanelerde mevcut.
Bu kütüphane ile ilk önce bir excel dosyası oluşturuyoruz. Daha sonra mevcut tarihde bir sayfa oluşturuyoruz. Kolon isimlerini verdikten sonra. Bir döngü ile array içerisindeki verileri sayfaya ekliyoruz.
İşimiz bittiğinde tarayıcıyı kapatıyoruz. driver.quit()
Başka makalelerde görüşmek üzere…
hashtag#python hashtag#selenium hashtag#excel
Kaynak Kodlar ve Örnek uygulama: https://disk.yandex.com.tr/d/JPsMCDR5VEKy7A
Youtube çalışan örnek uygulama: https://www.youtube.com/watch?v=98G7pNYnS0Y