Twitter : Script PHP pour savoir qui ne nous suit pas

Pourquoi connaitre les personnes qui ne nous suivent pas

C’est effectivement une question importante que l’on est en droit de se poser. Après tout rien n’oblige les gens que vous suivez à vous suivre. C’est le même principe que dans la vie réelle, les personnes que vous appréciez ne vous le rendent pas forcément. Pourquoi donc vouloir repérer les mauvais suiveurs, les personnes qui vous ont retiré de leur liste d’amis ?

Voici 3 explications qui me viennent à l’esprit. C’est surement ce qui m’a poussé à développer un moyen de pister ses fans sur le réseau social. Mais il doit exister autant de raison que d’utilisateur.

  • Pour l’égo : C’est important d’être suivi par plus de personnes que ce que l’on en suit. C’est flatteur et ça remonte un peu le moral. On se sent de suite plus important. Il ne faut pas oublier que la balance globale sur l’ensemble du réseau est nulle. Il y a donc autant de personnes suivies que de suiveurs. On ne pourra donc pas tous avoir plus d’abonnés que d’abonnements. Dans ce cas, il vaut mieux être du bon côté de la balance.
  • Pour la crédibilité : Le ratio abonnés/abonnements est un facteur de crédibilité d’un compte. On est en droit de se demander comment un utilisateur qui suit plus de 200 personnes arrive à s’y retrouver. Pour améliorer cette image, on peut faire baisser ses abonnements inutiles en commençant bien entendu par les personnes qui ne nous suivent pas en retour.
  • Par mesquinerie : Tu m’as retiré alors je te retire. Si tu ne me suis pas alors je ne vois pas pourquoi je te suivrais en retour.

Utilisation de l’API twitteroauth de Abraham

Comme dans l’article précédent concernant la publication automatique de tweets, nous allons utiliser la library de référence en PHP pour interagir avec Twitter. Grâce à cette API nous allons pouvoir utiliser les méthodes de l’API v1.1 grâce à un certain formalisme.

La documentation de cette API est disponible sur le github.com De nombreux exemples sont livrés dans le package d’installation. Attention toutefois certaines fonctions sont devenues obsolètes entretemps, il convient de les remplacer par leurs équivalents.

Exemple PHP simple pour connaitre les abonnés

La première solution simple à mettre en œuvre qui vient à l’esprit est d’utiliser directement les fonctions de l’API. Toutes les fonctions existent, il ne reste plus qu’à les mettre en place. C’est ce que nous allons faire dans un premier temps.

Au moment de l’exécution on est vite limité par les restrictions de l’API qui restreint le nombre d’appel aux fonctions par heure. Pour les gros comptes ayant plusieurs milliers de followers, il est alors impossible de pourvoir terminer l’exécution de script sans tomber dans la rate limit. Une fois cette limite atteinte, il devient impossible d’exécuter des requêtes supplémentaires.

La solution consiste alors à découper le travail en plusieurs lots et de reprendre l’exécution à l’endroit où l’on s’était arrêté avant de tomber hors limite.

Amélioration du script PHP de suivi avec MySQL

Pour les comptes qui disposent d’un nombre d’abonnés important, les limites de requêtes autorisées par l’API deviennent rapidement bloquantes. Il n’est pas possible d’exécuter le script à chaque chargement de la page. Pour contourner le problème, la solution consiste à calculer régulièrement en arrière-plan le suivi des followers en différé et d’afficher le résultat autant de fois que nécessaire. Ainsi on dispose d’une situation mise à jour en permanence sans tomber hors limite.

Nous allons utiliser 2 tables dans la base de données : la première pour stocker nos abonnements et la deuxième pour stocker nos abonnées. Les personnes qui ne nous suivent pas sont obtenues en croisant ces 2 tables grâce à des requêtes SQL de contrôle.

--
-- Structure de la table `follower`
--
CREATE TABLE IF NOT EXISTS `follower` (
`idFollower` INT(11) NOT NULL AUTO_INCREMENT,
`followerUserId` BIGINT(20) NOT NULL,
`followerId` BIGINT(20) NOT NULL,
`followerName` VARCHAR(256) NOT NULL,
`followerDateAjout` DATE NOT NULL,
`followerTemoin` VARCHAR(1) NOT NULL,
PRIMARY KEY (`idFollower`),
KEY `followerUserId` (`followerUserId`,`followerId`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
 
-----------------------------------------------------------
--
-- Structure de la table `friend`
--
CREATE TABLE IF NOT EXISTS `friend` (
`idFriend` INT(11) NOT NULL AUTO_INCREMENT,
`friendUserId` BIGINT(20) NOT NULL,
`friendId` BIGINT(20) NOT NULL,
`friendName` VARCHAR(256) NOT NULL,
`friendSuivi` VARCHAR(1) NOT NULL,
`friendDateVerif` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`friendDateAjout` DATE NOT NULL,
`friendTemoin` VARCHAR(1) NOT NULL,
PRIMARY KEY (`idFriend`),
KEY `INDEX1` (`friendUserId`,`friendId`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Le script est modifié pour devenir une tâche de fond qui va s’exécuter régulièrement grâce à un planificateur de tâche sur le serveur. Le résultat du script ne sera pas affiché à l’écran mais mettra à jour les 2 tables dans la base.

Un horodatage de suivi pour chaque abonnement permet de poursuivre le traitement là où il s’est terminé la fois précédente, ainsi même si le traitement tombe hors limite, il poursuivra son traitement à l’endroit où il s’est arrêté.

Partie 1 : Récupération des informations de l’utilisateur à analyser

La première étape est de déterminer les informations sur le compte que l’on souhaite analyser. Les informations ainsi récupérées serviront de paramètre aux fonctions de l’API dans les étapes suivantes.

/* Get logged in user to help with tests. */
$user = $connection->get('account/verify_credentials');
 
// Récupération de l'id de l'utilisateur connecté
$userId = $user->id;
 
// Date du jour
$dateJour = date('Y-m-d');
 
/* statuses/followers */
$method = 'statuses/followers/';
$content = $connection->get('account/verify_credentials');
if($content->errors[0]->code==88) {
  echo "Dépassement limite content<br/>";
  exit;
}
 
// Récupération de l'id de l'utilisateur connecté
$userId = $content->id;
$totalFriends = $content->friends_count;
$totalFollowers = $content->followers_count;
echo 'Total friends : ' . $totalFriends . ' Total followers : '. $totalFollowers . '<br/>';

On dispose maintenant de l’id interne à Twitter de l’utilisateur ainsi que son nombre d’abonnés et le nombre d’abonnement. Ces informations nous serons utiles dans la suite de programme.

Partie 2 : Récupération des abonnements du compte

On va maintenant récupérer toutes les personnes que l’on suit. Les identifiants seront chargés dans la table friend. La table n’est pas purgée entre 2 lancements pour conserver l’horodatage de dernier traitement. A la place on utilise un témoin qui indique les personnes que l’on suit toujours.

///////////////////////////////
// Traitement des amis
///////////////////////////////
 
// Mise à blanc du témoin pour tout le monde de traitement sur toutes les lignes
$sql = "UPDATE friend ";
$sql.= "SET friendTemoin = '0', friendDateVerif=friendDateVerif ";
$db->query($sql) or die ($db->error);
 
$friendsCursor = -1;
$qtd = ceil($totalFriends/5000);
for($z=0;$z<$qtd;$z++){
  $friends = $connection->get('friends/ids', array('user_id'=>$userId, 'cursor'=>$friendsCursor));
  if($friends->errors[0]->code==88) {
    echo "Dépassement limite friends<br/>";
    exit;
  }
 
  $friendsCursor = $friends->next_cursor_str;
  $friendsIds = $friends->ids;
  $friendsTotal = count($friendsIds);
  echo "Total lu $friendsTotal pour $userId<br>";
 
  // On boucle sur les gens qu'on follow pour alimenter la base de données
  for($i=0; $i<$friendsTotal; $i++ ){
    // Recherche si l'utilisateur est déjà dans la table
    $sql = "SELECT idFriend FROM friend ";
    $sql.= 'WHERE friendId = ' . $friendsIds[$i] . ' AND friendUserId = ' . $userId;
    $data = $db->query($sql) or die ($db->error);
    // Si la ligne n'existe pas encore : on la crée
    if($data->num_rows == 0) {
      $sql = "INSERT INTO friend ";
      $sql.= '(`friendUserId`, `friendId`, `friendDateAjout`, `friendDateVerif`, `friendTemoin`) ';
      $sql.= 'VALUES (' . $userId . ', ' . $friendsIds[$i] . ", '$dateJour', '0001-01-01 00:00:00', '1')";
      $db->query($sql) or die ($db->error);
    }
 
    // L'utilisateur est déjà présent : on met à jour le témoin
    else {
      $sql = "UPDATE friend ";
      $sql.= "SET friendTemoin = '1', friendDateVerif=friendDateVerif ";
      $sql.= "WHERE friendUserId =  $userId AND friendId = " . $friendsIds[$i];
      $db->query($sql) or die ($db->error);
    }
  }
}
 
// On supprime ceux qui n'ont pas le témoin à 1 : on ne les suit plus
$sql = "DELETE FROM friend ";
$sql.= "WHERE friendTemoin <> '1' AND friendUserId = $userId ";
$db->query($sql) or die ($db->error);
 
// Mise à blanc du témoin pour tout le monde de traitement sur toutes les lignes
$sql = "UPDATE friend ";
$sql.= "SET friendTemoin = '0', friendDateVerif=friendDateVerif ";
$db->query($sql) or die ($db->error);

Partie 3 : Récupération des followers (abonnés)

Sur le même principe que pour récupérer les personnes que l’on suit, on va maintenant alimenter la table follower avec les personnes qui nous suivent.

///////////////////////////////
// Traitement des followers
///////////////////////////////
 
// Mise à blanc du témoin pour tout le monde de traitement sur toutes les lignes
$sql = "UPDATE follower ";
$sql.= "SET followerTemoin = '0' ";
$db->query($sql) or die ($db->error);
 
$followersCursor = -1;
$followersParLot = ceil($totalFollowers/5000);
for($y=0; $y<$followersParLot; $y++){
  echo "Début boucle $y $followersParLot<br/>";
  $followers = $connection->get('followers/ids', array('user_id'=>$userId, 'cursor'=>$followersCursor));
  if($followers->errors[0]->code==88) {
    echo "Dépassement limite followers<br/>";
    exit;
  }
 
  $followersCursor = $followers->next_cursor_str;
  $followersIds = $followers->ids;
  $followersNames = $followers->names;
  $followersTotalIds = count($followersIds);
  echo "Followers dans le lot : $followersTotalIds<br/>";
 
  for($j=0; $j<$followersTotalIds; $j++ ){
    // Recherche si le follower est déjà dans la table
    $sql = "SELECT idFollower FROM follower ";
    $sql.= 'WHERE followerId = ' . $followersIds[$j] . ' AND followerUserId = ' . $userId;
    $data = $db->query($sql) or die ($db->error);
    // Si la ligne n'existe pas encore : on la crée
    if($data->num_rows == 0) {
      $sql = "INSERT INTO follower ";
      $sql.= '(`followerUserId`, `followerId`, `followerDateAjout`, `followerTemoin`) ';
      $sql.= 'VALUES (' . $userId . ', ' . $followersIds[$j] . ", '$dateJour', '1')";
      $db->query($sql) or die ($db->error);
    }
    // Le follower est déjà présent : on met à jour le témoin
    else {
      $sql = "UPDATE follower ";
      $sql.= "SET followerTemoin = '1' ";
      $sql.= "WHERE followerUserId =  $userId AND followerId = " . $followersIds[$j];
      $db->query($sql) or die ($db->error);
    }
  }
}
 
// On supprime ceux qui n'ont pas le témoin à 1 : on ne les suit plus
$sql = "DELETE FROM follower ";
$sql.= "WHERE followerTemoin <> '1' AND followerUserId = $userId ";
$db->query($sql) or die ($db->error);
 
// Mise à blanc du témoin pour tout le monde de traitement sur toutes les lignes
$sql = "UPDATE follower ";
$sql.= "SET followerTemoin = '0' ";
$db->query($sql) or die ($db->error);

Une fois cette étape terminée, on dispose d’une table chargée avec toutes les personnes qui nous suivent.

Partie 4 : Croisement des 2 tables

Il ne reste plus qu’à consolider les données en croisant les 2 tables entre elles. Les personnes qu’on suit et qui ne nous suivent pas sont repérées grâce à une jointure entre les tables friend et follower.

// Maintenant que les friends et les followers sont chargés : on met à jour le témoin de suivi
$sql = "UPDATE friend ";
$sql.= "SET friendSuivi = '0' ";
$db->query($sql) or die ($db->error);
 
$sql = "UPDATE friend A ";
$sql.= "SET friendSuivi = '1' ";
$sql.= "WHERE CONCAT(A.friendId, A.friendUserId) IN ";
$sql.= "(SELECT CONCAT(B.followerId, B.followerUserId) FROM follower B) ";
$db->query($sql) or die ($db->error);
 
// La table est maintenant chargée avec tous les amis :
// on va aller lire plus d'informations sur l'utilisateur
$sql = 'SELECT friendId ';
$sql.= "FROM friend ";
$sql.= "WHERE friendUserId =  $userId AND friendTemoin = '0' ";
$sql.= 'ORDER BY friendDateVerif';
$data = $db->query($sql) or die ($db->error);
while($result = $data->fetch_array(MYSQLI_ASSOC)) {
  $friendId = $result['friendId'];
  $userShow = $connection->get('users/show', array('user_id'=>$friendId));
  if($userShow->errors[0]->code==88) {
    echo "Dépassement limite user<br/>";
    exit;
  }
 
  // Mise à jour de la table
  echo "Mise à jour de {$userShow->screen_name}<br/>";
  $sql = "UPDATE friend ";
  $sql.= "SET `friendName`='" . $userShow->screen_name . "', friendTemoin = '1' ";
  $sql.= "WHERE friendUserId =  $userId AND friendId = $friendId ";
  $db->query($sql) or die ($db->error);
}

Résultat final

On dispose maintenant d’un témoin dans la table friend qui indique si l’utilisateur nous soit en retour. Le programme ne se désabonne pas automatiquement. Les personnes qui nous ont unfollow apparaissent avec le témoin de suivi à 0 dans la table friend. Les utilisateurs qui follow back ont quant à elles le témoin de suivi à 1.

Personnes qui ne nous suivent pas

Il ne reste plus qu’à faire une page HTML qui utilise les données des 2 tables pour afficher un rapport sur le compte Twitter connecté.

Laisser un commentaire