Python ile web kazıma hakkında genel bir bakış isterseniz, DataCamp’in Python ile Web Kazıma kursunu inceleyin.
Bu eğitimde, büyük miktarda veriyi işleyebileceğiniz bir Python çatısı olan Scrapy’yi kullanmayı öğreneceksiniz! Bir e-ticaret sitesi olan AliExpress.com için bir web kazıyıcı oluşturarak Scrapy’yi öğreneceksiniz. Haydi kazımaya başlayalım!
Temel HTML ve CSS bilgisi, bu eğitimi daha kolay ve hızlı anlamanıza yardımcı olur. HTML ve CSS üzerine tazeleme için bu makaleyi okuyun.
Web kazıma, karar verme ve analiz için webden bilgi çıkarmanın etkili bir yolu haline geldi. Veri bilimi araç setinin vazgeçilmez bir parçası oldu. Veri bilimciler, web sayfalarından nasıl veri toplayacaklarını ve bu verileri ileri analiz için farklı formatlarda nasıl depolayacaklarını bilmelidir.
İnternette gördüğünüz herhangi bir web sayfası bilgi için taranabilir ve bir web sayfasında görünen her şey çıkarılabilir [2]. Her web sayfasının kendine özgü bir yapısı ve web öğeleri vardır; bu nedenle, kazıdığınız web sayfasına göre tarayıcılarınızı/spider’larınızı yazmanız gerekir.
Scrapy, veriyi çıkarmak, işlemek ve ardından kaydetmek için güçlü bir çatı sunar.
Scrapy, kendisine bir dizi talimat verilen, kendi kendine yeten tarayıcılar olan spider’ları kullanır [1]. Scrapy, geliştiricilerin kodlarını yeniden kullanmalarına olanak tanıyarak büyük tarama projelerini kurmayı ve ölçeklendirmeyi kolaylaştırır.
Scrapy ve BeautifulSoup Karşılaştırması
Bu bölümde, en yaygın kullanılan web kazıma araçlarından biri olan BeautifulSoup’a ve Scrapy ile karşılaştırmasına genel bir bakış yapacaksınız.
Scrapy, geliştiricilere kod bakımıyla uğraşmadan eksiksiz bir paket sunan bir web kazıma Python çatısıdır.
Beautiful Soup da web kazıma için yaygın olarak kullanılır. HTML ve XML belgelerini ayrıştırmak ve bunlardan veri çıkarmak için bir Python paketidir. Python 2.6+ ve Python 3 için mevcuttur.
Özetle aralarındaki bazı farklar şunlardır:
Scrapy
BeautifulSoup
İşlevsellik
---
Scrapy, web sayfalarını indirmek, işlemek ve dosyalara ya da veritabanlarına kaydetmek için eksiksiz bir pakettir
BeautifulSoup temelde bir HTML ve XML ayrıştırıcısıdır; URL açmak ve sonuçları depolamak için requests, urlib2 gibi ek kütüphanelere ihtiyaç duyar [6]
Öğrenme Eğrisi
---
Scrapy web kazıma için güçlü bir araçtır ve bir web sayfasını kazımak için birçok yöntem sunar. Scrapy’nin nasıl çalıştığını öğrenmek ve anlamak daha fazla zaman gerektirir; ancak bir kez öğrenildiğinde, web tarayıcıları oluşturmayı ve onları tek satırlık bir komutla çalıştırmayı kolaylaştırır. Scrapy’de uzmanlaşmak tüm işlevleri öğrenmek için biraz pratik ve zaman gerektirebilir.
BeautifulSoup, programlamaya yeni başlayanlar için nispeten kolay anlaşılır ve küçük işleri kısa sürede halledebilir
Hız ve Yük
---
Scrapy büyük işleri çok kolay halledebilir. Bir URL grubunu, grubun büyüklüğüne bağlı olarak bir dakikadan kısa sürede tarayabilir ve bunu eşzamanlılık için eşzamansız (engellemesiz) çalışan Twister kullandığı için oldukça akıcı yapar.
BeautifulSoup, basit kazıma işleri için verimli şekilde kullanılır. multiprocessing kullanmazsanız Scrapy’den daha yavaştır.
İşlevselliği Genişletme
---
Scrapy, verinizi doğrulamak, veriyi kaldırmak ve veriyi bir veritabanına kaydetmek gibi işlemleri spider’ınızda yazmanıza olanak tanıyan Öğe (Item) hatları sağlar. Spider’larınızı test etmek için Spider Sözleşmeleri sunar ve genel amaçlı ve derin tarayıcılar oluşturmanıza olanak tanır. Yeniden deneme, yönlendirme vb. birçok değişkeni yönetmenizi sağlar.
Proje çok fazla mantık gerektirmiyorsa BeautifulSoup iş için iyidir; ancak proxy’ler, çerez yönetimi ve veri hatları gibi özelleştirmeler gerekiyorsa en iyi seçenek Scrapy’dir.
Bilgi: Eşzamanlı (synchronous) demek, yeni bir işe başlamadan önce mevcut işin bitmesini beklemeniz gerektiği; eşzamansız (asynchronous) ise önceki iş tamamlanmadan başka bir işe geçebileceğiniz anlamına gelir
Python 3.0 (ve sonrası) kuruluysa ve anaconda kullanıyorsanız, scrapy’yi kurmak için conda kullanabilirsiniz. Anaconda komut istemine aşağıdaki komutu yazın:
conda install -c conda-forge scrapy
Anaconda kurmak için, Mac ve Windows için bu DataCamp eğitimlerine bakın.
Alternatif olarak, Python Paket Yükleyicisi pip’i kullanabilirsiniz. Bu, Linux, Mac ve Windows’ta çalışır:
pip install scrapy
Scrapy Shell
Scrapy, geliştiricilerin bir sitenin davranışına ilişkin varsayımlarını test etmek için kullanabilecekleri Scrapy Shell adlı bir web tarama kabuğu da sunar. AliExpress e-ticaret sitesinde tabletler için bir web sayfası ele alalım. Scrapy shell’i kullanarak web sayfasının hangi bileşenleri döndürdüğünü ve bunları gereksinimlerinize göre nasıl kullanabileceğinizi görebilirsiniz.
Komut satırını açın ve aşağıdaki komutu yazın:
scrapy shell
Anaconda kullanıyorsanız, yukarıdaki komutu anaconda isteminde de yazabilirsiniz. Komut satırında veya anaconda isteminde çıktınız aşağıdakine benzer olacaktır:
Scrapy shell’de fetch komutunu kullanarak web sayfası üzerinde bir tarayıcı çalıştırmanız gerekir. Bir tarayıcı veya spider, bir web sayfasını dolaşarak metnini ve üst verilerini indirir.
Not: URL’leri her zaman tırnak içine alın, tek ve çift tırnakların ikisi de çalışır
Çıktı aşağıdaki gibi olacaktır:
Tarayıcı, shell’de view(response) komutunu kullanarak görüntülenebilen bir response döndürür:
view(response)
Ve web sayfası varsayılan tarayıcıda açılacaktır.
Ham HTML betiğini Scrapy shell’de aşağıdaki komutu kullanarak görüntüleyebilirsiniz:
print(response.text)
Web sayfasını oluşturan betiği göreceksiniz. Bu, bir web sayfasında boş bir alana sağ tıklayıp kaynağı görüntüle veya sayfa kaynağını görüntüle dediğinizde gördüğünüzle aynıdır. Tüm betikten yalnızca ilgili bilgilere ihtiyaç duyduğunuz için, gerekli öğeyi incelemek üzere tarayıcı geliştirici araçlarını kullanacaksınız. Şu öğeleri ele alalım:
Tablet adı
Tablet fiyatı
Sipariş sayısı
Mağaza adı
İstediğiniz öğeye sağ tıklayın ve aşağıdaki gibi incele’yi tıklayın:
Tarayıcının geliştirici araçları web kazımada size çok yardımcı olacaktır. Bunun bir <a> etiketi ve class’ı product olan bir öğe olduğunu ve metnin ürün adını içerdiğini görebilirsiniz:
Çıkarmak için CSS Seçicilerini Kullanma
Bunu, öğe özniteliklerini veya sınıflar gibi css seçicilerini kullanarak çıkarabilirsiniz. Ürün adını çıkarmak için Scrapy shell’de aşağıdakini yazın:
response.css(".product::text").extract_first()
Çıktı şöyle olacaktır:
extract_first(), css seçicisini sağlayan ilk öğeyi çıkarır. Tüm ürün adlarını çıkarmak isterseniz extract() kullanın:
response.css(".product::text").extract()
Aşağıdaki kod ürünlerin fiyat aralığını çıkaracaktır:
response.css(".value::text").extract()
Benzer şekilde, sipariş sayısı ve mağaza adı için de deneyebilirsiniz.
Çıkarmak için XPath Kullanma
XPath, bir XML belgesindeki düğümleri seçmek için kullanılan bir sorgu dilidir [7]. XPath kullanarak bir XML belgesinde gezinebilirsiniz. Arka planda, Scrapy HTML belge öğelerinde gezinmek için XPath kullanır. Yukarıda kullandığınız CSS seçiciler de XPath’e dönüştürülür; ancak çoğu durumda CSS kullanımı çok daha kolaydır. Yine de Scrapy’de XPath’in nasıl çalıştığını bilmelisiniz.
Scrapy Shell’inize gidin ve daha öncekiyle aynı şekilde fetch(https://pt.aliexpress.com/category/201005406/special-store.html/) yazın. Aşağıdaki kod parçacıklarını deneyin [3]:
response.xpath('/html').extract()
Bu, <html> etiketinin altındaki tüm kodu gösterecektir. /, düğümün doğrudan çocuğu anlamına gelir. html etiketinin altındaki <div> etiketlerini almak isterseniz şöyle yazarsınız [3]:
response.xpath('/html//div').extract()
XPath için, alt ve soy düğümlerde nasıl gezinileceğini bilmek üzere / ve // kullanımını öğrenmelisiniz. XPath Düğümleri için yararlı bir eğitim ve denemek için bazı örnekler burada.
Tüm <div> etiketlerini almak isterseniz, /html kullanmadan derinleşerek bunu yapabilirsiniz [3]:
response.xpath("//div").extract()
Öznitelikleri ve değerlerini kullanarak başladığınız düğümleri daha da filtreleyebilir ve istediğiniz düğümlere ulaşabilirsiniz. Aşağıda sınıfları ve değerlerini kullanmanın sözdizimi verilmiştir.
Düğümlerin içindeki tüm metni çıkarmak için text() kullanın
Aşağıdaki HTML kodunu düşünün:
<div> öğesinin çocuk düğümü olan <a> etiketi içindeki metni almak istiyorsunuz; bu site-notice-container container sınıflarına sahip. Bunu şu şekilde yapabilirsiniz:
Web kazıma, verileri karşılaştırmak için kullanabileceğiniz bir toplayıcı (aggregator) oluşturmak amacıyla kullanılabilir. Örneğin, bir tablet satın almak istiyorsunuz ve ürünleri ve fiyatları birlikte karşılaştırmak istiyorsunuz; istediğiniz sayfaları tarayıp bir Excel dosyasına kaydedebilirsiniz. Burada tablet bilgileri için aliexpress.com’u kazıyacaksınız.
Şimdi, aynı sayfa için özel bir spider oluşturacaksınız. Önce, kodunuzun ve sonuçlarınızın depolanacağı bir Scrapy projesi oluşturmanız gerekir. Komut satırına veya anaconda istemine aşağıdaki komutu yazın.
scrapy startproject aliexpress
Bu, varsayılan python veya anaconda kurulumunuzda gizli bir klasör oluşturacaktır. aliexpress klasörün adı olacaktır. İstediğiniz adı verebilirsiniz. Klasör içeriğini doğrudan gezgin üzerinden görüntüleyebilirsiniz. Klasörün yapısı aşağıdaki gibidir:
dosya/klasör
Amacı
scrapy.cfg
dağıtım yapılandırma dosyası
aliexpress/
Projenin Python modülü; kodunuzu buradan içe aktaracaksınız
__init.py__
Başlatma dosyası
items.py
proje öğeleri dosyası
pipelines.py
proje veri hattı (pipeline) dosyası
settings.py
proje ayarları dosyası
spiders/
spider’larınızı daha sonra koyacağınız dizin
__init.py__
Başlatma dosyası
Projeyi oluşturduktan sonra yeni oluşturulan dizine geçecek ve şu komutu yazacaksınız:
Bu, yukarıda tartışıldığı gibi spiders dizininde aliexpress_tablets.py adlı bir şablon dosyası oluşturur. O dosyadaki kod aşağıdaki gibidir:
import scrapy
classAliexpressTabletsSpider(scrapy.Spider):
name ='aliexpress_tablets'
allowed_domains =['aliexpress.com']
start_urls =['https://www.aliexpress.com/category/200216607/tablets.html']defparse(self, response):passAltyapı:
Yukarıdaki kodda name, allowed_domains, sstart_urls ve bir parse fonksiyonunu görebilirsiniz.
name: Name, spider’ın adıdır. Uygun adlar, oluşturduğunuz tüm spider’ları takip etmenize yardımcı olur. Adlar benzersiz olmalıdır; çünkü scrapy crawl name_of_spider komutu kullanıldığında spider’ı çalıştırmak için kullanılır.
allowed_domains (isteğe bağlı): İsteğe bağlı bir Python listesi olup, taranmasına izin verilen alan adlarını içerir. Bu listede olmayan URL’lere yönelik istekler taranmaz. Bu liste yalnızca sitenin alan adını (Örnek: aliexpress.com) içermelidir; start_urls içinde belirtilen tüm URL’yi değil; aksi halde uyarılar alırsınız.
start_urls: Belirtilen URL’ler için istekleri yapar. Belirli URL’ler belirtilmediğinde spider’ın taramaya başlayacağı URL’lerin bir listesidir [4]. Dolayısıyla, ilk indirilen sayfalar burada listelenenler olacaktır. Sonraki istekler, başlangıç URL’lerinde yer alan verilerden ardışık olarak üretilecektir [4].
parse(self, response): Bu fonksiyon, bir URL başarıyla tarandığında çağrılır. Geri çağırma (callback) fonksiyonu olarak da bilinir. Taramanın sonucu olarak döndürülen response (Scrapy shell’de kullandığınız) bu fonksiyona aktarılır ve çıkarım kodunu bunun içine yazarsınız!
Bilgi: Scrapy spider’ının parse() fonksiyonu içinde HTML belgesini ayrıştırmak için BeautifulSoup kullanabilirsiniz.
Not: Veriyi, Scrapy shell bölümünde tartışıldığı gibi response.css() ile css seçicileri üzerinden çıkarabileceğiniz gibi, alt öğelere erişmenizi sağlayan XPath (XML) kullanarak da çıkarabilirsiniz. pass() fonksiyonunda düzenlenen kodda response.xpath() örneğini göreceksiniz.
aliexpress_tablet.py dosyasında değişiklikler yapacaksınız. start_urls içine başka bir URL ekledim. pass() fonksiyonuna çıkarım mantığını aşağıdaki gibi ekleyebilirsiniz:
# -*- coding: utf-8 -*-import scrapy
classAliexpressTabletsSpider(scrapy.Spider):
name ='aliexpress_tablets'
allowed_domains =['aliexpress.com']
start_urls =['https://www.aliexpress.com/category/200216607/tablets.html','https://www.aliexpress.com/category/200216607/tablets/2.html?site=glo&g=y&tag=']defparse(self, response):print("procesing:"+response.url)#Extract data using css selectors
product_name=response.css('.product::text').extract()
price_range=response.css('.value::text').extract()#Extract data using xpath
orders=response.xpath("//em[@title='Total Orders']/text()").extract()
company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract()
row_data=zip(product_name,price_range,orders,company_name)#Making extracted data row wisefor item in row_data:#create a dictionary to store the scraped info
scraped_info ={#key:value'page':response.url,'product_name': item[0],#item[0] means product in the list and so on, index tells what value to assign'price_range': item[1],'orders': item[2],'company_name': item[3],}#yield or give the scraped info to scrapyyield scraped_info
Altyapı:
Bilgi: zip(), n sayıda yinelenebilir nesneyi alır ve bir demet (tuple) listesi döndürür. Demetin i. öğesi, her yinelenebilir nesnenin i. öğesi kullanılarak oluşturulur. [8]
yield anahtar sözcüğü, bir üreteç (generator) fonksiyon tanımladığınızda kullanılır. Üreteç fonksiyon, return yerine yield kullanan normal bir fonksiyona benzer. yield anahtar sözcüğü, çağıran fonksiyon bir değer istediğinde kullanılır; yield içeren fonksiyon yerel durumunu korur ve değeri çağıran fonksiyona verdikten sonra kaldığı yerden çalışmaya devam eder. Burada yield, oluşturulan sözlüğü Scrapy’ye verir; Scrapy de bunu işler ve kaydeder!
Artık spider’ı çalıştırabilirsiniz:
scrapy crawl aliexpress_tablets
Komut satırında aşağıdakine benzer uzun bir çıktı göreceksiniz:
Veri Dışa Aktarma
Veriyi analiz için daha sonra kullanabilmek amacıyla CSV veya JSON olarak sunmanız gerekecektir. Bu bölümde, bu veriler için CSV ve JSON dosyasını nasıl kaydedebileceğiniz anlatılmaktadır.
Bir CSV dosyası kaydetmek için, proje dizininden settings.py’yi açın ve aşağıdaki satırları ekleyin:
FEED_URI [5]: Dosyanın konumunu belirtir. Dosyayı yerel dosya depolamada veya bir FTP’de de saklayabilirsiniz.
Scrapy’nin Akış Dışa Aktarma özelliği, dosya adınıza bir zaman damgası ve spider adını ekleyebilir veya bunları depolamak istediğiniz bir dizini belirtmek için kullanabilirsiniz.
%(time)s: akış oluşturulurken bir zaman damgası ile değiştirilir [5]
settings.py içinde yaptığınız Akış değişiklikleri, projedeki tüm spider’lar için geçerli olacaktır. Ayrıca, settings.py dosyasındaki ayarların üzerine yazacak şekilde belirli bir spider için özel ayarlar da belirleyebilirsiniz.
# -*- coding: utf-8 -*-import scrapy
classAliexpressTabletsSpider(scrapy.Spider):
name ='aliexpress_tablets'
allowed_domains =['aliexpress.com']
start_urls =['https://www.aliexpress.com/category/200216607/tablets.html','https://www.aliexpress.com/category/200216607/tablets/2.html?site=glo&g=y&tag=']
custom_settings={'FEED_URI':"aliexpress_%(time)s.json",'FEED_FORMAT':'json'}defparse(self, response):print("procesing:"+response.url)#Extract data using css selectors
product_name=response.css('.product::text').extract()
price_range=response.css('.value::text').extract()#Extract data using xpath
orders=response.xpath("//em[@title='Total Orders']/text()").extract()
company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract()
row_data=zip(product_name,price_range,orders,company_name)#Making extracted data row wisefor item in row_data:#create a dictionary to store the scraped info
scraped_info ={#key:value'page':response.url,'product_name': item[0],#item[0] means product in the list and so on, index tells what value to assign'price_range': item[1],'orders': item[2],'company_name': item[3],}#yield or give the scraped info to Scrapyyield scraped_info
Altyapı:
start_urls içinde iki bağlantı olduğunu fark etmiş olmalısınız. İkinci bağlantı, aynı tablet arama sonuçlarının 2. sayfasıdır. Tüm bağlantıları eklemek pratik olmayacaktır. Bir tarayıcı, tüm sayfaları kendi kendine tarayabilmeli; yalnızca başlangıç noktası start_urls içinde belirtilmelidir.
Bir sayfanın devam sayfaları varsa, sayfanın sonunda sayfalar arasında ileri geri gitmenizi sağlayan bir gezgin görürsünüz. Bu eğitimde uyguladığınız durumda, bunu şu şekilde göreceksiniz:
Göreceğiniz kod şudur:
Gördüğünüz gibi, altında geçerli sayfada olduğunuz .ui-pagination-active sınıfına sahip bir <span> etiketi var ve onun altında da sonraki sayfaya giden bağlantıları içeren tüm <a> etiketleri bulunuyor. Her seferinde bu <span> etiketinden sonraki <a> etiketlerini almanız gerekecek. İşte burada biraz CSS devreye giriyor! Bu durumda, bir alt düğümü değil, kardeş düğümü almalısınız; bu yüzden tarayıcıya, .ui-pagination-active sınıfına sahip <span> etiketinden sonra gelen <a> etiketlerini bulmasını söyleyen bir css seçici oluşturmanız gerekiyor.
Unutmayın! Her web sayfasının kendi yapısı vardır. İstediğiniz öğeyi nasıl elde edebileceğinizi anlamak için yapıyı biraz incelemeniz gerekir. Kod yazmadan önce her zaman Scrapy Shell’de response.css(SELECTOR) deneyin.
aliexpress_tablets.py dosyanızı aşağıdaki gibi değiştirin:
import scrapy
classAliexpressTabletsSpider(scrapy.Spider):
name ='aliexpress_tablets'
allowed_domains =['aliexpress.com']
start_urls =['https://www.aliexpress.com/category/200216607/tablets.html']
custom_settings={'FEED_URI':"aliexpress_%(time)s.csv",'FEED_FORMAT':'csv'}defparse(self, response):print("procesing:"+response.url)#Extract data using css selectors
product_name=response.css('.product::text').extract()
price_range=response.css('.value::text').extract()#Extract data using xpath
orders=response.xpath("//em[@title='Total Orders']/text()").extract()
company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract()
row_data=zip(product_name,price_range,orders,company_name)#Making extracted data row wisefor item in row_data:#create a dictionary to store the scraped info
scraped_info ={#key:value'page':response.url,'product_name': item[0],#item[0] means product in the list and so on, index tells what value to assign'price_range': item[1],'orders': item[2],'company_name': item[3],}#yield or give the scraped info to scrapyyield scraped_info
NEXT_PAGE_SELECTOR ='.ui-pagination-active + a::attr(href)'
next_page = response.css(NEXT_PAGE_SELECTOR).extract_first()if next_page:yield scrapy.Request(
response.urljoin(next_page),
callback=self.parse)Altyapı:
Yukarıdaki kodda:
Önce next_page = response.css(NEXT_PAGE_SELECTOR).extract_first() ile bir sonraki sayfanın bağlantısını çıkardınız ve ardından next_page değişkeni bir bağlantı alır ve boş olmazsa if gövdesine girer.
response.urljoin(next_page): parse() yöntemi bu yöntemi kullanarak yeni bir URL oluşturacak ve geri çağırmaya daha sonra gönderilecek yeni bir istek sağlayacaktır. [9]
Yeni URL alındıktan sonra, for gövdesini çalıştırarak o bağlantıyı kazıyacak ve tekrar bir sonraki sayfayı arayacaktır. Bu, bir sonraki sayfa bağlantısı bulunamayıncaya kadar devam edecektir.
Burada arkanıza yaslanıp spider’ınızın tüm sayfaları kazımasını izlemek isteyebilirsiniz. Yukarıdaki spider, tüm devam sayfalarından çıkarım yapacaktır. Bu epeyce kazıma demek! Ama spider’ınız bunu yapacak! Aşağıda dosya boyutunun 1,1 MB’a ulaştığını görebilirsiniz.
Scrapy sizin için yapar!
Bu eğitimde Scrapy’yi, BeautifulSoup ile nasıl karşılaştırıldığını, Scrapy Shell’i ve Scrapy’de kendi spider’larınızı nasıl yazacağınızı öğrendiniz. Scrapy, proje dosya ve klasörlerini oluşturmaktan yinelenen URL’leri ele almaya kadar, ağır kod yükünün tümünü sizin için üstlenir; dakikalar içinde yüksek güçlü web kazıma yapmanıza yardımcı olur ve diğer programlara aktarabileceğiniz yaygın veri formatları için destek sağlar. Bu eğitim, Scrapy’yi ve çatısını, ayrıca onunla neler yapabileceğinizi anlamanıza kesinlikle yardımcı olacaktır. Scrapy’de ustalaşmak için sunduğu tüm harika işlevleri gözden geçirmeniz gerekir; ancak bu eğitim, web sayfası gruplarını verimli bir şekilde kazıyabilecek duruma gelmenizi sağladı.
Algoritmalar, sistem tasarımı ve davranışsal senaryoları kapsayan bu temel sorularla teknik mülakat sürecine hakim olun. Uzman cevapları, kod örnekleri ve kanıtlanmış hazırlık stratejileri edinin.
Git deponuzu temiz tutmak için .gitignore’u nasıl kullanacağınızı öğrenin. Bu eğitim; temelleri, yaygın kullanım durumlarını ve başlamanıza yardımcı olacak pratik örnekleri kapsar!
Python ile web kazıma hakkında genel bir bakış isterseniz, DataCamp’in Python ile Web Kazıma kursunu inceleyin.
Bu eğitimde, büyük miktarda veriyi işleyebileceğiniz bir Python çatısı olan Scrapy’yi kullanmayı öğreneceksiniz! Bir e-ticaret sitesi olan AliExpress.com için bir web kazıyıcı oluşturarak Scrapy’yi öğreneceksiniz. Haydi kazımaya başlayalım!
Temel HTML ve CSS bilgisi, bu eğitimi daha kolay ve hızlı anlamanıza yardımcı olur. HTML ve CSS üzerine tazeleme için bu makaleyi okuyun.
Scrapy’ye Genel Bakış
Web kazıma, karar verme ve analiz için webden bilgi çıkarmanın etkili bir yolu haline geldi. Veri bilimi araç setinin vazgeçilmez bir parçası oldu. Veri bilimciler, web sayfalarından nasıl veri toplayacaklarını ve bu verileri ileri analiz için farklı formatlarda nasıl depolayacaklarını bilmelidir.
İnternette gördüğünüz herhangi bir web sayfası bilgi için taranabilir ve bir web sayfasında görünen her şey çıkarılabilir [2]. Her web sayfasının kendine özgü bir yapısı ve web öğeleri vardır; bu nedenle, kazıdığınız web sayfasına göre tarayıcılarınızı/spider’larınızı yazmanız gerekir.
Scrapy, kendisine bir dizi talimat verilen, kendi kendine yeten tarayıcılar olan
spider’ları kullanır [1]. Scrapy, geliştiricilerin kodlarını yeniden kullanmalarına olanak tanıyarak büyük tarama projelerini kurmayı ve ölçeklendirmeyi kolaylaştırır.Scrapy ve BeautifulSoup Karşılaştırması
Bu bölümde, en yaygın kullanılan web kazıma araçlarından biri olan BeautifulSoup’a ve Scrapy ile karşılaştırmasına genel bir bakış yapacaksınız.
Scrapy, geliştiricilere kod bakımıyla uğraşmadan eksiksiz bir paket sunan bir web kazıma Python çatısıdır.
Beautiful Soup da web kazıma için yaygın olarak kullanılır. HTML ve XML belgelerini ayrıştırmak ve bunlardan veri çıkarmak için bir Python paketidir. Python 2.6+ ve Python 3 için mevcuttur.
Özetle aralarındaki bazı farklar şunlardır:
requests,urlib2gibi ek kütüphanelere ihtiyaç duyar [6]Twisterkullandığı için oldukça akıcı yapar.multiprocessingkullanmazsanız Scrapy’den daha yavaştır.Bilgi: Eşzamanlı (synchronous) demek, yeni bir işe başlamadan önce mevcut işin bitmesini beklemeniz gerektiği; eşzamansız (asynchronous) ise önceki iş tamamlanmadan başka bir işe geçebileceğiniz anlamına gelir
Öğrenmek için ilgi çekici bir DataCamp BeautifulSoup eğitimi burada.
Scrapy Kurulumu
Python 3.0 (ve sonrası) kuruluysa ve anaconda kullanıyorsanız,
scrapy’yi kurmak içincondakullanabilirsiniz. Anaconda komut istemine aşağıdaki komutu yazın:conda install -c conda-forge scrapyAnaconda kurmak için, Mac ve Windows için bu DataCamp eğitimlerine bakın.
Alternatif olarak, Python Paket Yükleyicisi
pip’i kullanabilirsiniz. Bu, Linux, Mac ve Windows’ta çalışır:pip install scrapyScrapy Shell
Scrapy, geliştiricilerin bir sitenin davranışına ilişkin varsayımlarını test etmek için kullanabilecekleri Scrapy Shell adlı bir web tarama kabuğu da sunar. AliExpress e-ticaret sitesinde tabletler için bir web sayfası ele alalım. Scrapy shell’i kullanarak web sayfasının hangi bileşenleri döndürdüğünü ve bunları gereksinimlerinize göre nasıl kullanabileceğinizi görebilirsiniz.
Komut satırını açın ve aşağıdaki komutu yazın:
scrapy shellAnaconda kullanıyorsanız, yukarıdaki komutu anaconda isteminde de yazabilirsiniz. Komut satırında veya anaconda isteminde çıktınız aşağıdakine benzer olacaktır:
Scrapy shell’de
fetchkomutunu kullanarak web sayfası üzerinde bir tarayıcı çalıştırmanız gerekir. Bir tarayıcı veya spider, bir web sayfasını dolaşarak metnini ve üst verilerini indirir.fetch(https://pt.aliexpress.com/category/201005406/special-store.html)Not: URL’leri her zaman tırnak içine alın, tek ve çift tırnakların ikisi de çalışır
Çıktı aşağıdaki gibi olacaktır:
Tarayıcı, shell’de
view(response)komutunu kullanarak görüntülenebilen bir response döndürür:view(response)Ve web sayfası varsayılan tarayıcıda açılacaktır.
Ham HTML betiğini Scrapy shell’de aşağıdaki komutu kullanarak görüntüleyebilirsiniz:
print(response.text)Web sayfasını oluşturan betiği göreceksiniz. Bu, bir web sayfasında boş bir alana sağ tıklayıp kaynağı görüntüle veya sayfa kaynağını görüntüle dediğinizde gördüğünüzle aynıdır. Tüm betikten yalnızca ilgili bilgilere ihtiyaç duyduğunuz için, gerekli öğeyi incelemek üzere tarayıcı geliştirici araçlarını kullanacaksınız. Şu öğeleri ele alalım:
İstediğiniz öğeye sağ tıklayın ve aşağıdaki gibi
incele’yi tıklayın:Tarayıcının geliştirici araçları web kazımada size çok yardımcı olacaktır. Bunun bir
<a>etiketi veclass’ı product olan bir öğe olduğunu ve metnin ürün adını içerdiğini görebilirsiniz:Çıkarmak için CSS Seçicilerini Kullanma
Bunu, öğe özniteliklerini veya sınıflar gibi css seçicilerini kullanarak çıkarabilirsiniz. Ürün adını çıkarmak için Scrapy shell’de aşağıdakini yazın:
response.css(".product::text").extract_first()Çıktı şöyle olacaktır:
extract_first(), css seçicisini sağlayan ilk öğeyi çıkarır. Tüm ürün adlarını çıkarmak istersenizextract()kullanın:response.css(".product::text").extract()Aşağıdaki kod ürünlerin fiyat aralığını çıkaracaktır:
response.css(".value::text").extract()Benzer şekilde, sipariş sayısı ve mağaza adı için de deneyebilirsiniz.
Çıkarmak için XPath Kullanma
XPath, bir XML belgesindeki düğümleri seçmek için kullanılan bir sorgu dilidir [7]. XPath kullanarak bir XML belgesinde gezinebilirsiniz. Arka planda, Scrapy HTML belge öğelerinde gezinmek için XPath kullanır. Yukarıda kullandığınız CSS seçiciler de XPath’e dönüştürülür; ancak çoğu durumda CSS kullanımı çok daha kolaydır. Yine de Scrapy’de XPath’in nasıl çalıştığını bilmelisiniz.
Scrapy Shell’inize gidin ve daha öncekiyle aynı şekilde
fetch(https://pt.aliexpress.com/category/201005406/special-store.html/)yazın. Aşağıdaki kod parçacıklarını deneyin [3]:response.xpath('/html').extract()Bu,
<html>etiketinin altındaki tüm kodu gösterecektir./, düğümün doğrudan çocuğu anlamına gelir.htmletiketinin altındaki<div>etiketlerini almak isterseniz şöyle yazarsınız [3]:response.xpath('/html//div').extract()XPath için, alt ve soy düğümlerde nasıl gezinileceğini bilmek üzere
/ve//kullanımını öğrenmelisiniz. XPath Düğümleri için yararlı bir eğitim ve denemek için bazı örnekler burada.Tüm
<div>etiketlerini almak isterseniz,/htmlkullanmadan derinleşerek bunu yapabilirsiniz [3]:response.xpath("//div").extract()Öznitelikleri ve değerlerini kullanarak başladığınız düğümleri daha da filtreleyebilir ve istediğiniz düğümlere ulaşabilirsiniz. Aşağıda sınıfları ve değerlerini kullanmanın sözdizimi verilmiştir.
response.xpath("//div[@class='quote']/span[@class='text']").extract()response.xpath("//div[@class='quote']/span[@class='text']/text()").extract()Aşağıdaki HTML kodunu düşünün:
<div>öğesinin çocuk düğümü olan<a>etiketi içindeki metni almak istiyorsunuz; busite-notice-container containersınıflarına sahip. Bunu şu şekilde yapabilirsiniz:response.xpath('//div[@class="site-notice-container container"]/a[@class="notice-close"]/text()').extract()Bir Scrapy Projesi ve Özel Spider Oluşturma
Web kazıma, verileri karşılaştırmak için kullanabileceğiniz bir toplayıcı (aggregator) oluşturmak amacıyla kullanılabilir. Örneğin, bir tablet satın almak istiyorsunuz ve ürünleri ve fiyatları birlikte karşılaştırmak istiyorsunuz; istediğiniz sayfaları tarayıp bir Excel dosyasına kaydedebilirsiniz. Burada tablet bilgileri için aliexpress.com’u kazıyacaksınız.
Şimdi, aynı sayfa için özel bir spider oluşturacaksınız. Önce, kodunuzun ve sonuçlarınızın depolanacağı bir Scrapy projesi oluşturmanız gerekir. Komut satırına veya anaconda istemine aşağıdaki komutu yazın.
scrapy startproject aliexpressBu, varsayılan python veya anaconda kurulumunuzda gizli bir klasör oluşturacaktır.
aliexpressklasörün adı olacaktır. İstediğiniz adı verebilirsiniz. Klasör içeriğini doğrudan gezgin üzerinden görüntüleyebilirsiniz. Klasörün yapısı aşağıdaki gibidir:__init.py____init.py__Projeyi oluşturduktan sonra yeni oluşturulan dizine geçecek ve şu komutu yazacaksınız:
[scrapy genspider aliexpress_tablets](https://pt.aliexpress.com/category/201005406/special-store.html)Bu, yukarıda tartışıldığı gibi
spidersdizinindealiexpress_tablets.pyadlı bir şablon dosyası oluşturur. O dosyadaki kod aşağıdaki gibidir:Yukarıdaki kodda
name,allowed_domains, sstart_urlsve birparsefonksiyonunu görebilirsiniz.scrapy crawl name_of_spiderkomutu kullanıldığında spider’ı çalıştırmak için kullanılır.response(Scrapy shell’de kullandığınız) bu fonksiyona aktarılır ve çıkarım kodunu bunun içine yazarsınız!Bilgi: Scrapy spider’ının
parse()fonksiyonu içinde HTML belgesini ayrıştırmak için BeautifulSoup kullanabilirsiniz.Not: Veriyi, Scrapy shell bölümünde tartışıldığı gibi
response.css()ile css seçicileri üzerinden çıkarabileceğiniz gibi, alt öğelere erişmenizi sağlayan XPath (XML) kullanarak da çıkarabilirsiniz.pass()fonksiyonunda düzenlenen koddaresponse.xpath()örneğini göreceksiniz.aliexpress_tablet.pydosyasında değişiklikler yapacaksınız.start_urlsiçine başka bir URL ekledim.pass()fonksiyonuna çıkarım mantığını aşağıdaki gibi ekleyebilirsiniz:Bilgi:
zip(), n sayıda yinelenebilir nesneyi alır ve bir demet (tuple) listesi döndürür. Demetin i. öğesi, her yinelenebilir nesnenin i. öğesi kullanılarak oluşturulur. [8]yieldanahtar sözcüğü, bir üreteç (generator) fonksiyon tanımladığınızda kullanılır. Üreteç fonksiyon,returnyerineyieldkullanan normal bir fonksiyona benzer.yieldanahtar sözcüğü, çağıran fonksiyon bir değer istediğinde kullanılır;yieldiçeren fonksiyon yerel durumunu korur ve değeri çağıran fonksiyona verdikten sonra kaldığı yerden çalışmaya devam eder. Buradayield, oluşturulan sözlüğü Scrapy’ye verir; Scrapy de bunu işler ve kaydeder!Artık spider’ı çalıştırabilirsiniz:
scrapy crawl aliexpress_tabletsKomut satırında aşağıdakine benzer uzun bir çıktı göreceksiniz:
Veri Dışa Aktarma
Veriyi analiz için daha sonra kullanabilmek amacıyla CSV veya JSON olarak sunmanız gerekecektir. Bu bölümde, bu veriler için CSV ve JSON dosyasını nasıl kaydedebileceğiniz anlatılmaktadır.
Bir CSV dosyası kaydetmek için, proje dizininden
settings.py’yi açın ve aşağıdaki satırları ekleyin:settings.py’yi kaydettikten sonra, proje dizininizdescrapy crawlaliexpress_tabletskomutunu yeniden çalıştırın.CSV dosyası şöyle görünecektir:
Not: Spider’ı her çalıştırdığınızda dosyaya ekleme yapılır.
Scrapy’nin Akış Dışa Aktarma özelliği, dosya adınıza bir zaman damgası ve spider adını ekleyebilir veya bunları depolamak istediğiniz bir dizini belirtmek için kullanabilirsiniz.
%(time)s: akış oluşturulurken bir zaman damgası ile değiştirilir [5]%(name)s: spider adı ile değiştirilir [5]Örneğin:
ftp://user:[email protected]/scraping/feeds/%(name)s/%(time)s.jsonsettings.pyiçinde yaptığınız Akış değişiklikleri, projedeki tüm spider’lar için geçerli olacaktır. Ayrıca,settings.pydosyasındaki ayarların üzerine yazacak şekilde belirli bir spider için özel ayarlar da belirleyebilirsiniz.response.url, yanıtın üretildiği sayfanın URL’sini döndürür.scrapy crawl aliexpress_tabletskomutuyla tarayıcıyı çalıştırdıktan sonra json dosyasını görüntüleyebilirsiniz:Bağlantıları Takip Etme
start_urlsiçinde iki bağlantı olduğunu fark etmiş olmalısınız. İkinci bağlantı, aynı tablet arama sonuçlarının 2. sayfasıdır. Tüm bağlantıları eklemek pratik olmayacaktır. Bir tarayıcı, tüm sayfaları kendi kendine tarayabilmeli; yalnızca başlangıç noktasıstart_urlsiçinde belirtilmelidir.Bir sayfanın devam sayfaları varsa, sayfanın sonunda sayfalar arasında ileri geri gitmenizi sağlayan bir gezgin görürsünüz. Bu eğitimde uyguladığınız durumda, bunu şu şekilde göreceksiniz:
Göreceğiniz kod şudur:
Gördüğünüz gibi, altında geçerli sayfada olduğunuz
.ui-pagination-activesınıfına sahip bir<span>etiketi var ve onun altında da sonraki sayfaya giden bağlantıları içeren tüm<a>etiketleri bulunuyor. Her seferinde bu<span>etiketinden sonraki<a>etiketlerini almanız gerekecek. İşte burada biraz CSS devreye giriyor! Bu durumda, bir alt düğümü değil, kardeş düğümü almalısınız; bu yüzden tarayıcıya,.ui-pagination-activesınıfına sahip<span>etiketinden sonra gelen<a>etiketlerini bulmasını söyleyen bir css seçici oluşturmanız gerekiyor.aliexpress_tablets.pydosyanızı aşağıdaki gibi değiştirin:Yukarıdaki kodda:
Önce
next_page = response.css(NEXT_PAGE_SELECTOR).extract_first()ile bir sonraki sayfanın bağlantısını çıkardınız ve ardındannext_pagedeğişkeni bir bağlantı alır ve boş olmazsaifgövdesine girer.response.urljoin(next_page): parse() yöntemi bu yöntemi kullanarak yeni bir URL oluşturacak ve geri çağırmaya daha sonra gönderilecek yeni bir istek sağlayacaktır. [9]Yeni URL alındıktan sonra,
forgövdesini çalıştırarak o bağlantıyı kazıyacak ve tekrar bir sonraki sayfayı arayacaktır. Bu, bir sonraki sayfa bağlantısı bulunamayıncaya kadar devam edecektir.Burada arkanıza yaslanıp spider’ınızın tüm sayfaları kazımasını izlemek isteyebilirsiniz. Yukarıdaki spider, tüm devam sayfalarından çıkarım yapacaktır. Bu epeyce kazıma demek! Ama spider’ınız bunu yapacak! Aşağıda dosya boyutunun 1,1 MB’a ulaştığını görebilirsiniz.
Scrapy sizin için yapar!
Bu eğitimde Scrapy’yi, BeautifulSoup ile nasıl karşılaştırıldığını, Scrapy Shell’i ve Scrapy’de kendi spider’larınızı nasıl yazacağınızı öğrendiniz. Scrapy, proje dosya ve klasörlerini oluşturmaktan yinelenen URL’leri ele almaya kadar, ağır kod yükünün tümünü sizin için üstlenir; dakikalar içinde yüksek güçlü web kazıma yapmanıza yardımcı olur ve diğer programlara aktarabileceğiniz yaygın veri formatları için destek sağlar. Bu eğitim, Scrapy’yi ve çatısını, ayrıca onunla neler yapabileceğinizi anlamanıza kesinlikle yardımcı olacaktır. Scrapy’de ustalaşmak için sunduğu tüm harika işlevleri gözden geçirmeniz gerekir; ancak bu eğitim, web sayfası gruplarını verimli bir şekilde kazıyabilecek duruma gelmenizi sağladı.
Daha fazla okumak için Resmi Scrapy Dokümanlarına bakabilirsiniz.
Ayrıca DataCamp’in Python ile Web Kazıma kursunu da unutmayın.
Kaynakça