• Non ci sono risultati.

2. La diffusione di Facebook in Italia

2.4 Scraper: funzionamento in dettaglio

2.4.3 Dettaglio script per estrazione commenti

Come detto precedentemente, la prima parte dello script get_fb_comments_from_fb.py è identica alla prima parte dello script per l’estrazione dei post. Vediamo invece le funzioni specifiche che include.

La funzione getFacebookCommentFeedData (status_id, access_token, num_comments) con parametri come ID dello status analizzato, access token dell’utilizzatore e numero di commenti da analizzare si comporta in modo analogo alla funzione

getFacebookPageFeedData dello script precedente. Si occupa della costruzione di un

URL sulla quale baserà la richiesta fatta con la funzione request_until_succeed(url), in cui concatena ID pagina e i campi richiesti, in questo caso ID del commento, testo del

commento (message), numero di like, data di creazione, autore (from), allegati (attachment, ovvero indirizzi di foto o link).

def getFacebookCommentFeedData(status_id, access_token, num_comments):

#costruzione l’url composto da base, nodo, campi e parametri base = "https://graph.facebook.com/v2.6"

node = "/%s/comments" % status_id

fields = "?fields=id,message,like_count,created_time, comments,from, attachment"

parameters = "&order=chronological&limit=%s&access_token= %s" % \

(num_comments, access_token) url = base + node + fields + parameters #reperimento dei dati come risposta JSON data = request_until_succeed(url)

if data is None: return None else:

return json.loads(data)

La funzione processFacebookComment (comment, status_id, parent_id = ' ') ha il compito di analizzare i commenti al post indicato reperiti prima. Ha come parametri:

• un commento (trattato come un dizionario); • ID del post commentato;

• ID del commento genitore se presente (questo nel caso in cui il commento sia una risposta a un altro commento, altrimenti il campo di default viene impostato come vuoto).

• ID del commento comment_id; • ID dello status commentato status_id;

• ID del commento genitore in caso di risposte parent_id, • il testo del commento comment_message,

• l’autore comment_author,

• la data di pubblicazione comment_published, • il numero dei like comment_likes.

def processFacebookComment(comment, status_id, parent_id = ''): #ogni singolo commento viene trattato come un dizionario #lo script controlla la chiave esista nel dizionario e in #caso normalizza il valore in UTF-8:

comment_id = comment['id']

comment_message = '' if 'message' not in comment else \ unicode_normalize(comment['message'])

comment_author = unicode_normalize(comment['from']['name']) comment_likes = 0 if 'like_count' not in comment else \

comment['like_count']

if 'attachment' in comment:

attach_tag = "[[%s]]" % comment['attachment'] ['type'].upper()

comment_message = attach_tag if comment_message is '' else \ (comment_message.decode("utf-8") + " " + \

attach_tag).encode("utf-8")

#Vengono restituite le tuple del dizionario:

return (comment_id, status_id, parent_id, comment_message, comment_author, comment_published, comment_likes)

La funzione scrapeFacebookPageFeedComments (page_id, access_token) con parametri ID della pagina da analizzare e access token dell’utilizzatore è la funzione principale di questo script. Ha il compito di ottenere i commenti invocando la funzione

getFacebookCommentFeedData con limite di cento post, di analizzarli un commento

alla volta con la funzione processFacebookComment e di creare un file di testo CSV in cui scrivere le informazioni trovate. I commenti sono forniti da Facebook organizzati in pagine, cioè in un elenco lungo tanto quanto il limite impostato, in questo caso cento. Se i commenti eccedono il limite, per ogni pagina ottenuta la presenza di un campo next indica l’esistenza di una pagina successiva (al massimo di cento commenti anche essa). La funzione scrapeFacebookPageFeedComments ottiene una pagina di cento commenti alla volta, e finché è presente il campo next continua a chiedere la pagina successiva per analizzare tutti i commenti. Lo stesso meccanismo è applicato alle risposte ai commenti. Vediamo il codice nel dettaglio:

def scrapeFacebookPageFeedComments(page_id, access_token): #crea un file CSV con le colonne specificate in basso: with open('%s_facebook_comments.csv' % file_id, 'wb') as file:

w = csv.writer(file) #nome delle colonne

w.writerow(["comment_id", "status_id", "parent_id", "comment_message","comment_author",

"comment_published","comment_likes"])

#stampa nel terminale o prompt dei comandi un feedback di #quanto svolge, per tenere l’utente informato. In questa riga #visualizza la pagina target e l’ora di inizio analisi:

num_processed = 0 #contatore dei commenti analizzati scrape_starttime = datetime.datetime.now()

print "Scraping %s Comments From Posts: %s\n" % \ (file_id, scrape_starttime)

with open('%s_facebook_statuses.csv' % file_id, 'rb') as csvfile:

reader = csv.DictReader(csvfile)

#finché c’è una pagina successiva, analizza i commenti ai post con

#la funzione getFacebookCommentFeedData invocata su uno status alla

#volta e chiedendo 100 commenti per volta.

#Analizza i commenti con la funzione processFacebookComment e ne #scrive nel file CSV i campi esaminati

for status in reader: has_next_page = True comments =

getFacebookCommentFeedData(status['status_id'], access_token, 100)

while has_next_page and comments is not None: for comment in comments['data']:

w.writerow(processFacebookComment(comment, status['status_id']))

#controlla se i commenti abbiano una sottopagina di risposte e in quel

#caso li analizza fino a completarli con il meccanismo spiegato prima if 'comments' in comment: has_next_subpage = True subcomments = getFacebookCommentFeedData( comment['id'], access_token, 100) while has_next_subpage:

for subcomment in subcomments['data']: #scrive i campi relativi ai commenti di risposta nel CSV

w.writerow(processFacebookComment (subcomment, status['status_id'],comment['id']))

#aggiorna il contatore dei commenti

#ogni migliaia di commenti analizzati stampa un messaggio di feedback

#nel terminale

if num_processed % 1000 == 0:

print "%s Comments Processed: %s" % \

(num_processed,

datetime.datetime.now()) #controlla se ci siano altre pagine con altre risposte ai commenti e #in caso le chiede:

if 'paging' in subcomments: if 'next' in subcomments['paging']: subcomments = json.loads( request_until_succeed( subcomments['paging']\ ['next'])) else: has_next_subpage = False else: has_next_subpage = False #aggiorna il contatore dei commenti

num_processed += 1

#ogni migliaia di commenti analizzati stampa un messaggio di feedback

#nel terminale

if num_processed % 1000 == 0:

print "%s Comments Processed: %s" % \ (num_processed,

datetime.datetime.now())

#controlla se ci siano altre pagine di altri commenti e in caso le

if 'paging' in comments: if 'next' in comments['paging']: comments = json.loads(request_until_succeed( comments['paging']['next'])) else: has_next_page = False else: has_next_page = False

#stampa un messaggio che avvisa della fine dell’esecuzione #dello script, del numero di commenti analizzati e del tempo #impiegato

print "\nDone!\n%s Comments Processed in %s" % \ (num_processed, datetime.datetime.now() -

scrape_starttime)

Documenti correlati