Categories
Rehber Yazılım

Python Web Scraping Kullanarak İnternetten Veri Nasıl Çekilir?

İnternetten bilgi toplamanın pek çok farklı çeşidi vardır. World Wide Web üzerinden veri toplamak için en popüler iki yöntem API (Applicaiton Programming Interface/Uygulama Programlama Arayüzü) ve Web Scraping (Web Kazıma) dir. Bu iki yöntemin arasındaki temel fark, sunulan verinin muhatabıdır.

Web Scraping vs API Çağrıları

API çağrılarında size verileri rahatça çekip kendi uygulamanızda kullanabilmeniz için end-pointler (uç noktaları) vardır.

Bu end-pointlere çeşitli HTTP/S istekleri göndererek istediğiniz verilere standart bir formatta ( genellikle JSON) ulaşabilirsiniz.

Öte yandan Web Scrapingde veriler bir web sitesinin çalışabilmesi için, websitesi tarafından tarayıcınıza gönderilir, renderlanır ve bu veriler buradan bu web sitesinin üzerinden adeta “kazınarak” toplanır.

Hedef Belirleme

Bu projemiz için n11.com üzerindeki bütün masaüstü bilgisayarların bilgilerini çekeceğiz. Öncelikle yapmanız gereken ilk iş hedefimizi tanımak. İstediğimiz verilerin nerelerde olduğunu belirlemek.

web sitesinde elementin kodu inceleniyor

Burada görebileceğimiz üzere ürünlerimizin hepsi, “column” class’ına sahip birer div ile kaplı. Bu sayede siteden hangi elementleri seçerek başlayacağımızı bulmuş olduk.

Sıradaki işimiz, her bir ürüne ait istediğimiz verileri tutan elementleri bulmak.

yazılmış kodlar inceleniyor

Yine geliştirici konsolumuzun yardımıyla ihtiyacımız olan elementleri belirmiş durumdayız. Bu örneğiniz için ihtiyacımız olan elementler şunlardır.

<h3 class="productName"> // Ürünümüzün adı
<a class="oldPrice"> // Ürünümüzün indirimsiz fiyatı
<a class="newPrice"> // Ürünümüzün indirimli fiyatı
<a class="plink"> // Ürünümüzün sayfasının linki

Fakat ihtiyacımız olan bir element daha var. Bir sayfada sadece belirli bir miktarda ürün listelendiğinden diğer ürünleri görebilmemiz için bir diğer sayfaya geçmemiz gerekiyor.

Bunun için de ürünlerin hemen altında bulunan sayfa butonlarını kullanacağız.sayfa sayıları görünüyor birinci sayfada sayfa sayıları var ellinci sayfada

Resimde de görüldüğü gibi son sayfaya gelene kadar next butonunu kullanabiliriz.

Bu sayede bir sayfadaki ürünleri bitirdiğimizde next butonunu kullanarak bir sonraki sayfaya geçip oradaki ürünleri çekmeye devam edebiliriz.

Gerekli bütün ön taramayı yaptıktan sonra artık kodlama kısmına geçebiliriz.

import requests
from bs4 import BeautifulSoup
import csv

site = requests.get("https://www.n11.com/bilgisayar/masaustu-bilgisayar")

soup = BeautifulSoup(site.content)

with open('laptops.csv', mode='w',encoding='utf-8') as laptops:
    laptopWriter = csv.writer(laptops, delimiter=',')
    laptopWriter.writerow(["Laptop Adı","Eski Fiyatı","Yeni Fiyatı","Link"]

page = soup.find(class_="next")

while page:
    site = requests.get(page["href"])
    soup = BeautifulSoup(site.content)
    products = soup.find_all(class_="column")

    for product in products:
        name = product.find(class_="productName")
        if name:
            name = name.get_text().strip()
            
        else:
            break
        oldPrice = product.find(class_="oldPrice")
        newPrice = product.find(class_="newPrice").get_text().strip()
        if oldPrice:
            oldPrice = oldPrice.get_text().strip()
        else:
            oldPrice = newPrice

        link = product.find(class_="plink")["href"]

        with open('laptops.csv', mode='a',encoding='utf-8') as laptops:
                laptopWriter = csv.writer(laptops, delimiter=',')
                laptopWriter.writerow([name,oldPrice,newPrice,link])
    page = soup.find(class_="next")

Kodumuzun üzerinden gidip ne yaptığına sırayla bir bakalım:


import requests
from bs4 import BeautifulSoup
import csv

Requests modülü sayesinde bir websitesinin raw (ham) HTML halini çekebilriz. Daha sonra bu raw HTML’i BeautifulSoup gibi bir HTML parser’ı kullanarak içerisinden ihtiyacımız olan verileri çıkarabiliriz.

Son olarak da csv modülü sayesinde, topladığımız verileri bir CSV (Comma Seperated Values/Virgülle Ayrılmış Değerler) dosyasına yazıp kullanabiliriz.

site = requests.get("https://www.n11.com/bilgisayar/masaustu-bilgisayar")

soup = BeautifulSoup(site.content)

with open('laptops.csv', mode='w',encoding='utf-8') as laptops:
    laptopWriter = csv.writer(laptops, delimiter=',')
    laptopWriter.writerow(["Laptop Adı","Eski Fiyatı","Yeni Fiyatı","Link"])

page = soup.find(class_="next")

Burada ise masaüstü bilgisayarların olduğu ilk sayfayı requests ile çekip BeautifulSoup ile işlenmeye hazır hale getiriyoruz.

Daha sonra bir CSV dosyası açıp içine başlılarımızı yazıp kapatıyoruz.

Burada dikkat etmemiz gereken bir husus ise Türkçe karakter kullandığımız için dosyayı utf-8 modunda açmamız gerektiğidir.

Aksi takdirde hata alabiliriz. Son olarak, sayfalar arasında ileri gitmemizi sağlayacak olan next butonunu bulup bir değişkene atıyoruz.

while page:
    site = requests.get(page["href"])
    soup = BeautifulSoup(site.content)
    products = soup.find_all(class_="column")

    for product in products:
        name = product.find(class_="productName")
        if name:
            name = name.get_text().strip()
            
        else:
            break
        oldPrice = product.find(class_="oldPrice")
        newPrice = product.find(class_="newPrice").get_text().strip()
        if oldPrice:
            oldPrice = oldPrice.get_text().strip()
        else:
            oldPrice = newPrice

        link = product.find(class_="plink")["href"]

        with open('laptops.csv', mode='a',encoding='utf-8') as laptops:
                laptopWriter = csv.writer(laptops, delimiter=',')
                laptopWriter.writerow([name,oldPrice,newPrice,link])
    page = soup.find(class_="next")

Döngümüzün içinde ilk önce next butonumuzun işaret ettiği sayfayı request ile çekip BeautifulSoup ile işlemeye hazır hale getiriyoruz.

Daha sonra, daha önceden belirlemiş olduğumuz ürün class’ımızı kullanarak bütün ürünlerimizin olduğu elementleri çekiyoruz.

İkinci döngümüzde ise bu ürünlerimizin içerinde teker teker gezip ihtiyacımız olan bilgileri çekiyoruz.

Bir ürünün bütün bilgilerini çektikten sonra en başta açtığımız CSV dosyasını tekrar açıp ekliyoruz.

Burada dikkat etmemiz gereken kısım dosyayı “w” (write/yazma) moduyla değil “a” (append/ekleme) moduyla açmamız gerektiğidir zira daha önce yazdığımız bütün verilerimizin üzerine yazarız.

Son olarak, şu anda ürünlerini çektiğimiz sayfanın next butonunu alıp ilk döngümüze geri dönüyoruz. Bu süreç “page” değişkeni yani next butonumuz boş olana kadar devam edecek.

Bunun olmasının tek yolu sitede en son sayfaya gelmiş olmamızdır.

Sonuç: Örnek Çıktı

Laptop Adı,Eski Fiyatı,Yeni Fiyatı,Link

Dell G5DT-B70W165N i7-10700F 16GB 512GB SSD 6GB GTX 1660 W10H,"12.499,99 TL","11.879,99
                TL",https://urun.n11.com/masaustu-bilgisayar/dell-g5dt-b70w165n-i7-10700f-16gb-512gb-ssd-6gb-gtx-1660-w10h-P469658715

"Zeiron Sn107 İ5-650 3,46Ghz 8GB 120GB SSD 18.5 Masaüstü Bilgisaya","4.450,00 TL","2.249,00
                TL",https://urun.n11.com/masaustu-bilgisayar/zeiron-sn107-i5-650-346ghz-8gb-120gb-ssd-185-masaustu-bilgisaya-P456175492

"Zeiron Sn108 İ5-650 Turbo 3,46Ghz 8GB 500GB 18.5 Masaüstü Bilgisa","4.250,00 TL","2.199,00
                TL",https://urun.n11.com/masaustu-bilgisayar/zeiron-sn108-i5-650-turbo-346ghz-8gb-500gb-185-masaustu-bilgisa-P456176226

"i5 8GB Ram 128GB Ssd 18,5"" Monitör Masaüstü Bilgisayar - EBA TV","2.429,00 TL","2.022,58
                TL",https://urun.n11.com/masaustu-bilgisayar/i5-8gb-ram-128gb-ssd-185-monitor-masaustu-bilgisayar-eba-tv-P368648481

Dragos ATM9922509 i3 10100f 8GB Ram 240GB Ssd 4GB GTX1650 Oyun Bi,"4.650,64
                TL","4.650,64
                TL",https://urun.n11.com/masaustu-bilgisayar/dragos-atm9922509-i3-10100f-8gb-ram-240gb-ssd-4gb-gtx1650-oyun-bi-P463168484

Yukarıdaki küçük pyhon script’imiz sayesinde yaklaşık olarak 4.000 masaüstü bilgisayarın bilgilerini dakikalar içerisinde çekmiş olduk. Yazımızda öğrendiğimiz teknikleri kullanarak bu script’i benzer sitelere uyarlayabilir veya farklı bir web scraping ihtiyacınız için kendi scriptinizi kolaylıkla yazabilirsiniz.

Categories
Rehber Yazılım

Docker ile Sanal Ortam Oluşturun: Docker Nedir?

Docker, basit bir şekilde süper hızlı “sanal ortam” oluşturma teknolojisidir. Bu basitliğin ardında büyük olaylar bizi beklediği için sade bir giriş yapalım istedim. Hemen başlayalım.

dockeryazılım programının logosu

Sanallaştırma

Bir bilgisayar/sunucu içerisinde bulunan işletim sisteminin üzerinde sanal makine başlatılır.

Başlatılacak olan her sanal makine ana bilgisayarımızın fiziksel özelliklerinin bir kısmı ile beslenmeye başlar.

Her sanal makine içerisinde gerekli olan işletim sistemi bulunur. Bu sebeple makine dosyaları oldukça çok fazla yük içerir.

Makine sayısı arttıkça, fiziksel makinenin özellikleri hızla sanal makineler tarafından tüketilir.

Oluşturulan makinelerin fiziksel bilgisayardan alınacak kaynakların esnek yapıda seçilmemesi proje gereksinimlerinin değişiminde büyük sıkıntılar ortaya çıkarır.

Bu sebeplerle sanal makineler çeviklik açısından başa bela bir hale gelirler.

Konteynerleştirme

Bu terim yazılım dünyası için aslında yeni değildir. Docker sayesinde bu teknoloji son kullanıcının kullanımına çok kolay bir şekilde sunulmuştur.

Bu teknolojide amaç fiziksel makinemizin çekirdeğini direkt kullanmak.

Yeni işletim sistemlerinin tüm gereksinimleri yerine amaçlanan sistem belirlenir ve halihazırda asıl çekirdek üzerine bu sistem kurulumu gerçekleştirilir.

Bu sayede işlem ve yer maliyeti düşük, kolay taşınabilir makineler oluşturulur.

Docker

Docker‘ın sitesinden sisteminize uygun kurulumu ile ilgili detaylı bilgiyi alabilirsiniz.

Docker’ın sanallaştırmanın yanı sıra neler sunduğunu işleyişlerinden yola çıkarak anlatmaya çalıştık ancak yapabileceklerimizin çok daha fazlası bizleri bekliyor.

Şimdi Docker’ın “Image” kısmını ele alalım.

Konteynerlerin içerisinde çalışacak düşük kapasiteli yüksek erişebilirlik sağlayan sistem görüntüleri. Bu görüntüler nginx den mysql e her türlü paketi bulundurabilir.

Bu paketleri kendi işleriniz için özel olarak oluşturabilir, şirket içi ya da topluluk için özel geliştirmeler yapabilirsiniz.

Bu sayede oluşturduğunuz görüntüyü insanlar projelerinde kullanabilir.

Düşük dosya boyutları sayesinde dakikalar içerisinde uğraştırıcı bir çok ortamın kurulumu kolayca sağlanır.

Sistemimizde olan görüntüleri aşağıdaki şekilde görebiliriz. Şuan sistemimizde herhangi bir görüntü yok.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

Deneme amaçlı bir mysql görüntüsü çalıştıralım. Docker görüntünün olmadığını gördüğü zaman önce görüntüyü alacak, kurulumunu yapıp hizmetimize sunacaktır.

Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
a076a628af6f: Pull complete                                                                                                                                                 f6c208f3f991: Pull complete                                                                                                                                                 88a9455a9165: Pull complete                                                                                                                                                 406c9b8427c6: Pull complete                                                                                                                                                 7c88599c0b25: Pull complete                                                                                                                                                 25b5c6debdaf: Pull complete                                                                                                                                                 43a5816f1617: Pull complete                                                                                                                                                 69dd1fbf9190: Pull complete                                                                                                                                                 5346a60dcee8: Pull complete                                                                                                                                                 ef28da371fc9: Pull complete                                                                                                                                                 fd04d935b852: Pull complete                                                                                                                                                 050c49742ea2: Pull complete                                                                                                                                                 Digest: sha256:--
Status: Downloaded newer image for mysql:latest
[Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.
[Note] [Entrypoint]: Switching to dedicated user 'mysql'
[Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.
[ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
        You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD

Aynı komutu tekrar çalıştıralım.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               latest              d4c3cafb11d5        25 hours ago        545MB

Artık görüntü yerel makinemizde hazır. İstediğimiz zaman bu görüntü ile yeni bir konteyner oluşturup birden fazla mysql sunucusu elde edebiliriz.

Peki Docker bu görüntüyü nereden aldı? Tabiki de kendi “image” havuzu Docker Hub’dan (docker farklı kaynaklardan da görüntü alabilir).

Bu sistem içerisinden işinize yarayan herhangi bir görüntüyü yerelinize almak için aşağıdaki komutu kullanabilirsiniz.

docker pull blabla

Etiketler bir çok depo(repository) alanında olduğu gibi Docker görüntülerinde de versiyonlama için kullanılır. Yapısı bu şekildedir;

<görüntü-adı>:<etiket>

Yukarıdaki mysql örneğimizi ele aldığımızda depodan çekilecek olan görüntü mysql görüntünün versiyon adı ise latest dır. Eğer mysql in farklı bir sürümünü yüklemek istiyorsak aşağıdaki gibi bir komut kullanmalıyız.

docker pull mysql:5.7.32

Docker Hub içerisinde herhangi bir görüntü deposuna girdiğimizde “Description”, “Reviews” ve “Tags” şeklinde 3 farklı tab görürüz.

Tags” tab i içerisine girdiğimizde ilgili deponun oluşturulmuş tüm versiyonlarını görebilir nasıl erişebileceğimize dair bilgileri edinebiliriz.

Docker çalışma sistemi ve belkemiği konteyner sistemidir.

Konteynerler çok hızlı bir şekilde ayağa kaldırılıp kullanıma hazır hale getirilir.

Bir uygulama için birden fazla uygulama/veri tabanı konteynerleri oluşturulup aynı anda çalışması ve yükü eşit bir şekilde paylaşacak şekilde yapılandırılmaları mümkündür.

Hatta bu sistemleri ek uğraş gerektirmeden otomatik olarak yapan sistemlerde geliştirilmiştir.

Bir görüntü seçilip docker run komutu kullanıldığında otomatik olarak konteyner oluşturulmaya başlanır. Yine mysql örneği ile gösterelim;

$ docker run --name mysqltest -e MYSQL_ROOT_PASSWORD=docker-test -d mysql:latest

Şimdi biraz inceleyelim ilk yaptığımız run komutundan farklı parametreler var.

— name mysqltest  konteyner adımız

-e MYSQL_ROOT_PASSWORD konteyner a gömmek istediğimiz ortam değişkeni

-d bağımsız(detached) modda konteyner başlar, komut girildikten sonra komut istemine geri döneriz, docker arkada oluşturma işlemine başlar, bizi engellemez.

mysql:latest kurmasını istediğimiz görüntünün adı

Docker konteynerlerini aşağıdaki komut ile listeyebiliriz;

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
2fa80a5b07c6        mysql:latest        "docker-entrypoint.s…"   26 minutes ago      Up 26 minutes       3306/tcp, 33060/tcp   mysqltest

Oluşturduğumuz konteyner ın özelliklerini ve durumunu görüntüleyebiliyoruz. Konteyner ı durdurmak için aşağıdaki komut kullanılabilir.

$ docker container stop 2fa80a5b07c6

stop ibaresinden sonraki alan konternerimizin id si. İstersek ismi ile de aynı işlemi gerçekleştirebiliriz.

Şimdi ise konteyner silmek için aşağıdaki komutu kullanalım

$ docker container rm mysqltest

Bu şekilde Docker da konteyner oluşturma durdurma ve silme işlemlerinin nasıl yapıldığını incelemiş olduk.

Bu dosyalar var olan görüntüleri özelleştirerek projemize özel yeni görüntüler elde etmemizi sağlıyor. İçerisine gireceğimiz komutlar ile Docker’ın konteyner oluşturma aşamasında ne tür adımlar izleyeceğini belirliyoruz. Docker vereceğimiz tüm işleri bizim yerimize istediğimiz kadar konteyner içerisinde yapıyor. Şimdi bir tane oluşturalım;

FROM node:14.15.4                                                                                                                                                           RUN mkdir /nodetest                                                                                                                                                         WORKDIR /nodetest                                                                                                                                                           ADD . /nodetest                                                                                                                                                             CMD node index.js

FROM oluşturulacak konteynerin kullanacağı görünütüyü belirtir.

RUN konteynerin çalıştıracağı komut burada bir klasör oluşturduk.

WORKDIR konteynerin komutlarımızı nerede çalıştıracağını belirttik.

ADD konteynerin içerisine aktarılacak fiziksel makinemizdeki dizini gösterdik Dockerfile ın bulunduğu dizindeki herşey konteyner içerisinde bulunan nodetest klasörüne kopyalanacak.

CMD konteynerin işlemlerden sonra çalıştırmasını istediğimiz ilk ve asıl işlem.

Dockerfile ımızın yanına bir index.js açıyor ve içerisini aşağıdaki şekilde dolduruyoruz;

const https = require('https')                                                                                                                                              let req = https.request({ hostname: 'webhook.site', path: '/1d7a8108-ecfe-413d-a210-156a0fe3ad96', port: 443, method: 'GET' }, () => {});
req.end();

Webhook.site üzerinden bir webhook oluşturuyoruz ve istek atıyoruz.

Şimdi oluşturduğumuz Dockerfile üzerinden bir görüntü oluşturmak için aşağıdaki komutu kullanalım:

$ docker build ./
Sending build context to Docker daemon  3.072kB
Step 1/5 : FROM node:14.15.4
 ---> 995ff80c793e
Step 2/5 : RUN mkdir /nodetest
 ---> Running in 37739a546f10
Removing intermediate container 37739a546f10
 ---> f5f56db2746d
Step 3/5 : WORKDIR /nodetest
 ---> Running in ae357849a077
Removing intermediate container ae357849a077
 ---> ae2f76d3ad04
Step 4/5 : ADD . /nodetest
 ---> 58b31c30cbcf
Step 5/5 : CMD node index.js
 ---> Running in 5bd9c578f13c
Removing intermediate container 5bd9c578f13c
 ---> e540f9d9eea3
Successfully built e540f9d9eea3

Bulunduğumuz dizini göstererek “e540f9d9eea3” idsine sahip bir görüntü oluşturduk hemen bunu inceleyelim:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              e540f9d9eea3        24 seconds ago      942MB
node                14.15.4             995ff80c793e        27 hours ago        942MB
mysql               latest              d4c3cafb11d5        28 hours ago        545MB

İlk sırada bizim oluşturduğumuz görüntü geldi. Artık konteynerimizi başlatabiliriz.

$ docker run e540f9d9eea3

Bu komut ile konteyner başladığı anda Webhook.site adresinde istek hemen karşımıza geliyor.

Node konternerimiz ayağa kalktı tüm ortam yüklendi, index.js dosyamız alındı ve sonrasında talimatlarımıza göre çalıştırıldı.

Image for post

Image for post

İşlem başarıyla tamamlandı. Artık bu görüntü ile istediğiniz her şeyi yapabilirsiniz.

Yazımızda “Docker Nedir?”, “Hangi Teknolojiyi Kullanır?”, “Konteynerleştime(Containerization) Nedir?”, “Docker Image Nedir Nasıl Çalışır?”, “Docker Konyetner Nasıl Çalışır?”, “Dockerfile Nedir ve Nasıl Çalışır?” ve “Docker Image Nasıl Oluşturulur?” gibi pek çok soruya değinmeye ve cevap vermeye çalıştık.

 

Sonuna kadar okuduğunuz için teşekkür ederim. Umarım sizler için faydalı bir yazı olmuştur ve aklınızda soru işaretlerini bir nebze olsun azaltmıştır.