Burak Buldu

O bir Teknoloji KurduGalatasaray taraftarıIT ProfesyoneliAntalyalı

Python 3 ile Veri Çekme Örneği

Merhaba değerli takipçilerim, geçtiğimiz Mart ayında bir veri toplama işi almıştım. Nasıl yaparım, ederim diye düşünürken Python ile oldukça kolay olduğunu duydum. Haklılarmış da, çünkü uzun zamandır hiç html parsing gibi konulara girmemiştim. İlk web geliştirmeye başladığım yıllarda PHP ile yaptığımı, meşakkatli bir iş olduğunu hatırlıyorum. Tabi yine C++ olsun, C# olsun, bu dillerde html parsing yaparken süreçler çok da farklı değildir. Ancak Python 3 ile oldukça pratik olduğunu tecrübe ettim.

Benden istedikleri belirli markalara ait müşterilerin şikayetlerini “sikayetvar.com” üzerinden almaktı. Muhtemelen elle tek tek yapmak, onlarca şikayet için epey zor olur. Önce Github‘da biraz taradım, hatta bununla ilgili aynı domaine özgü örnek de buldum. Bu konuda script hazırlayan Mehmet’e de teşekkür ederim.

Neler yaptım?

Tabiki de güncel olmadığı için hataları vardı. Olması da normal çünkü sikayetvar.com da yapısını değiştiriyor ve python kütüphaneleri gelişiyor. Yeni bir iki kütüphane ekledim. Biraz eski kodları düzelttim, onun haricinde çok fazla şikayet verisi toplamaktan mıdır yoksa başka bir nedenden dolayı mı bilmiyorum URL uzunluğundan bir problem yaşadım. Aldığım hatanın çözümünü keşfedemedim ama 32 karakterden uzun şikayet başlıkları olunca sıkıntı olmadı. Bunun yanı sıra şikayetler toplanırken tekrar aynı kayıtlar oluşuyordu, bazen bir sonraki sayfaya gidemiyordu. Bunun için foreach yerine for döngüsüyle sayfa numaralarını tek tek gönderdim. Hazır bu kadar uğraşmışken, her markayı ayrı kaydedeyim dedim.

Velhasıl kelam, temiz çalışan güzel bir örnek oluşturdum. Kodu da sizlerle paylaşıyorum. İyi kodlamalar…

import requests
import codecs
import csv
from requests.exceptions import RequestException
from contextlib import closing
from bs4 import BeautifulSoup

def simple_get(url):
    """
    GET isteği yaparak url almaya çalışır.
    Yanıt HTML veya XML ise, içeriğini döndürür.
    Aksi halde None döner.
    """
    try:
        with closing(requests.get(url, stream=True)) as resp:
            if is_good_response(resp):
                return resp.content
            else:
                return None

    except RequestException as e:
        log_error('{0} için yapılan istekte hata döndü : {1}'.format(url, str(e)))
        return None

def is_good_response(resp):

    #Yanıt HTML ise True, aksi takdirde False döndürür.

    content_type = resp.headers['Content-Type'].lower()
    return (resp.status_code == 200
            and content_type is not None
            and content_type.find('html') > -1)


def log_error(e):

    #Hataları kaydeder.

    print(e)

BASE_URL = "https://www.sikayetvar.com"
brand_names = ["marka1","marka2"] #Markalar ["marka1","marka2",...]

scraped_data = []

for brand in brand_names:
    BRAND_URL = BASE_URL + "/" + brand

    my_page = simple_get(BRAND_URL)
    parsing = BeautifulSoup(my_page, "html.parser")

    pages = parsing.find("section",{"class":"pagination row"})

    num_of_pages = pages.find_all("a")
    page_numbs = []
    for page_no in num_of_pages:
        page_numbs.append(page_no.text)
    last_page_no = int(page_numbs[-2])+1

    #Sonraki sayfalar için döngü
    for x in range(1, last_page_no):
        page_num=x
        log = "\n "+ brand + " için " + str(page_num) + ". sayfa okunuyor...\n"
        print(log)

        raw_html = simple_get(BRAND_URL+"?page="+str(page_num))
        soup = BeautifulSoup(raw_html, "html.parser")

        item_pages = []
        for complaint in soup.find_all("a", {"class":"complaint-link-for-ads"}):
            item_pages.append(complaint["href"])

        for page in item_pages:
            """
            URL uzunluğundan dolayı aldığım bir hata sonucu 32 karakter sınırı koydum.
            """
            if len(page) <=32:

                continue

            else:

                my_url = BASE_URL + page
                print("Okunan sayfa: " + my_url + "...")
                raw_html = simple_get(my_url)
                soup = BeautifulSoup(raw_html, "html.parser")

                title = soup.find("h1",{"class":"title"})
                if title != None:
                    title = title.text.strip('\n')

                description = soup.find("div", {"class":"description"})
                if description != None:
                    description = description.text.strip('\n')

                date = soup.find("span",{"class":"date date-tips"})
                if date != None:
                    date = date["title"][:-5]

                views = soup.find("span",{"class":"view-count-detail"})
                if views != None:
                    views = views.b.text

                hashtags = soup.find_all("a",{"class":"highlight"})
                tags = []
                for tag in hashtags:
                    tags.append(tag["title"])

                row = [brand,title,description,date,views,tags]
                scraped_data.append(row)

    with open(brand+".csv", "w", encoding="utf8", newline="") as csvfile:
        print(brand+" Bitti!")
        writer = csv.writer(csvfile, delimiter=';', quotechar='"')

        headers = ["Marka","Başlık","Açıklama","Tarih","Görüntüleme Sayısı","Etiketler"]
        writer.writerow(headers)

        for row in scraped_data:
            writer.writerow(row)
        scraped_data.clear()

print("Tüm işlemler bitti!")
Paylaş