Cemre Acar
Scrapy Framework ile Web Scraping

Scrapy Framework ile Web Scraping

Genellikle Veri Kazıma , Scraping Nedir ? Scrapy Framework Nedir? İnternet üzerinden nasıl veri kazırım ? İnternetten nasıl veri toplarım ? gibi sorulara cevap olacak bir yazı ile karşınızdayım. Web kazıma veya web örümcek yazılım olarak adlandırılan web scraping, web'deki verilerle çalışmak için güçlü bir araçtır. Bir web scraper ile, bir dizi ürün hakkında veri çıkarabilir, oynamak için büyük bir metin veya niceliksel veri toplayabilir, resmi bir API'sı olmayan bir siteden veri alabilir veya sadece kendi merakınızı giderebilirsiniz. 

Peki gelelim bu işi nasıl yapacağımıza.. Bunun için bir çok kütüphane mevcut ama biz bu yazıda bir Python çatısı olan Scrapy Framework ile bir örümcek yazılım örneği oluşturacağız. Bu süreçte ProjectEuler websayfası üzerindeki soruları ve çözülme sayılarını elde etmeye çalışacağız ve bu verileri bir .txt dosyasına yazdıracağız , böylece örümcek yazılım sürecinin temelleri hakkında oldukça bilgi sahibi olacaksınız. Bu arada bilmeyenler için ProjectEuler içinde farklı zorluk seviyelerinde bir çok problem bulunan bir site. Kendinizi geliştirmek istiyorsanız kesinlikle problemlere göz atmanızı ve çabalamanızı öneririm. Özellikle algoritma mantığını geliştirmek için çok faydalıdır.

Şimdi geçelim kuruluma , ben tüm adımları Linux terminal ortamı üzerinden gerçekleştireceğim bu yüzden ilk olarak terminali açıyoruz ve pip ile kurulumumuzu gerçekleştiriyoruz. Pip, Python'da yazılmış yazılım paketlerini kurmak ve yönetmek için kullanılan fiili standart bir paket yönetim sistemidir. Temel terminal kullanımı hakkında bilginiz yok ise buradan bilgi edinebilirsiniz.

pip install scrapy

Kurulumu sorunsuz bir şekilde gerçekleştirdiyseniz bir klasör oluşturalım ve klasörün içine girip adımlarımızı sürdürelim. 

mkdir myapp-scraperfile
cd myapp-scraperfile

Şimdi klasörümüzün içinde Scrapy komutlarımızı kullanarak projemizi oluşturmaya başlayalım.

scrapy startproject myappname


Bu komutun ardından iskeletimiz bu şekildeki gibi gözükecektir.

Buradaki dosyalarımıza biraz değinmek gerekirse ;

» scrapy.cfg  Konfigürasyon dosyası

» items.py  Proje öğelerinin tanım dosyası

» middlewares.py  Projenin middlewares dosyası

» pipelines.py  Projenin pipelines dosyası

» settings.py  Projenin ayarlar dosyası

» spiders   Örümceklerimizi koyacağımız klasör.

Artık ilk örümceğimizi yazabiliriz. spider/ klasörünün altına myapp_spider.py adında bir Python dosyası oluşturuyoruz. 

Burada Scrapy Framework documentation üzerindeki iskeletten faydalandım ve şu şekilde class yapımı oluşturdum.

 

import scrapy

class EulerSpider(scrapy.Spider):

    name = "problems"

    mypage = 2

    problem_count = 1

    file = open("problems.txt","a",encoding = "UTF-8")

    start_urls = [

        "https://projecteuler.net/archives;page=1"

    ]

Siz class'ın ismini herhangi bir şey de koyabilirsiniz. URL kısmına bakacak olursak linkimizi başlangıç linki olarak ayarladık. Verilerimizi çekmeye bu sayfadan başlayacağız.



Peki bu verileri nasıl çekeceğiz nasıl bulacağız tüm sayfa içinde ? Class'ımızın içine bir method tanımlayıp istediğimiz verileri elde etmeye başlayalım.

    def parse(self, response):

        mytext = response.css("table#problems_table a").extract()

        problem_names = [u''.join(mytext.css('::text').extract()).strip() for mytext in response.css("table#problems_table a")]

        problem_solved_count = response.css("table#problems_table div::text").extract()

Burada ne yaptığımıza değinecek olursak , ProjectEuler web sayfasındaki 'Description' ve 'Solved By' kısımlarındaki verileri istiyorduk ve bunların yolunu ya XPath ile ya da CSS selector ile belirtmemiz gerekiyor. Ben burada CSS selector kullanarak ilerliyorum dilerseniz XPath ile de bu işlemi yapabilirsiniz. İlk değişkenimiz olan mytext bize 'description' kısmını getiriyor ve ikinci değişken problem_names ilk değişkenimizin getirdiği veriyi tek satırda yazmamıza yarıyor ve son olarak problem_solved_count sayfamızdaki 'solved by' kısmını getiriyor. Şimdi burada değinmek istediğim ufak bir nokta var. Aslında problem_names değişkenine ihtiyaç duymadan direkt olarak ;

mytext = response.css("table#problems_table a ::text").extract()

yazabilirdik. Şöyle ki , ProjectEuler 141. sorusunda bir problem ile karşılaştım. Yazılı problemin içinde italic olarak 'n' harfi yazılmış. Biz direkt olarak veriye ulaştığımızda 141. soru 3 ayrı şekilde bölünüyor. Bu yüzden extra bir işlem yapıp problem_names değişkenini oluşturduk. Bu kısmı da detaylıca irdeledikten sonra bu çektiğimiz verileri bir dosyaya yazma aşamasına geldik. 

        i = 0

        while (i < len(problem_names)):

            self.file.write("-----------------------------------------------\n")

            self.file.write(str(self.problem_count) + ".\n")

            self.file.write("Problem İsmi : " + problem_names[i] + "\n")

            self.file.write("Çözüm Sayısı : " + problem_solved_count[i] + "\n")

            self.file.write("-----------------------------------------------\n")

            self.problem_count += 1

            i += 1

Dosyamızı yeterince süslediysek şimdi geçelim sayfaları gezmeye buraya kadar yaptıklarımız start_urls kısmında belirttiğimiz ilk sayfamız içindi. Peki biz sayfaları nasıl gezeceğiz ?


        next_url = "https://projecteuler.net/archives;page={}".format(self.mypage)

        self.mypage += 1

ProjectEuler üzerinde sayfaları gezdiğinizde '/archives;page=...' kısmına dikkat edin. URL siz hangi sayfaya giderseniz o sayfanın numarasıyla değişiyor. Bu sayede biz de next_url değişkenimizle sayfaları gezebiliyoruz. Artık son olarak sayfa kontrollerini yapıp projemizi çalıştırabiliriz. 

        if self.mypage != 5:

            yield scrapy.Request(url = next_url,callback = self.parse)

        else:

            self.file.close()

Yazının başında da belirttiğim gibi hedefimiz ilk 150 soruyu dosyamıza yazdırmaktı.Bu yüzden mypage değişkenimiz 5'e ulaştığında if statement'tan çıkıp ilk 3 sayfamızı gezmiş oluyoruz sonrasında .txt dosyamızı güvenli bir şekilde kapatıyoruz. Tüm bu işlemlerden sonra dosyamızın son hali aşağıdaki gibi gözükmektedir.

import scrapy

class EulerSpider(scrapy.Spider):

    name = "problems"

    mypage = 2

    problem_count = 1

    file = open("problems.txt","a",encoding = "UTF-8")

    start_urls = [

        "https://projecteuler.net/archives;page=1"

    ]

    def parse(self, response):

        mytext = response.css("table#problems_table a").extract()

        problem_names = [u''.join(mytext.css('::text').extract()).strip() for mytext in response.css("table#problems_table a")]

        problem_solved_count = response.css("table#problems_table div::text").extract()


        i = 0

        while (i < len(problem_names)):  

            self.file.write("-----------------------------------------------\n")

            self.file.write(str(self.problem_count) + ".\n")

            self.file.write("Problem İsmi : " + problem_names[i] + "\n")

            self.file.write("Çözüm Sayısı : " + problem_solved_count[i] + "\n")

            self.file.write("-----------------------------------------------\n")

            self.problem_count += 1

            i += 1

        next_url = "https://projecteuler.net/archives;page={}".format(self.mypage)

        self.mypage += 1


        if self.mypage != 5:

            yield scrapy.Request(url = next_url,callback = self.parse)

        else:

            self.file.close()

Bu projeye ayrıca Portfolio üzerinden erişim sağlayabilirsiniz. Umarım anlatım yararlı olmuştur. Bu yazıda yetersiz ya da eksik bulduğunuz bir konuyu yorum olarak yazarsanız , yazıyı güncelleyerek herkese faydalı olmaya çalışırım. Kolay gelsin.

Heyy ! Blog'a abone olup yazılarımdan ilk sen haberdar olmak ister misin ?

ABONE OL!

Yorumlar

Yorum Ekle

Yorumunuz onaylandıktan sonra yayınlanacaktır.