Python Instagram Scraper: emoji sentiment analysis

Le interiezioni nascono dall’esigenza di migliorare la comunicazione verbale (“Boh è il mio nuovo super potere!”, 2019), allo stesso modo in cui le emoticons rendono la comunicazione scritta più chiara e meno ambigua.
Le emoticons, che sono molto più recenti delle interiezioni, spesso imitano le espressioni facciali 🙂 😉 , che permettono alle persone di capirsi dal vivo con immediatezza, oppure di dire qualcosa per fare intendere il contrario (ad esempio quando facciamo ironia).

Le emoticons sono spesso presenti nei commenti di Instagram, come brand o influencer  sarebbe molto utile comprendere le emozioni, il sentiment dei propri followers attraverso l’analisi del sentiment delle emoji.

1.0 – Emoji sentiment ranking

Nel 2015 i ricercatori Petra Kralj Novak, Jasmina Smailović, Borut Sluban e Igor Mozetič dell’Istituto Jožef Stefan di Lubiana, in Slovenia, hanno rilasciato il primo sentiment ranking per le emoji su Twitter . Questa ricerca potrebbe essere un buon punto di partenza per avere un ranking iniziale dei commenti su Instagram.

Iniziamo con crearci una classe che dovrà contenere i metodi per lo scrapping della tabella
Emoji Sentiment Ranking v1.0, per poi poter salvare i dati in una cartella e per poi poterla leggere.

Decidiamo di salvare ogni riga della tabella in formato json, prendendo però solo alcuni campi come l’unicode name da utilizzare come descrizione dell’emoji ed il sentiment score dando  una polarity positiva se maggiore di zero, negativa se minore, neutra se uguale a zero.

{
      "polarity":"positive",
      "emoji":"\ud83d\ude02",
      "unicode_name":"face_with_tears_of_joy",
      "unicode":"0x1f602",
      "sentiment_score":0.221,
      "explanation":"face with tears of joy",
      "unicode_block":"emoticons"
}




Già che ci siamo dal formato json ci creiamo subito il datamodel dei campi che andremo ad esporre e che utilizzeremo dopo nell’analisi delle emoji.

class EmojiModel(object):

	"""
	Emoji DataModel
	"""

	def __init__(self, data):
		self.polarity = data['polarity']
		self.unicode_name = data['unicode_name']
		self.unicode = data['emoji']
		self.sentiment_score = data['sentiment_score']
		self.explanation = data['explanation']
		self.unicode_block = data['unicode_block']




Per il momento salviamo la tabella in una cartella di default “ranking_emojis” e proviamo a leggere i dati.

er=EmojiRanking()
er.save_emoji_ranking()
data = er.read_emoji_ranking()
print(data)




1.1 – Emoji Ranking

import json
import emoji
import requests
from bs4 import BeautifulSoup

class EmojiRanking(object):
	
	def __init__(self):
		self.url_ranking = 'http://kt.ijs.si/data/Emoji_sentiment_ranking/index.html'
		
	def _parse_emoji_sentiment_ranking(self):

		"""
		Parsing Emoji Sentiment ranking page
		:return:
		"""

		page = requests.get(self.url_ranking)
		soup = BeautifulSoup(page.content, 'html.parser')

		table = soup.find('table')
		table_body = table.find('tbody')
		table_rows = table_body.find_all('tr')

		ranking_rows = list()
		for row in table_rows:
			cols = row.find_all('td')
			new_cols = list()
			for ele in cols:
				element = ele.text.strip()
				new_cols.append(element)

			ranking_rows.append([ele for ele in new_cols if ele])

		new_rankin_rows = list()
		for row in ranking_rows:
			del row[4:8]
			del row[0]
			del row[2]
			new_rankin_rows.append(row)
		return new_rankin_rows
	
	def _create_emoji_ranking_data(self):

		ranking_rows = self._parse_emoji_sentiment_ranking()

		new_ranking_rows = list()
		for row in ranking_rows:
			emoji_dict = dict()
			emo = row[0]
			unicode = row[1]
			sentiment_score = float(row[2])

			if sentiment_score > 0:
				emoji_dict['polarity'] = 'positive'
			elif sentiment_score < 0:
				emoji_dict['polarity'] = 'negative'
			elif sentiment_score == 0:
				emoji_dict['polarity'] = 'neutral'

			explanation = row[3]
			block = row[4]

			emoji_dict['emoji'] = emo
			emoji_dict['unicode_name'] = emoji.demojize(emo).replace(":", "")
			emoji_dict['unicode'] = unicode
			emoji_dict['sentiment_score'] = sentiment_score
			emoji_dict['explanation'] = explanation.lower()
			emoji_dict['unicode_block'] = block.lower()
			new_ranking_rows.append(emoji_dict)

		return new_ranking_rows

	def save_emoji_ranking(self, folder='ranking_emojis'):

		data = self._create_emoji_ranking_data()
		with open(folder + '/emojis.json', 'w') as write_file:
			json.dump(data, write_file)

	def read_emoji_ranking(self, folder='ranking_emojis'):
		with open(folder + '/emojis.json', "r") as read_file:
			data = json.load(read_file)
			return data





2.0 – Emoji analysis

Il successo a livello mondiale delle emoji è dimostrato dall’utilizzo poco convenzionale di tradurre i classici come Moby Dick in emoji o da Coca-Cola che nel 2015 per una campagna pubblicitaria rese possibile l’inserimento di una emoji in un indirizzo web.

Alla loro nascita le emoji erano utilizzate per lo più per comunicarci il tempo, le fasi della luna nei cercapersone, ma oggi sono ci aiutano a comprendere i messaggi testuali (e-mail, chat, commenti) fornendoci un contesto da cui poter estrarre le emozioni.

Prendiamo come esempio il commento di un’utente che abbia utillizato le emojis per dimostrare il proprio apprezzamento ad un autoritratto di Vincent van Gogh:

text = "❤❤❤❤❤❤❤"

e = EmojiAnalysis()
sentiment = e.extract_emoji_sentiment(text)
print(sentiment)




E vediamo che è stato riconosciuto l’utilizzo del cuore rosso come emoji e che lo score è di 0.746.

{
   "text":"❤❤❤❤❤❤❤",
   "demojize_text":":red_heart::red_heart::red_heart::red_heart:
                     :red_heart::red_heart::red_heart:",
   "emojis":[
      {
         "emoji":"",
         "unicode_name":"red_heart",
         "sentiment_score":0.746,
         "polarity":"positive"
      }
   ],
   "demojize_span":[...]
}




Un aspetto interessante emerso dalla ricerca  dell’Istituto Jožef Stefan di Lubiana è che i tweet contenenti delle emoji tendono ad avere un sentiment più positivo di quelli senza. Altro aspetto è la posizione delle emoji nei tweet: più carica sentimentale ha un’emoji, più è probabile che appaia alla fine dei tweet. Chissà quali sarebbero i risultati con i commenti di Instagram?

2.1 – Un po’ di magia

import emoji
import re
from emoji_ranking import EmojiRanking

class EmojiAnalysis(EmojiRanking):

	def __init__(self):
		super().__init__()
		self.emojis = dict()


	def extract_emojis(self, text):

		"""
		:param text example: i'm very happy ???? ♥
		:return:
			{
				'????': 'face_blowing_a_kiss',
				'♥': 'heart_suit'
			}
		"""

		text = emoji.demojize(text)

		pattern = r'(:[^:]*:)'
		emoji_matches = [m.group() for m in re.finditer(pattern, text)]

		self.emojis = {k: emoji.demojize(k).replace(":", "") for k in emoji_matches}
		return self.emojis

	def demoji_span(self, text):

		"""
		Span using unicode_name
		:param text:
		:return:
		"""

		text = emoji.demojize(text)
		pattern = r'(:[^:]*:)'
		span = [[m.start(), m.end()] for m in re.finditer(pattern, text)]
		return span

	def has_emoji_text(self, text):

		has_emoji = bool(emoji.get_emoji_regexp().search(text))
		return has_emoji

	def remove_emoji(self, text):

		e = emoji.get_emoji_regexp()
		new_text = re.sub(e, r"", text)
		return new_text

	def demojize_text(self, text):

		text = emoji.demojize(text)
		return text

	def extract_emoji_sentiment(self, text):

		data = self.read_emoji_ranking()
		emojis = self.extract_emojis(text)
		demojis_span = self.demoji_span(text)
		demojize_text = emoji.demojize(text)

		emojis_sentiment = list()
		for key, value in emojis.items():
			for row in data:
				e = EmojiModel(row)
				if value == e.unicode_name:
					score = e.sentiment_score
					emoji_data = {
								"emoji": emoji.emojize(key),
								"unicode_name": value,
								"sentiment_score": score,
								"polarity": e.polarity,
						}
					emojis_sentiment.append(emoji_data)

		results = {
			"text": text,
			"demojize_text": demojize_text,
			"emojis": emojis_sentiment,
			"demojize_span": demojis_span
		}

		return results