Come raschiare i dati vitali di YouTube con Python

Commenti: 0

I creatori di YouTube devono valutare le performance dei loro video; analizzare i commenti positivi e negativi e confrontare i loro contenuti con altri della stessa categoria o di categorie diverse diventa essenziale.

Passare manualmente al setaccio i video pubblicati può essere noioso e richiedere molto tempo ai creatori. È proprio qui che uno script di scraping di YouTube diventa prezioso. In questa guida svilupperemo uno script YouTube progettato per automatizzare il processo di raccolta dei dati.

Creare uno scraper per estrarre dati da YouTube

Affinché lo script funzioni correttamente, è necessario installare alcuni pacchetti. Il primo pacchetto da installare è selenium-wire, un'estensione di Selenium che consente una corretta configurazione del proxy, e Selenium stesso per le classi e i moduli essenziali. Per installare questi pacchetti, eseguire il seguente comando nella propria interfaccia di comando:

pip install selenium-wire selenium blinker==1.7.0

Ora concentriamoci sulle importazioni.

Fase 1: Importare librerie e pacchetti

In questa fase, è importante importare le librerie e i pacchetti che saranno utilizzati nel nostro script per interagire con gli elementi web. Inoltre, dovremmo includere i moduli per l'elaborazione dei dati e la gestione del tempo di esecuzione, per garantire un'esecuzione efficiente dello script.

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

Il modulo json aiuta a convertire i dati estratti in dati JSON correttamente formattati, garantendo una presentazione ottimale dei dati. Nonostante il mascheramento del nostro IP, il modulo time è essenziale per introdurre la casualità nelle azioni, impedendo la comparsa di comportamenti simili a quelli di uno script.

Inoltre, questo modulo è fondamentale per garantire che gli elementi di cui abbiamo bisogno per estrarre i dati dalla pagina siano stati caricati. Le importazioni rimanenti sono costituite da classi o sottomoduli necessari che svolgono azioni distinte e che verranno approfondite nelle sezioni successive del codice.

Fase 2: Impostazione del driver di Selenium Chrome

Ogni volta che si esegue un'istanza di Selenium utilizzando uno script in python, lo script utilizza il nostro indirizzo IP per qualsiasi attività si voglia eseguire. Questo è pericoloso, soprattutto per siti web come YouTube, che hanno politiche severe contro lo scraping di informazioni dal loro sito; si può controllare il loro file robots per un riferimento migliore. Le conseguenze potrebbero essere restrizioni temporanee all'accesso ai contenuti di YouTube da parte del vostro IP.

Per evitare tutto questo, dobbiamo fare un paio di cose. Dobbiamo creare 3 variabili per ospitare i dettagli del proxy attraverso cui accedere alla pagina. Poi creiamo una variabile options, chrome_options, che passeremo nell'istanza di Chrome WebDriver, in modo che Selenium sappia quale proxy utilizzare durante lo scraping. Passiamo i dettagli del proxy come argomenti per chrome_options e il nostro proxy è impostato.

# Specificare l'indirizzo del server proxy con nome utente e password
proxy_address = ""
proxy_username = ""
proxy_password = ""
# Impostare le opzioni di Chrome con il proxy e l'autenticazione
chrome_options = Options()
chrome_options.add_argument(f'--proxy-server={proxy_address}')
chrome_options.add_argument(f'--proxy-auth={proxy_username}:{proxy_password}')
# Creare un'istanza di WebDriver con selenium-wire
driver = wiredriver.Chrome(options=chrome_options)

Fase 3: Estrazione delle informazioni dalla pagina del video di YouTube

Creare una variabile chiamata "youtube_url_to_scrape" per memorizzare l'URL della pagina di destinazione di YouTube. Questa variabile viene poi utilizzata nel metodo "driver.get()" per indirizzare Selenium ad aprire una pagina specifica per lo scraping. L'esecuzione di questa azione aprirà una finestra separata di Chrome quando lo script viene eseguito.

youtube_url_to_scrape = ""
# Eseguire l'automazione di Selenium con le funzionalità avanzate di selenium-wire
driver.get(youtube_url_to_scrape)

Successivamente, definiamo la funzione "extract _information()" che, come suggerisce il nome, estrae le informazioni necessarie dalla pagina.

È importante assicurarsi che tutti gli elementi della pagina siano caricati. A tale scopo, utilizziamo la classe WebDriverWait per mettere in pausa lo script almeno fino a quando non è disponibile e cliccato il pulsante "more", implementato nella variabile "element". Una volta disponibile, Selenium esegue un'azione JavaScript di clic che consente di accedere alla descrizione completa del video.

Per risolvere il problema dei commenti dinamici menzionato in precedenza, stiamo implementando una soluzione per eliminare qualsiasi problema correlato. Utilizzando la classe Actions e il modulo Time, scorriamo verso il basso due volte ogni 10 secondi, assicurandoci di raccogliere il maggior numero possibile di commenti. Questo approccio proattivo protegge dai potenziali colli di bottiglia associati ai contenuti caricati dinamicamente.

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)

Esistono diversi modi per cercare elementi con Selenium Webdriver. Si può cercare per ID, CLASS_NAME, XPATH, ecc. Per questa guida, utilizzeremo una combinazione piuttosto che un solo metodo.

XPATH è un sistema più complesso, ma basato su modelli, per individuare le variabili durante lo scraping. È considerato il più complicato; tuttavia, Chrome lo ha reso semplice.

Mentre si esamina il codice utilizzando lo strumento di ispezione di Chrome, è sufficiente fare clic con il tasto destro del mouse per copiare l'XPATH. Una volta copiato, è possibile utilizzare la funzione `find_elements` per identificare tutti gli elementi che contengono le informazioni desiderate, come il titolo del video, la descrizione, ecc.

È fondamentale notare che alcuni elementi della pagina possono condividere attributi simili, il che può far sì che la chiamata `find_elements()` restituisca un elenco anziché una stringa. In questi casi, è necessario esaminare l'elenco per individuare l'indice delle informazioni rilevanti ed estrarre il testo.

Infine, viene restituita una variabile di dizionario denominata `data`, che racchiude tutte le informazioni raccolte durante lo scraping, ergo, un elemento essenziale per la sezione successiva.

 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}")

Fase 4: scrivere i dati raccolti in un file JSON

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}")

La funzione `organizza_scrittura_dei_dati()` prende in input i `dati` restituiti e li organizza in una struttura JSON formattata. Quindi scrive questi dati organizzati in un file di output chiamato "output.json", gestendo eventuali errori durante il processo di scrittura del file.

Codice completo

Ecco il codice completo del nostro programma di scraping:

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

# Specificare l'indirizzo del server proxy con nome utente e password
proxy_address = ""
proxy_username = ""
proxy_password = ""

# Impostare le opzioni di Chrome con il proxy e l'autenticazione
chrome_options = Options()
chrome_options.add_argument(f'--proxy-server={proxy_address}')
chrome_options.add_argument(f'--proxy-auth={proxy_username}:{proxy_password}')

# Creare un'istanza di WebDriver con selenium-wire
driver = wiredriver.Chrome(options=chrome_options)

youtube_url_to_scrape = ""

# Eseguire l'automazione di Selenium con le funzionalità avanzate di selenium-wire
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}")


# Registrare i dati in JSON
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()

Risultati

L'output appare come questo:

Screenshot_1.png

Sfruttare in modo sicuro la ricchezza di informazioni di YouTube è notevolmente vantaggioso quando si utilizzano script ben realizzati che utilizzano proxy per garantire l'aderenza alle politiche e alle normative della piattaforma. L'approccio sopra descritto facilita l'estrazione responsabile dei dati e attenua il rischio di potenziali restrizioni imposte dalla piattaforma.

Commenti:

0 Commenti