Günümüz interneti gerekli gereksiz her bilgiyi içeren büyük bir veri yığını. Bu yığın içersinide sadece bizim için gerekli bilgilere ulaşmak bazen oldukça önemli oluyor. Bu noktada web scraping konusunda yetenekli olamamız gerekiyor. Blogumun ilk içeriği olan bu yazıda elimden geldiğince bu konu üzerinde duracağım.
Web Scraping Nedir?
Web scraping'i türkçeye çevirmeye çalıştığımızda Web'i kazıma gibi bir anlamı çıkıyor. Esasında yaptığımız iş, bulma ve parçalama işlemi. Web scraping'i kavramak için bir web sayfasının nasıl görüntülendiğini anlamamız gerekiyor.
Web sayfaları html dediğimiz bir markup dili ile yazılıyor. Web tarayıcıları(Chrome, Firefox... gibi) bu html kodlarını sahip oldukları motorlar sayesinde anlamlı site görünümlerine dönüştürüyor. Eğer statik bir sitenin html kodunu elde edebilirseniz sayfa hakkında tüm yazılara, resimlere, bağlantılara ve diğer verilere ulaşabiliyorsunuz. Site içinde sadece kendi istediğimiz verileri çekme işlemine de Web Scraping deniyor.
Gelin isterseniz bu işlemi kodlayarak anlayalım. Web Scraping için Python'un iki tane güçlü kütüphanesi var. requests ve Beautiful Soup.
Kodlayalım
Öncelikle yukarda belirtiğim iki kütüphaneyi kuralım
$ pip install beautifulsoup4 requests
requests ile web sayfalarında istekte bulunup geriye dönen değerleri (ki bunlar genelde html formatında olur) okuyabiliceğiz.
beautifulsoup4 ile ise string formatında gelen html'de parçalama ve arama yapabileceğiz.
Bir seneryo üzerinden devam edelim. Seneryoya göre https://github.com/django sitesinden djangoya ait tüm repoları ve repolara ait bilgileri çekmek istiyoruz diyelim.
Aşama 1: Veri Kaynağının İncelenmesi
Amacımız işaretlediğim kısımları çekmek olsun.
Bunun için öncelikle scrape etmek istediğimiz datanın unique(eşsiz) bir özeliğini bulmamız lazım. Bu bazen bir class ismi bazen id olabilir. Tarayıcınızın dev tool'u bu iş için bayağı uygun.
Görüldüğü gibi istediğimiz veriler repo-list class'ına sahip bir div elementinini içinde. Bu bilgiyi aklımızda tutalım ve kodlamay başlayalım.
Aşama 2: Veri Kaynağından Verilerin Çekilmesi
Python da bir sitenin html kaynak kodunu çekmek oldukça kolaydır.
import requests
res = requests.get("https://github.com/django")
source = res.text
print(source)
Şimdi elimizdeki bu ham datayı BeautifulSoup kullanarak yontalım.
from bs4 import BeautifulSoup
import requests
res = requests.get("https://github.com/django")
source = res.text
soup = BeautifulSoup(source, "html.parser")
BeautifulSoup'un aldığı ikinci parametre olan html.parser, BeautifulSoup'a hangi tipde bir parse işlemi yapacağını bildiriyor. html.parser yerine daha hızlı olan lxml parserini de kullanabilirdik. Ama lxml paketini projeye dahil etmek gerekirdi. O yüzden Python'un kendi html.parser'inden devam edelim.
Şimdi yukarda bahsettiğimiz repo-list sınıfını kullanarak verileri parse edelim. Bunun için soup nesnesine .find() methodunu kullanacağız.
.find() methodunun ilk parametresi source treede aranacak olan elemanın ismidir. Yani bir html element ismi alır. attrs ise o elementin hangi özelikleri olduğunu belirtmek için kullanılır. Biz burada class'ı repo-list olan bir div elementini scrape etmesini söyledik. Yani BeautifulSoup, kaynak kodda şu patterne sahip ilk gördüğü elementi geri dönürecektir.
<div class="repo-list">
[...]
</div>
Sonuca baktığımızda istediğimizi elde ettiğimizi görüyoruz
Burada tüm li elemenlerinin içindeki a tagının içeriğine erişmek için .text'i kullandık. .text html taglarının içindeki veriyi string şeklinde verir.
Hadi bu çıktıyı daha güzel hale getirelim
from bs4 import BeautifulSoup
import requests
import re
res = requests.get("https://github.com/django")
source = res.text
soup = BeautifulSoup(source, "html.parser")
repo_list = soup.find('div', attrs={"class": "repo-list"})
repos = repo_list.find_all('li')
template = """
Isim: {name}
Aciklama: {desc}
Star: {star}
================"""
for repo in repos:
name = repo.find("a").text.strip()
desc = ""
if repo.find('p'): ## Eğer açıklama varsa
desc = repo.find('p').text.strip()
star = repo.find(href=lambda x: x and re.compile("stargazers").search(x)).text.strip()
print(template.format(name=name, desc=desc, star=star))
Sonuç:
Isim: django
Aciklama: The Web framework for perfectionists with deadlines.
Star: 46,040
================
Isim: djangoproject.com
Aciklama: Source code to djangoproject.com
Star: 1,151
================
Isim: channels
Aciklama: Developer-friendly asynchrony for Django
Star: 4,141
================
Isim: daphne
Aciklama: Django Channels HTTP/WebSocket server
Star: 1,120
================
Isim: code.djangoproject.com
Aciklama: Configuration for Django's Trac instance (code.djangoproject.com)
Star: 33
================
Isim: django-docs-translations
Aciklama: Translations of the Django documentation. Questions and discussions happen on https://groups.google.com/forum/#!forum/django-i18n
Star: 37
================
Isim: django-contrib-comments
Aciklama:
Star: 358
================
Isim: django-localflavor
Aciklama: Country-specific Django helpers, formerly of contrib fame
Star: 498
================
[...]
[...]
Isim: djangobench
Aciklama: Harness and benchmarks for evaluating Django's performance over time
Star: 165
================
Isim: django-box
Aciklama: VM to run the Django test suite. ARCHIVED Please use https://github.com/django/django-docker-box
Star: 60
================
Buradaki
star = repo.find(href=lambda x: x and re.compile("stargazers").search(x)).text.strip()
kodu kafa karıştırıcı olabilir. Aslında yaptığı işlem çok basit. li elementini tutan repo nesnesinin .find methodu ile, eğer herhangi bir elementin href alanı "stargazers" stringini içeriyorsa onu geri döndürüyor. Bu da repoya verilen starları scrape etmemizi sağlıyor.
Bitirirken...
Doğruyu söylemek gerekirse buraya kadar anlattığım şeyler Web Scraping işlmeminin çok küçük bir kısmı. BeautifulSoup'un dökümantasyonunda keşfedilmeyi bekleyen daha o kadar çok şey varki. Bu işte biraz daha vakit geçirdiğinizde Web Scraping'in sadece BeautifulSoup ve requests'den ibaret olmadığını göreceksiniz. Karşınızda her zaman statik bir veri döndüren sayfalar gelmeyecek. Bazı sayfalar kendi içeriklerini javascript ile oluşturur. Ve anlamlı verilerin oluşması için bir tarayıcı motoruna ihtiyaç duyar. Böyle durumda geleneksel yöntemleri kullanarak (bizim requests ile kaynak kod çekmek gibi) elde ettiğiniz şey sadece Javascript'in bundle dosyası olacaktır muhtemelen. Bunun için arkada bir tarayıcı motoru ve sağladığı API'leri kullanmak gerekiyor. Mesela Selenium bu iş için oldukça uygundur.
Günümüz interneti gerekli gereksiz her bilgiyi içeren büyük bir veri yığını. Bu yığın içersinide sadece bizim için gerekli bilgilere ulaşmak bazen oldukça önemli oluyor. Bu noktada
web scraping
konusunda yetenekli olamamız gerekiyor. Blogumun ilk içeriği olan bu yazıda elimden geldiğince bu konu üzerinde duracağım.Web Scraping Nedir?
Web scraping'i türkçeye çevirmeye çalıştığımızda Web'i kazıma gibi bir anlamı çıkıyor. Esasında yaptığımız iş, bulma ve parçalama işlemi. Web scraping'i kavramak için bir web sayfasının nasıl görüntülendiğini anlamamız gerekiyor.
Web sayfaları
html
dediğimiz bir markup dili ile yazılıyor. Web tarayıcıları(Chrome, Firefox... gibi) bu html kodlarını sahip oldukları motorlar sayesinde anlamlı site görünümlerine dönüştürüyor. Eğer statik bir sitenin html kodunu elde edebilirseniz sayfa hakkında tüm yazılara, resimlere, bağlantılara ve diğer verilere ulaşabiliyorsunuz. Site içinde sadece kendi istediğimiz verileri çekme işlemine deWeb Scraping
deniyor.Gelin isterseniz bu işlemi kodlayarak anlayalım. Web Scraping için Python'un iki tane güçlü kütüphanesi var.
requests
veBeautiful Soup
.Kodlayalım
Öncelikle yukarda belirtiğim iki kütüphaneyi kuralım
requests
ile web sayfalarında istekte bulunup geriye dönen değerleri (ki bunlar genelde html formatında olur) okuyabiliceğiz.beautifulsoup4
ile isestring
formatında gelen html'de parçalama ve arama yapabileceğiz.Bir seneryo üzerinden devam edelim. Seneryoya göre https://github.com/django sitesinden djangoya ait tüm repoları ve repolara ait bilgileri çekmek istiyoruz diyelim.
Aşama 1: Veri Kaynağının İncelenmesi
Amacımız işaretlediğim kısımları çekmek olsun.
Bunun için öncelikle scrape etmek istediğimiz datanın unique(eşsiz) bir özeliğini bulmamız lazım. Bu bazen bir class ismi bazen id olabilir. Tarayıcınızın dev tool'u bu iş için bayağı uygun.
Görüldüğü gibi istediğimiz veriler
repo-list
class'ına sahip birdiv
elementinini içinde. Bu bilgiyi aklımızda tutalım ve kodlamay başlayalım.Aşama 2: Veri Kaynağından Verilerin Çekilmesi
Python da bir sitenin
html
kaynak kodunu çekmek oldukça kolaydır.Şimdi elimizdeki bu ham datayı BeautifulSoup kullanarak yontalım.
BeautifulSoup'un aldığı ikinci parametre olan
html.parser
, BeautifulSoup'a hangi tipde bir parse işlemi yapacağını bildiriyor.html.parser
yerine daha hızlı olanlxml
parserini de kullanabilirdik. Amalxml
paketini projeye dahil etmek gerekirdi. O yüzden Python'un kendihtml.parser
'inden devam edelim.Şimdi yukarda bahsettiğimiz
repo-list
sınıfını kullanarak verileri parse edelim. Bunun içinsoup
nesnesine.find()
methodunu kullanacağız..find()
methodunun ilk parametresi source treede aranacak olan elemanın ismidir. Yani bir html element ismi alır.attrs
ise o elementin hangi özelikleri olduğunu belirtmek için kullanılır. Biz buradaclass
'ırepo-list
olan birdiv
elementini scrape etmesini söyledik. Yani BeautifulSoup, kaynak kodda şu patterne sahip ilk gördüğü elementi geri dönürecektir.Sonuca baktığımızda istediğimizi elde ettiğimizi görüyoruz
Şimdi elimizdeki
div
'i biraz daha inceleyelim. Aradığımız veriler budiv
'in her birli
elementinde tutuluyor.Bu
div
içindeki tümli
leri çekmek için.find_all()
methodunu kullanabiliriz. Bu method, bulduğu tüm elemenleri bir liste içinde geri döndürür.Bingo! Artık tüm
li
leri çektik. Geriye repoların isimlerini almak kaldı.Burada tüm
li
elemenlerinin içindekia
tagının içeriğine erişmek için.text
'i kullandık..text
html taglarının içindeki veriyi string şeklinde verir.Hadi bu çıktıyı daha güzel hale getirelim
Sonuç:
Buradaki
kodu kafa karıştırıcı olabilir. Aslında yaptığı işlem çok basit.
li
elementini tutanrepo
nesnesinin.find
methodu ile, eğer herhangi bir elementinhref
alanı "stargazers" stringini içeriyorsa onu geri döndürüyor. Bu da repoya verilen starları scrape etmemizi sağlıyor.Bitirirken...
Doğruyu söylemek gerekirse buraya kadar anlattığım şeyler Web Scraping işlmeminin çok küçük bir kısmı. BeautifulSoup'un dökümantasyonunda keşfedilmeyi bekleyen daha o kadar çok şey varki. Bu işte biraz daha vakit geçirdiğinizde Web Scraping'in sadece
BeautifulSoup
verequests
'den ibaret olmadığını göreceksiniz. Karşınızda her zaman statik bir veri döndüren sayfalar gelmeyecek. Bazı sayfalar kendi içeriklerini javascript ile oluşturur. Ve anlamlı verilerin oluşması için bir tarayıcı motoruna ihtiyaç duyar. Böyle durumda geleneksel yöntemleri kullanarak (bizimrequests
ile kaynak kod çekmek gibi) elde ettiğiniz şey sadece Javascript'in bundle dosyası olacaktır muhtemelen. Bunun için arkada bir tarayıcı motoru ve sağladığı API'leri kullanmak gerekiyor. Mesela Selenium bu iş için oldukça uygundur.