You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
8.4 KiB
Python

# -*- coding: utf-8 -*-
"""
Created on Tue Apr 28 10:46:49 2020
@author: Leopold
@version = 2.0
module permetant une annalyse des conversations Mesenger
"""
import datetime
import json
class Conv():
"""
Representation en machine d'une conversation.
## Utilisation
Utiliser `Conv.from_list` de preference.
"""
def __init__(self, cible):
"""
## Initialisation
cible : str
Emplacement du fichier `.json` de la conversation.
"""
file = open(cible)
datas = json.load(file)
file.close()
try:
self.nom = datas["title"].encode('cp1252').decode('utf8')
except UnicodeEncodeError:
self.nom = datas["title"]
self.membres = {}
"""Liste des utilisaeur dans la conversation."""
self.messages = []
"""Liste des messages de la conversation."""
for elem in datas['participants']:
self.membres[elem['name']] = User(elem['name'], self)
self._ajout_list_msg(datas['messages'])
def _ajout_list_msg(self, list_msg):
for msg in list_msg:
try:
user = self.membres[msg['sender_name']]
self.messages.append(Messages.bon_type(
msg,
user,
self,
msg['timestamp_ms']))
except KeyError:
pass
def __repr__(self):
return "{}:\n{}\n-{} messages".format(self.nom, self.membres, len(self.messages))
def classement(self):
"""
Crée un classment des membres de la conversation en fonction de
leur nombre de participation.
Returns
-------
chaine : str
Ladite chaine de la forme `numero : nom, n message`.
"""
users = [self.membres[elem] for elem in self.membres]
users.sort(key=User.n_msg, reverse=True)
chaine = ""
for n, usr in enumerate(users):
chaine += "{} : {} - {} messages\n".format(n+1, usr.nom, usr.n_msg())
return chaine
def add_fichier(self, cible):
"""
Rajoute un fichier a l'objet `Conv`.
"""
file = open(cible)
datas = json.load(file)
file.close()
self._ajout_list_msg(datas['messages'])
def pie_participation(self):
"""
Camembert du nombre de participation des participants de la conv.
"""
from matplotlib import pyplot as plt
plt.xkcd()
fig = plt.figure()
fig.title = self.nom
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('equal')
users = [self.membres[elem] for elem in self.membres]
users.sort(key=User.n_msg)
noms = [usr.nom for usr in users]
participations = [usr.n_msg() for usr in users]
ax.pie(participations, labels=noms, autopct='%1.2f%%')
plt.title("Participation des membres de la conv {}".format(self.nom))
return fig
def hist_heure(self):
"""
histogramme de l'utilisation de la `Conv` en fonction de l'heure.
"""
list_des_minutes = []
def convertisseur_timestamps(datetime_object: datetime.datetime) -> float:
time = datetime_object.time()
minutes = 0
minutes += 60 * time.hour
minutes += time.minute
minutes += 1/60 * time.second
return minutes
for message in self.messages:
list_des_minutes.append(convertisseur_timestamps(message.datetime))
from matplotlib import pyplot as plt
plt.xkcd()
plt.hist(list_des_minutes, density=True, bins=4*24, range=(0, 24*60))
plt.xticks(
[i*60*2 for i in range(0, 13)],
["{}h00".format(i*2) for i in range(0, 13)],
rotation=45)
plt.xlim(0, 24*60)
plt.title("""activité de la conv "{}" en fonction de l'heure""".format(self.nom))
return plt
def __len__(self):
return len(self.messages)
def bar_nom_ocurence_mot(self, chaine_cible: str):
"""
BarGraph du nombre d'utilisation de la chaine `chaine_cible`.
Insensible à la case.
"""
from matplotlib import pyplot as plt
plt.xkcd()
chaine_cible = chaine_cible.lower()
liste_user = []
liste_occurence = []
for msg in self.messages:
if isinstance(msg, MsgTexte):
if chaine_cible in msg.content.lower():
if msg.user in liste_user:
for n, user in enumerate(liste_user):
if msg.user == user:
liste_occurence[n] += 1
else:
liste_user.append(msg.user)
liste_occurence.append(1)
plt.bar([str(user) for user in liste_user], liste_occurence)
plt.xticks(rotation=25)
plt.title("""Utilisation du terme "{}" """.format(chaine_cible))
return plt
@classmethod
def from_list(cls, liste_adresse):
"""Permet d'initialiser une conversation à partir d'une liste de fichier"""
if not liste_adresse:
raise ValueError
conv = cls(liste_adresse[0])
for elem in liste_adresse[1:]:
conv.add_fichier(elem)
return conv
class User():
"""
Objet representant un utiliateur dans une `Conv`.
"""
def __init__(self, nom, conv=None):
"""
## Initialisation
nom : str
Nom de l'utilisateur.
conv : `Conv
Conversation associé, optionel.
"""
self.nom = None
"""Nom de l'utilisateur."""
try:
self.nom = nom.encode('cp1252').decode('utf8')
except UnicodeEncodeError:
self.nom = nom
self.conv = conv
"""`Conv` où se trouve l'utilisateur."""
self.messages = []
"""Liste des messages de l'utilisateur."""
def add_msg(self, msg):
self.messages.append(msg)
def n_msg(self):
return len(self.messages)
def __repr__(self):
return "{} - {} messages".format(self.nom, self.n_msg())
def __str__(self):
return self.nom
class Messages():
"""
Class representant les messages d'une conversation.
"""
def __init__(self, msg_data, user: User, conv: Conv, timestamp):
self.datetime = datetime.datetime.fromtimestamp(timestamp/1000)
"""Temps POSIX de parution du message."""
self.user = user
"""`User` ayant poster le message."""
self.reactionaire = []
"""Liste des personnes ayant reagit au message."""
try:
for elem in msg_data["reactions"]:
self.reactionaire.append(conv.membres[elem["actor"]])
except KeyError:
pass
user.add_msg(self)
@classmethod
def bon_type(cls, msg_data, user: User, conv: Conv, timestamp):
"""
Permet de creer un message avec la bonne sous-class en fonction de son contenu.
Soit `MsgTexe`, `MsgPhoto`.
Si le message n'a pas de class particulière `Messages`.
"""
if 'content' in msg_data:
msg = MsgTexte(msg_data, user, conv, timestamp)
elif 'photos' in msg_data:
msg = MsgPhoto(msg_data, user, conv, timestamp)
else:
msg = Messages(msg_data, user, conv, timestamp)
return msg
@property
def nombre_react(self):
"""
Nombre de personne ayant reagit à ce message.
"""
return len(self.reactionaire)
class MsgTexte(Messages):
"""
Message comportant du texte.
"""
def __init__(self, msg_data, user: User, conv: Conv, timestamp):
Messages.__init__(self, msg_data, user, conv, timestamp)
contenu = msg_data['content']
self.content = None
"""Texte du message."""
try:
self.content = contenu.encode('cp1252').decode('utf8')
except UnicodeEncodeError:
self.content = contenu
class MsgPhoto(Messages):
"""
Message comportant une image.
"""
def __init__(self, msg_data, user: User, conv: Conv, timestamp):
Messages.__init__(self, msg_data, user, conv, timestamp)
self.contenu = [elem["uri"] for elem in msg_data['photos']]
"""Emplacement de l'image dans l'archive des données FaceBook."""
EEA = Conv.from_list(["msg/EEA/message_{}.json".format(n+1) for n in range(2)])