YouTube içerik oluşturucuları videolarının performansını değerlendirmek zorundadır; olumlu ve olumsuz yorumları analiz etmek ve içeriklerini aynı veya farklı kategorilerdeki diğer içeriklerle karşılaştırmak çok önemlidir.
Yayınlanan videoları manuel olarak incelemek, içerik oluşturucular için sıkıcı ve zaman alıcı olabilir. İşte tam da bu noktada bir YouTube kazıma betiği çok değerli hale gelir. Bu kılavuzda veri toplama sürecini otomatikleştirmek için tasarlanmış bir YouTube betiği geliştireceğiz.
Komut dosyasının düzgün çalışması için bazı paketleri yüklememiz gerekiyor. Yüklenecek ilk paket, uygun proxy yapılandırmasını sağlayan Selenium'un bir uzantısı olan selenium-wire ve temel sınıflar ve modüller için Selenium'un kendisidir. Bu paketleri yüklemek için komut arayüzünüzde aşağıdaki komutu çalıştırın:
pip install selenium-wire selenium blinker==1.7.0
Şimdi ithalatlara odaklanalım.
Bu aşamada, web öğeleriyle etkileşim için komut dosyamızda kullanılacak kütüphaneleri ve paketleri içe aktarmak önemlidir. Ek olarak, betiğin verimli bir şekilde yürütülmesini sağlamak için veri işleme ve çalışma zamanı yönetimi için modüller eklemeliyiz.
from selenium.webdriver.chrome.options import Options
from seleniumwire import webdriver as wiredriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import json
import time
Json modülü, çıkarılan verilerin uygun şekilde biçimlendirilmiş JSON verilerine dönüştürülmesine yardımcı olarak optimum veri sunumunu sağlar. IP'mizi maskelemesine rağmen, zaman modülü eylemlere rastgelelik katarak komut dosyası benzeri davranışların ortaya çıkmasını önlemek için gereklidir.
Ayrıca bu modül, sayfadan veri çekmek için ihtiyaç duyduğumuz öğelerin yüklendiğinden emin olmak için çok önemlidir. Geri kalan içe aktarmalar, farklı eylemler gerçekleştiren gerekli sınıflardan veya alt modüllerden oluşur ve kodun sonraki bölümlerinde ayrıntılı olarak açıklanacaktır.
Python'da bir betik kullanarak bir selenium örneği çalıştırdığınızda, betik gerçekleştirmek istediğimiz etkinlik için IP adresimizi kullanır. Bu, özellikle YouTube gibi web sitelerinden bilgi kazımaya karşı katı politikaları olan web siteleri için tehlikelidir, daha iyi bir referans için robots dosyalarına göz atabilirsiniz. Bunun sonuçları, IP adresinizin YouTube içeriğine erişiminin geçici olarak kısıtlanması olabilir.
Tüm bunlardan kaçınmak için yapmamız gereken birkaç şey var. Sayfaya erişeceğimiz proxy'nin ayrıntılarını barındırmak için 3 değişken oluşturmamız gerekiyor. Ardından, Chrome WebDriver örneğine aktaracağımız chrome_options adlı bir seçenek değişkeni oluşturuyoruz, böylece Selenium kazıma sırasında hangi proxy'yi kullanacağını biliyor. Proxy ayrıntılarını chrome_options için argüman olarak iletiriz ve proxy'miz ayarlanır.
# Proxy sunucu adresini kullanıcı adı ve parola ile belirtin
proxy_address = ""
proxy_username = ""
proxy_password = ""
# Proxy ve kimlik doğrulama ile Chrome seçeneklerini ayarlama
chrome_options = Options()
chrome_options.add_argument(f'--proxy-server={proxy_address}')
chrome_options.add_argument(f'--proxy-auth={proxy_username}:{proxy_password}')
# Selenium-wire ile bir WebDriver örneği oluşturma
driver = wiredriver.Chrome(options=chrome_options)
YouTube açılış sayfasının URL'sini saklamak için "youtube_url_to_scrape" adında bir değişken oluşturun. Bu değişken daha sonra Selenium'u kazıma için belirli bir sayfayı açmaya yönlendirmek için "driver.get()" yönteminde kullanılır. Bu eylemin yürütülmesi, komut dosyası çalıştırıldığında ayrı bir Chrome penceresi açacaktır.
youtube_url_to_scrape = ""
# Selenium otomasyonunuzu selenium-wire'ın gelişmiş özellikleriyle gerçekleştirin
driver.get(youtube_url_to_scrape)
Ardından, adından da anlaşılacağı gibi sayfadan gerekli bilgileri çıkaran "extract _information()" fonksiyonunu tanımlıyoruz.
Sayfadaki tüm öğelerin yüklendiğinden emin olmak önemlidir. Bunu yapmak için, en azından "element" değişkeni altında uygulanan "more" düğmesi kullanılabilir olana ve tıklanana kadar komut dosyasını duraklatmak için WebDriverWait sınıfını kullanırız. Kullanılabilir olduğunda, Selenium videonun tam açıklamasına erişim sağlayan bir JavaScript tıklama eylemi yürütür.
Daha önce bahsedilen dinamik yorum sorununu ele almak için, ilgili sorunları ortadan kaldıracak bir çözüm uyguluyoruz. Actions sınıfını ve Time modülünü kullanarak, her 10 saniyede bir iki kez aşağı kaydırıyoruz ve mümkün olduğunca çok sayıda yorumun kazındığından emin oluyoruz. Bu proaktif yaklaşım, dinamik olarak yüklenen içerikle ilişkili potansiyel darboğazlara karşı koruma sağlar.
def extract_information() -> dict:
try:
element = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="expand"]'))
)
element.click()
time.sleep(10)
actions = ActionChains(driver)
actions.send_keys(Keys.END).perform()
time.sleep(10)
actions.send_keys(Keys.END).perform()
time.sleep(10)
Selenium webdriver kullanarak öğeleri aramanın farklı yolları vardır. ID, CLASS_NAME, XPATH vb. ile arama yapabilirsiniz. Bu kılavuz için, tek bir yöntem yerine bir kombinasyon kullanacağız.
XPATH, kazıma sırasında değişkenleri bulmak için daha karmaşık ancak desen tabanlı bir sistemdir. En karmaşık sistem olarak kabul edilir; ancak Chrome bunu kolaylaştırmıştır.
Chrome'un denetleme aracını kullanarak kodu incelerken, XPATH'yi kopyalamak için sağ tıklamanız yeterlidir. Kopyaladıktan sonra, video başlığı, açıklama vb. gibi istenen bilgileri içeren tüm öğeleri tanımlamak için `find_elements` işlevini kullanabilirsiniz.
Sayfadaki bazı öğelerin benzer nitelikleri paylaşabileceğini ve bu durumun `find_elements()` çağrısının bir dize yerine bir liste döndürmesine neden olabileceğini unutmamak çok önemlidir. Bu gibi durumlarda, ilgili bilginin dizinini belirlemek ve metni çıkarmak için listeyi incelemeniz gerekir.
Sonuç olarak, `data` adında bir sözlük değişkeni döndürülür ve kazıma sırasında toplanan tüm bilgileri kapsar, ergo, sonraki bölüm için bir temel oluşturur.
video_title = driver.find_elements(By.XPATH, '//*[@id="title"]/h1')[0].text
owner = driver.find_elements(By.XPATH, '//*[@id="text"]/a')[0].text
total_number_of_subscribers = \
driver.find_elements(By.XPATH, "//div[@id='upload-info']//yt-formatted-string[@id='owner-sub-count']")[
0].text
video_description = driver.find_elements(By.XPATH, '//*[@id="description-inline-expander"]/yt-attributed-string/span/span')
result = []
for i in video_description:
result.append(i.text)
description = ''.join(result)
publish_date = driver.find_elements(By.XPATH, '//*[@id="info"]/span')[2].text
total_views = driver.find_elements(By.XPATH, '//*[@id="info"]/span')[0].text
number_of_likes = driver.find_elements(By.XPATH, '//*[@id="top-level-buttons-computed"]/segmented-like-dislike-button-view-model/yt-smartimation/div/div/like-button-view-model/toggle-button-view-model/button-view-model/button/div')[
1].text
comment_names = driver.find_elements(By.XPATH, '//*[@id="author-text"]/span')
comment_content = driver.find_elements(By.XPATH, '//*[@id="content-text"]/span')
comment_library = []
for each in range(len(comment_names)):
name = comment_names[each].text
content = comment_content[each].text
indie_comment = {
'name': name,
'comment': content
}
comment_library.append(indie_comment)
data = {
'owner': owner,
'subscribers': total_number_of_subscribers,
'video_title': video_title,
'description': description,
'date': publish_date,
'views': total_views,
'likes': number_of_likes,
'comments': comment_library
}
return data
except Exception as err:
print(f"Error: {err}")
def organize_write_data(data:dict):
output = json.dumps(data, indent=2, ensure_ascii=False).encode("ascii", "ignore").decode("utf-8")
try:
with open("output.json", 'w', encoding='utf-8') as file:
file.write(output)
except Exception as err:
print(f"Error encountered: {err}")
Organize_write_data()` fonksiyonu dönen `data` yı girdi olarak alır ve onu biçimlendirilmiş bir JSON yapısı halinde düzenler. Daha sonra bu düzenlenmiş verileri "output.json" adlı bir çıktı dosyasına yazar ve dosya yazma işlemi sırasında olası hataları ele alır.
Şimdiye kadar, kazıma programımızın tam kodu burada:
from selenium.webdriver.chrome.options import Options
from seleniumwire import webdriver as wiredriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import json
import time
# Proxy sunucu adresini kullanıcı adı ve parola ile belirtin
proxy_address = ""
proxy_username = ""
proxy_password = ""
# Proxy ve kimlik doğrulama ile Chrome seçeneklerini ayarlama
chrome_options = Options()
chrome_options.add_argument(f'--proxy-server={proxy_address}')
chrome_options.add_argument(f'--proxy-auth={proxy_username}:{proxy_password}')
# Selenium-wire ile bir WebDriver örneği oluşturma
driver = wiredriver.Chrome(options=chrome_options)
youtube_url_to_scrape = ""
# Selenium otomasyonunuzu selenium-wire'ın gelişmiş özellikleriyle gerçekleştirin
driver.get(youtube_url_to_scrape)
def extract_information() -> dict:
try:
element = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="expand"]'))
)
element.click()
time.sleep(10)
actions = ActionChains(driver)
actions.send_keys(Keys.END).perform()
time.sleep(10)
actions.send_keys(Keys.END).perform()
time.sleep(10)
video_title = driver.find_elements(By.XPATH, '//*[@id="title"]/h1')[0].text
owner = driver.find_elements(By.XPATH, '//*[@id="text"]/a')[0].text
total_number_of_subscribers = \
driver.find_elements(By.XPATH, "//div[@id='upload-info']//yt-formatted-string[@id='owner-sub-count']")[
0].text
video_description = driver.find_elements(By.XPATH,
'//*[@id="description-inline-expander"]/yt-attributed-string/span/span')
result = []
for i in video_description:
result.append(i.text)
description = ''.join(result)
publish_date = driver.find_elements(By.XPATH, '//*[@id="info"]/span')[2].text
total_views = driver.find_elements(By.XPATH, '//*[@id="info"]/span')[0].text
number_of_likes = driver.find_elements(By.XPATH,
'//*[@id="top-level-buttons-computed"]/segmented-like-dislike-button-view-model/yt-smartimation/div/div/like-button-view-model/toggle-button-view-model/button-view-model/button/div')[
1].text
comment_names = driver.find_elements(By.XPATH, '//*[@id="author-text"]/span')
comment_content = driver.find_elements(By.XPATH,
'//*[@id="content-text"]/span')
comment_library = []
for each in range(len(comment_names)):
name = comment_names[each].text
content = comment_content[each].text
indie_comment = {
'name': name,
'comment': content
}
comment_library.append(indie_comment)
data = {
'owner': owner,
'subscribers': total_number_of_subscribers,
'video_title': video_title,
'description': description,
'date': publish_date,
'views': total_views,
'likes': number_of_likes,
'comments': comment_library
}
return data
except Exception as err:
print(f"Error: {err}")
# Verileri JSON'a kaydetme
def organize_write_data(data: dict):
output = json.dumps(data, indent=2, ensure_ascii=False).encode("ascii", "ignore").decode("utf-8")
try:
with open("output.json", 'w', encoding='utf-8') as file:
file.write(output)
except Exception as err:
print(f"Error encountered: {err}")
organize_write_data(extract_information())
driver.quit()
Çıktı aşağıdaki gibi görünür:
YouTube'un bilgi zenginliğinden güvenli bir şekilde yararlanmak, platform politikalarına ve düzenlemelerine uyulmasını sağlamak için proxy'leri kullanan iyi hazırlanmış komut dosyaları kullanıldığında önemli ölçüde faydalıdır. Yukarıda tartışılan yaklaşım, sorumlu veri çıkarımını kolaylaştırır ve platform tarafından uygulanan potansiyel kısıtlama riskini azaltır.
Yorumlar: 0