From f6ba06ce8d78459964dc09faba5c45bb10fbf721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9opold=20Cl=C3=A9ment?= Date: Mon, 1 Mar 2021 18:24:19 +0100 Subject: [PATCH] Initial commit --- Lecteur_messenger.py | 280 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 Lecteur_messenger.py diff --git a/Lecteur_messenger.py b/Lecteur_messenger.py new file mode 100644 index 0000000..b423dea --- /dev/null +++ b/Lecteur_messenger.py @@ -0,0 +1,280 @@ +# -*- 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)])