Ansciad
Programmation : Python, API et Twitter

Programmation : Python, API et Twitter

Ce code Python a été développé dans le but de tirer parti de l’API Twitter pour collecter des données sur les abonnés d’un utilisateur donné, puis construire un réseau de relations entre ces abonnés. Ensuite, il effectue une détection de communauté dans ce réseau et enregistre les résultats pour une analyse ultérieure. Examinons en détail les aspects clés de ce code, son intérêt, ses difficultés et ses applications potentielles.

Intérêt:

L’intérêt majeur de ce code réside dans sa capacité à collecter et à analyser les données liées aux abonnés d’un utilisateur Twitter. Voici quelques-uns des avantages de ce script :

  1. Collecte de données significatives : En interagissant avec l’API Twitter, le code peut recueillir une quantité importante d’informations sur les abonnés d’un utilisateur, y compris leurs noms, descriptions et nombre de followers. Cela permet de mieux comprendre l’audience d’un compte Twitter.
  2. Analyse des relations : En créant un graphe des relations entre les abonnés et en identifiant des communautés, le code offre une perspective approfondie des connexions entre les utilisateurs. Cela peut être précieux pour les chercheurs en sciences sociales et les professionnels du marketing.
  3. Modularité et exportation de données : Le script calcule la modularité du réseau, ce qui permet de mesurer la qualité de la détection de communauté. De plus, il exporte le graphe au format GEXF pour une analyse plus avancée dans des outils comme Gephi.

Difficultés:

Le développement et l’exécution de ce code ne sont pas sans défis :

  1. Limites de l’API Twitter : L’API Twitter impose des restrictions strictes sur le nombre de requêtes autorisées en un certain laps de temps. Gérer ces limites nécessite une planification minutieuse pour collecter efficacement les données.
  2. Volume de données : La collecte de données sur un grand nombre d’abonnés peut générer une quantité significative de données. Il est essentiel de disposer de suffisamment d’espace de stockage pour les gérer.

Applications:

Ce code peut trouver des applications dans divers domaines, tels que :

  1. Analyse d’audience Twitter : Les professionnels du marketing peuvent l’utiliser pour mieux comprendre leur public, identifier les segments clés et adapter leurs stratégies de contenu.
  2. Recherche en sciences sociales : Les chercheurs peuvent exploiter ce script pour étudier les dynamiques des réseaux sociaux en ligne, en analysant comment les utilisateurs se connectent et interagissent.
  3. Analyse de sentiment : En identifiant des communautés et des groupes de discussion, le code peut être employé pour surveiller et analyser les discussions sur des sujets spécifiques, notamment la détection de tendances et l’analyse de sentiment.
  4. Études de réseaux sociaux : Les professionnels de la communication et de la sociologie numérique peuvent l’utiliser pour examiner les réseaux sociaux en ligne, en identifiant les leaders d’opinion et les influenceurs.

Un « graph » (ou graphe en français) est un concept fondamental en théorie des graphes et en science des réseaux. Dans ce contexte, un graphe est une structure mathématique qui représente des relations entre des entités. Dans le cadre des réseaux sociaux comme Twitter, un graphe peut être utilisé pour modéliser les relations entre les utilisateurs.

Un graphe se compose généralement de deux composants principaux :

  1. Nœuds (ou sommets) : Les nœuds représentent les entités ou les individus du réseau. Dans le cas de Twitter, chaque nœud représenterait un utilisateur Twitter. Par conséquent, chaque nœud dans le graphe est associé à un compte Twitter spécifique.
  2. Liens (ou arêtes) : Les liens représentent les relations ou les connexions entre les entités. Dans le contexte de Twitter, un lien serait une relation de suivi, c’est-à-dire qu’un utilisateur A suit un utilisateur B. Ainsi, les liens connectent les nœuds correspondants aux utilisateurs qui sont connectés sur la plateforme.

Lorsque ces nœuds et liens sont représentés graphiquement, vous obtenez un schéma visuel qui montre comment les utilisateurs sont connectés les uns aux autres. Cette représentation sous forme de graphe peut être très puissante pour comprendre la structure et les dynamiques d’un réseau social comme Twitter.

Visualisation des Communautés :

Dans un réseau social tel que Twitter, les communautés sont des groupes d’utilisateurs qui sont plus étroitement liés les uns aux autres qu’avec le reste du réseau. Ces communautés peuvent se former autour de centres d’intérêt communs, de sujets spécifiques, d’amis en commun, ou d’autres affinités. La visualisation des communautés dans un graphe Twitter peut révéler plusieurs informations importantes :

  1. Structure communautaire : Les communautés se manifestent sous forme de groupes de nœuds fortement interconnectés. En utilisant des techniques d’analyse de réseau, il est possible de détecter ces groupes et de les visualiser sous forme de clusters.
  2. Découverte de groupes d’intérêt : Les communautés peuvent indiquer des groupes d’utilisateurs partageant des intérêts similaires. En visualisant les communautés, il est plus facile de repérer ces groupes et de comprendre quels sujets ou quels thèmes les rassemblent.
  3. Identification d’influenceurs : En examinant les nœuds centraux au sein de chaque communauté, vous pouvez identifier les utilisateurs influents qui jouent un rôle clé dans ces groupes.
  4. Analyse de sentiment : En attribuant des couleurs ou des étiquettes aux communautés en fonction des sentiments associés aux discussions, vous pouvez visualiser comment les opinions et les émotions circulent au sein du réseau.

En résumé, un graphe représente les relations entre les utilisateurs d’un réseau social comme Twitter, et la visualisation des communautés dans ce graphe permet de mieux comprendre les dynamiques du réseau, d’identifier des groupes d’intérêt et d’explorer les interactions au sein de la plateforme.

 

Et voici le code.

import tweepy
import pandas as pd
import time
import os
import networkx as nx
import community

# Twitter API client
client = tweepy.Client(
    bearer_token='YOUR_BEARER_TOKEN_HERE',
    wait_on_rate_limit=True
)

# Replace the user and maximum number of primary and secondary followers
User_name = '*********'
N_followers_primary = 50
N_followers_secondary = 50

# Initialize time
start = time.time()

# Initialize request count
if N_followers_primary <= 1000:
    Max_resultsP = N_followers_primary
else:
    Max_resultsP = 1000

if N_followers_secondary <= 1000:
    Max_resultsS = N_followers_secondary
else:
    Max_resultsS = 1000

# Get user ID and optionally their follower count
User_id = client.get_user(username=User_name).data.id

# Create dataframes
df1 = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower'])  # Temporary dataframe for usernames
df1_ID = pd.DataFrame(columns=['source_ID', 'target_ID'])  # Temporary dataframe for IDs
Tableau_followers = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower'])  # Followers table
Tableau_followers_ID = pd.DataFrame(columns=['source_ID', 'target_ID'])  # Follower ID table
df2 = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower'])

Token = None  # Initialize token

# Create a directory and file path
directory = User_name
parent_dir = "C:/Users/.../twitter"

Directory_path = os.path.join(parent_dir, directory)
File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_0.csv')
Num_de_fichier = 0

try:
    os.mkdir(Directory_path)
except OSError:
    while True:
        if input('Resume the request? (y/n)   ') == "y":
            try:
                Tableau_followers_ID_notdone = pd.read_csv(
                    os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv'))  # Retrieve saved progress
                f = open(os.path.join(Directory_path, 'Num_de_fichier.txt'), 'r')
                Tableau_followers_ID = Tableau_followers_ID_notdone
                Num_de_fichier = int(f.read())
                Tableau_followers = pd.read_csv(
                    os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) +'.csv'))  # Retrieve saved progress
                Num_de_fichier = Num_de_fichier + 1
                File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) +'.csv')
                break
            except FileNotFoundError:
                print('File not found')
                quit()
        else:
            print('Stopping')
            quit()

if Num_de_fichier == 0:
    # Retrieve primary followers
    while len(Tableau_followers.index) < N_followers_primary:
        P_followers = client.get_users_followers(id=User_id, max_results=Max_resultsP,
                                                 user_fields=['public_metrics', 'description'], pagination_token=Token)
        Token = P_followers.meta.get('next_token')
        try:
            for follower in P_followers.data:
                if follower.get('public_metrics').get('followers_count') != 0:
                    df1 = pd.DataFrame(
                        [[User_name, follower.username, follower.get('description'), follower.get('public_metrics').get('followers_count')]],
                        columns=['source', 'target', 'description', 'Numb_of_follower'])
                    Tableau_followers = pd.concat([Tableau_followers, df1], ignore_index=True)
                    df1_ID = pd.DataFrame([[User_id, follower.id]], columns=['source_ID', 'target_ID'])
                    Tableau_followers_ID = pd.concat([Tableau_followers_ID, df1_ID], ignore_index=True)
        except TypeError:
            pass
        if not Token:
            break
    # DataFrame for pending work
    Tableau_followers_ID_notdone = Tableau_followers_ID
    df2 = Tableau_followers

# Dataframe manipulation
df1 = df1.iloc[0:0]

# Initialize error variables and counting
nb_errors = 0
server_error = 0
FollowerLimit = 0

Token = None  # Reset Token
Nb_loops = 0

# Retrieve secondary followers

try:
    for i in Tableau_followers_ID.index:
        print('Progress:', round(i / len(Tableau_followers_ID.index) * 100, 2), '%')
        print('Elapsed time:', round((time.time() - start) / 60), 'min')

        FollowerLimit = 0
        with open(os.path.join(Directory_path, 'Num_de_fichier.txt'), 'w') as f:
            f.write(str(Num_de_fichier))
        while FollowerLimit < N_followers_secondary:
            S_followers = client.get_users_followers(id=Tableau_followers_ID['target_ID'][i], max_results=Max_resultsS,
                                                     user_fields=['public_metrics', 'description'],
                                                     pagination_token=Token)
            Token = S_followers.meta.get('next_token')
            try:
                for followers in S_followers.data:
                    df1 = pd.DataFrame(
                        [[Tableau_followers['target'][i], followers.username, followers.get('description'),
                          followers.get('public_metrics').get('followers_count')]],
                        columns=['source', 'target', 'description', 'Numb_of_follower'])
                    df2 = pd.concat([df2, df1], ignore_index=True)
                    FollowerLimit += 1
                    Nb_loops += 1
            except TypeError:
                nb_errors += 1
            if not Token:
                break
        Tableau_followers_ID_notdone.loc[i:, :].to_csv(
            os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv'))  # Save remaining follower IDs
        df2.to_csv(File_path, index=False, escapechar='\\')  # Save the dataframe
        if Nb_loops > 10000:  # Limit rows to 10,000
            Num_de_fichier += 1
            File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) + '.csv')
            Nb_loops = 0
            df2 = df2.iloc[0:0]
except tweepy.errors.TwitterServerError:
    server_error += 1
    time.sleep(900)

print("User data access issues: ", nb_errors)
print("Server access issues:", server_error)

df2 = df2.iloc[0:0]
Tableau_followers = Tableau_followers.iloc[0:0]

for i in range(0, Num_de_fichier):
    df2 = pd.read_csv(os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(i) + '.csv'))
    Tableau_followers = pd.concat([Tableau_followers, df2], ignore_index=True)

File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '.csv')
Tableau_followers.to_csv(File_path, index=False)  # Save the final table


def delete_files(Directory_path):
    # List all files in the directory
    files = os.listdir(Directory_path)

    # Iterate through all files in the directory
    for file in files:
        # Check if the file is in CSV format and if its name ends with an integer
        if file.endswith('.csv') and file[-5].isdigit():
            # Build the full file path
            file_path = os.path.join(Directory_path, file)
            # Delete the file
            os.remove(file_path)

# Call the function to delete files
delete_files(Directory_path)

os.remove(os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv'))  # Remove the remaining follower IDs file
os.remove(os.path.join(Directory_path, 'Num_de_fichier.txt'))  # Remove the file location
end = time.time()
print("Execution time (twitter API):", round((end - start) / 3600), 'h')

quit()

# Create an undirected graph from connections
G = nx.from_pandas_edgelist(Tableau_followers, source='source', target='target', create_using=nx.Graph())

# Exclude nodes with fewer than 5 connections
G = G.subgraph([node for node, degree in dict(G.degree()).items() if degree >= 5])

# Perform community detection with the Louvain algorithm
partition = community.best_partition(G)

# Add "description" and "Numb_of_follower" information to each node
for node in G.nodes():
    if node in Tableau_followers['target'].values:
        description = Tableau_followers.loc[Tableau_followers['target'] == node, 'description'].values[0]
        numb_of_follower = Tableau_followers.loc[Tableau_followers['target'] == node, 'Numb_of_follower'].values[0]
        if pd.notna(description) and description != "":
            G.nodes[node]['description'] = description
        if pd.notna(numb_of_follower):
            G.nodes[node]['Numb_of_follower'] = numb_of_follower

# Calculate modularity for each node
modularity = community.modularity(partition, G)

# Add the modularity class to each node
for node, community_id in partition.items():
    G.nodes[node]['modularity_class'] = community_id

# Export the graph in GEXF format for Gephi
File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '.gexf')
nx.write_gexf(G, File_path)

end = time.time()
print("Execution time (network building):", round((end - start) / 3600), 'h')