Scrapy ile Ölçeklenebilir Web Kazıyıcıları Oluşturmak İçin En İyi Kılavuz

Yayınlanan: 2022-03-10
Kısa özet ↬ Scrapy, ölçeklenebilir web kazıyıcıları yazmak için popüler bir açık kaynaklı Python çerçevesidir. Bu eğitimde, Wikipedia'dan Oscar ödüllü filmlerin bir listesini toplamak için Scrapy'yi kullanarak adım adım yol göstereceğiz.

Web kazıma, API'lere veya web sitesinin veritabanına erişmeye gerek kalmadan web sitelerinden veri almanın bir yoludur. Yalnızca sitenin verilerine erişmeniz gerekir - tarayıcınız verilere erişebildiği sürece, bunları kazıyabilirsiniz.

Gerçekçi olarak, çoğu zaman bir web sitesini manuel olarak inceleyebilir ve verileri kopyala ve yapıştır kullanarak 'elle' alabilirsiniz, ancak çoğu durumda bu saatlerce süren manuel çalışmanızı gerektirebilir ve bu da size bir maliyete mal olabilir. özellikle sizin için görevi yapması için birini işe aldıysanız, verilerden çok daha fazlası değerlidir. Her birkaç saniyede bir otomatik olarak bir sorgu gerçekleştirecek bir programa sahipken, neden birisini sorgu başına 1-2 dakikada çalışacak şekilde işe almalısınız?

Örneğin, en iyi film için Oscar kazananların bir listesini, yönetmenleri, başrol oyuncuları, çıkış tarihi ve çalışma süresi ile birlikte derlemek istediğinizi varsayalım. Google'ı kullanarak, bu filmleri adlarına ve belki de bazı ek bilgilere göre listeleyen birkaç site olduğunu görebilirsiniz, ancak genellikle istediğiniz tüm bilgileri yakalamak için bağlantıları takip etmeniz gerekir.

Açıktır ki, 1927'den günümüze kadar her bağlantıyı incelemek ve her sayfadan bilgiyi manuel olarak bulmaya çalışmak pratik ve zaman alıcı olmayacaktır. Web kazıma ile, tüm bu bilgileri içeren sayfalara sahip bir web sitesi bulmamız ve ardından programımızı doğru talimatlarla doğru yöne yönlendirmemiz gerekiyor.

Bu eğitimde, ihtiyacımız olan tüm bilgileri içerdiği için web sitemiz olarak Wikipedia'yı kullanacağız ve ardından bilgilerimizi sıyırmak için bir araç olarak Python'da Scrapy kullanacağız.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Başlamadan önce birkaç uyarı:

Veri kazıma, kazıdığınız site için sunucu yükünü artırmayı içerir; bu, siteyi barındıran şirketler için daha yüksek maliyet ve o sitenin diğer kullanıcıları için daha düşük kaliteli bir deneyim anlamına gelir. Web sitesini çalıştıran sunucunun kalitesi, elde etmeye çalıştığınız veri miktarı ve sunucuya istek gönderme hızınız, sunucu üzerindeki etkinizi azaltacaktır. Bunu akılda tutarak, birkaç kurala bağlı kaldığımızdan emin olmamız gerekir.

Çoğu sitenin ana dizininde robots.txt adlı bir dosya da bulunur. Bu dosya, sitelerin sıyırıcıların erişmesini istemediği dizinlere ilişkin kuralları belirler. Bir web sitesinin Şartlar ve Koşullar sayfası, genellikle veri kazıma konusundaki politikalarının ne olduğunu size bildirir. Örneğin, IMDB'nin koşullar sayfasında aşağıdaki madde bulunur:

Robotlar ve Ekran Kazıma: Aşağıda belirtilen açık yazılı iznimiz dışında, bu sitede veri madenciliği, robotlar, ekran kazıma veya benzeri veri toplama ve çıkarma araçlarını kullanamazsınız.

Bir web sitesinin verilerini elde etmeye çalışmadan önce, yasal veriler aldığımızdan emin olmak için her zaman web sitesinin şartlarını ve robots.txt kontrol etmeliyiz. Sıyırıcılarımızı oluştururken, bir sunucuyu işleyemeyeceği isteklerle boğmadığımızdan da emin olmamız gerekir.

Neyse ki, birçok web sitesi, kullanıcıların veri edinme ihtiyacını kabul eder ve verileri API'ler aracılığıyla kullanılabilir hale getirir. Bunlar mevcutsa, API aracılığıyla veri elde etmek genellikle kazıma yoluyla elde etmekten çok daha kolay bir deneyimdir.

Wikipedia, robots.txt belirtildiği gibi, botlar 'çok hızlı' gitmediği sürece verilerin kazınmasına izin verir. Ayrıca, insanların verileri kendi makinelerinde işleyebilmeleri için indirilebilir veri kümeleri sağlarlar. Çok hızlı gidersek, sunucular IP'mizi otomatik olarak engeller, bu yüzden onların kurallarına uymak için zamanlayıcılar uygularız.

Başlarken, Pip Kullanarak İlgili Kitaplıkları Kurma

Her şeyden önce, başlamak için, Scrapy'yi yükleyelim.

pencereler

https://www.python.org/downloads/windows/ adresinden Python'un en son sürümünü yükleyin.

Not: Windows kullanıcıları ayrıca, buradaki “Microsoft Visual C++ Yapı Araçları”ndan alabileceğiniz Microsoft Visual C++ 14.0'a da ihtiyaç duyacaktır.

Ayrıca pip'in en son sürümüne sahip olduğunuzdan emin olmak isteyeceksiniz.

cmd.exe'de şunu yazın:

 python -m pip install --upgrade pip pip install pypiwin32 pip install scrapy

Bu, Scrapy'yi ve tüm bağımlılıkları otomatik olarak kuracaktır.

Linux

İlk önce tüm bağımlılıkları yüklemek isteyeceksiniz:

Terminal'de şunu girin:

 sudo apt-get install python3 python3-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

Hepsi yüklendikten sonra, şunu yazın:

 pip install --upgrade pip

Pip'in güncellendiğinden emin olmak için ve ardından:

 pip install scrapy

Ve hepsi bitti.

Mac

Öncelikle sisteminizde bir c-derleyici olduğundan emin olmanız gerekir. Terminal'de şunu girin:

 xcode-select --install

Bundan sonra, https://brew.sh/ adresinden homebrew yükleyin.

PATH değişkeninizi, homebrew paketlerinin sistem paketlerinden önce kullanılması için güncelleyin:

 echo "export PATH=/usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc source ~/.bashrc

Python'u yükleyin:

 brew install python

Ve sonra her şeyin güncellendiğinden emin olun:

 brew update; brew upgrade python

Bu yapıldıktan sonra, pip kullanarak Scrapy'yi kurmanız yeterlidir:

 pip install Scrapy
> ## Scrapy'ye Genel Bakış, Parçaların Bir Araya Nasıl Geldiği, Ayrıştırıcılar, Örümcekler vb.

Scrapy'nin çalışması için 'Örümcek' adında bir senaryo yazacaksınız, ama merak etmeyin, Scrapy örümcekleri isimlerine rağmen hiç de korkutucu değiller. Scrapy örümcekleri ile gerçek örümceklerin sahip oldukları tek benzerlik, internette gezinmeyi sevmeleridir.

Örümceğin içinde, sizin tanımladığınız ve Scrapy'ye ne yapacağını söyleyen bir class bulunur. Örneğin, taramaya nereden başlayacağınız, yaptığı istek türleri, sayfalardaki bağlantıları nasıl takip edeceğiniz ve verileri nasıl ayrıştıracağı. Bir dosyaya geri dönmeden önce verileri işlemek için özel işlevler bile ekleyebilirsiniz.

## İlk Örümceğinizi Yazın, Uygulamalı Öğrenmeye İzin Vermek İçin Basit Bir Örümcek Yazın

İlk örümcekimizi başlatmak için önce bir Scrapy projesi oluşturmamız gerekiyor. Bunu yapmak için komut satırınıza şunu girin:

 scrapy startproject oscars

Bu, projenizle birlikte bir klasör oluşturacaktır.

Temel bir örümcekle başlayacağız. Aşağıdaki kod bir python betiğine girilecektir. /oscars/spiders içinde yeni bir python betiği açın ve oscars_spider.py olarak adlandırın

Scrapy'yi içe aktaracağız.

 import scrapy

Ardından Spider sınıfımızı tanımlamaya başlıyoruz. İlk önce adı ve ardından örümceğin sıyırmasına izin verilen etki alanlarını belirledik. Son olarak, örümceğe nereden kazımaya başlayacağını söyleriz.

 class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ['https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture']

Ardından, istediğimiz bilgiyi yakalayacak bir fonksiyona ihtiyacımız var. Şimdilik, sadece sayfa başlığını alacağız. Başlık metnini taşıyan etiketi bulmak için CSS kullanıyoruz ve sonra onu çıkarıyoruz. Son olarak, bilgileri günlüğe kaydedilmek veya bir dosyaya yazılmak üzere Scrapy'ye geri döndürürüz.

 def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Şimdi kodu /oscars/spiders/oscars_spider.py içine kaydedin

Bu örümceği çalıştırmak için komut satırınıza gidin ve şunu yazın:

 scrapy crawl oscars

Bunun gibi bir çıktı görmelisiniz:

 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished)

Tebrikler, ilk temel Scrapy kazıyıcınızı yaptınız!

Tam kod:

 import scrapy class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Açıkçası, biraz daha fazlasını yapmasını istiyoruz, bu yüzden verileri ayrıştırmak için Scrapy'nin nasıl kullanılacağına bakalım.

İlk olarak, Scrapy kabuğunu tanıyalım. Scrapy kabuğu, Scrapy'nin istediğiniz verileri aldığından emin olmak için kodunuzu test etmenize yardımcı olabilir.

Kabuğa erişmek için bunu komut satırınıza girin:

 scrapy shell “https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture”

Bu, temelde onu yönlendirdiğiniz sayfayı açar ve tek satır kod çalıştırmanıza izin verir. Örneğin, şunu yazarak sayfanın ham HTML'sini görüntüleyebilirsiniz:

 print(response.text)

Veya şunu yazarak sayfayı varsayılan tarayıcınızda açın:

 view(response)

Buradaki amacımız, istediğimiz bilgileri içeren kodu bulmaktır. Şimdilik sadece film isimlerini almaya çalışalım.

İhtiyacımız olan kodu bulmanın en kolay yolu, sayfayı tarayıcımızda açıp kodu incelemektir. Bu örnekte, Chrome DevTools kullanıyorum. Herhangi bir film başlığına sağ tıklayın ve 'incele'yi seçin:

HTML ve CSS'yi incelemek için Chrome DevTools'u kullanma
Chrome Geliştirme Araçları penceresi. (Büyük önizleme)

Gördüğünüz gibi, Oscar kazananlar sarı bir arka plana sahipken, adaylar sade bir arka plana sahip. Ayrıca film başlığıyla ilgili makaleye bir bağlantı var ve filmlerin bağlantıları filmde bitiyor film) . Artık bunu bildiğimize göre, verileri almak için bir CSS seçici kullanabiliriz. Scrapy kabuğuna şunu yazın:

 response.css(r"tr[] a[href*='film)']").extract()

Gördüğünüz gibi, artık tüm Oscar En İyi Film Kazananlarının bir listesi var!

 > response.css(r"tr[] a[href*='film']").extract() ['<a href="/wiki/Wings_(1927_film)" title="Wings (1927 film)">Wings</a>', ... '<a href="/wiki/Green_Book_(film)" title="Green Book (film)">Green Book</a>', '<a href="/wiki/Jim_Burke_(film_producer)" title="Jim Burke (film producer)">Jim Burke</a>']

Ana hedefimize dönersek, yönetmenleri, başrol oyuncuları, çıkış tarihi ve çalışma süresi ile birlikte en iyi film için Oscar kazananların bir listesini istiyoruz. Bunu yapmak için, bu film sayfalarının her birinden veri almak için Scrapy'ye ihtiyacımız var.

Birkaç şeyi yeniden yazmamız ve yeni bir işlev eklememiz gerekecek, ancak endişelenmeyin, oldukça basit.

Kazıyıcıyı daha önce olduğu gibi başlatarak başlayacağız.

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"]

Ama bu sefer iki şey değişecek. İlk olarak, scrapy ile birlikte time içe aktaracağız çünkü botun ne kadar hızlı sıyırdığını kısıtlamak için bir zamanlayıcı oluşturmak istiyoruz. Ayrıca, sayfaları ilk kez ayrıştırdığımızda, yalnızca her bir başlığın bağlantılarının bir listesini almak istiyoruz, böylece bunun yerine bu sayfalardan bilgi alabiliriz.

 def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req

Burada, sayfadaki sarı arka plana sahip her bağlantıyı aramak için bir döngü yaparız ve sonra bu bağlantıları bir URL listesi halinde birleştiririz ve daha ileri parse_titles film) göndeririz. Ayrıca, yalnızca her 5 saniyede bir sayfa istemesi için bir zamanlayıcı ekledik. Doğru verileri aldığımızdan emin olmak için answer.css alanlarımızı test etmek için Scrapy kabuğunu kullanabileceğimizi unutmayın!

 def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Asıl iş, data adı verilen bir sözlük oluşturduğumuz ve ardından her anahtarı istediğimiz bilgiyle doldurduğumuz parse_data işlevimizde yapılır. Yine, tüm bu seçiciler, daha önce gösterildiği gibi Chrome DevTools kullanılarak bulundu ve ardından Scrapy kabuğuyla test edildi.

Son satır, veri sözlüğünü saklamak için Scrapy'ye geri döndürür.

Kodu tamamlayın:

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Web siteleri kazıma girişimlerimizi engellemeye çalışacağından bazen proxy kullanmak isteyeceğiz.

Bunu yapmak için sadece birkaç şeyi değiştirmemiz gerekiyor. Örneğimizi kullanarak, def parse() içinde, onu aşağıdaki şekilde değiştirmemiz gerekiyor:

 def parse(self, response): for href in (r"tr[] a[href*='film)']::attr(href)").extract() : url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) req.meta['proxy'] = "https://yourproxy.com:80" yield req

Bu, istekleri proxy sunucunuz üzerinden yönlendirecektir.

Dağıtım ve Günlüğe Kaydetme, Üretimde Bir Örümceğin Gerçekte Nasıl Yönetileceğini Göster

Şimdi örümceğimizi çalıştırma zamanı. Scrapy'nin kazımaya başlamasını ve ardından bir CSV dosyasına çıktı almasını sağlamak için komut isteminize aşağıdakini girin:

 scrapy crawl oscars -o oscars.csv

Büyük bir çıktı göreceksiniz ve birkaç dakika sonra tamamlanacak ve proje klasörünüzde oturan bir CSV dosyanız olacak.

Sonuçları Derleme, Önceki Adımlarda Derlenen Sonuçların Nasıl Kullanılacağını Göster

CSV dosyasını açtığınızda, istediğimiz tüm bilgileri göreceksiniz (başlıklı sütunlara göre sıralanmış). Gerçekten bu kadar basit.

Oscar ödüllü filmlerin ve ilgili bilgilerin CSV'si
Oscar ödüllü filmler listesi ve bilgiler. (Büyük önizleme)

Veri kazıma ile, bilgiler herkese açık olduğu sürece, istediğimiz hemen hemen her özel veri kümesini elde edebiliriz. Bu verilerle ne yapmak istediğiniz size kalmış. Bu beceri, pazar araştırması yapmak, bir web sitesindeki bilgileri güncel tutmak ve diğer birçok şey için son derece yararlıdır.

Özel veri kümelerini kendi başınıza elde etmek için kendi web kazıyıcınızı kurmak oldukça kolaydır, ancak ihtiyacınız olan verileri elde etmenin başka yolları da olabileceğini her zaman unutmayın. İşletmeler, istediğiniz verileri sağlamaya çok yatırım yapar, bu nedenle onların hüküm ve koşullarına saygı göstermemiz adil olur.

Genel Olarak Scrapy ve Web Scraping Hakkında Daha Fazla Bilgi Edinmek İçin Ek Kaynaklar

  • Resmi Scrapy Web Sitesi
  • Scrapy'nin GitHub Sayfası
  • “En İyi 10 Veri Kazıma Aracı ve Web Kazıma Aracı,” Scraper API
  • “Engellenmeden veya Kara Listeye Alınmadan Web Kazıma İçin 5 İpucu,” Kazıyıcı API
  • Parsel, HTML'den veri çıkarmak için normal ifadeleri kullanan bir Python kitaplığı.