J’avais écrit un article il y a quelques temps sur le développement d’un bot Twitter. L’utilisation de ce bot peut être bloqué par Twitter puisqu’il utilisait l’API directe de la plateforme. Cette fois-ci, nous allons voir une alternative qui utilisera directement l’interface « desktop » (bureau) de Twitter.
Pour écrire ce bot, nous allons utiliser JavaScript et un « package » (paquet) nommé Puppeteer, un package développé par Google, pour Google Chrome (ou Chromium pour ceux qui connaissent). La plupart des choses que vous pouvez faire manuellement dans votre navigateur peuvent être faites en utilisant Puppeteer ! Voici quelques exemples pour vous aider à démarrer :
- Générez des captures d’écran et des fichiers PDF de pages.
- Explorer un SPA et générer un contenu pré-rendu (par exemple « SSR »).
- Automatiser la soumission de formulaires, les tests d’interface utilisateur, la saisie au clavier, etc…
- Créez un environnement de test automatisé et à jour. Exécutez vos tests directement dans la dernière version de Chrome à l’aide des dernières fonctionnalités JavaScript et du navigateur.
- Capturez une trace chronologique de votre site pour aider à diagnostiquer les problèmes de performances.
- Testez les extensions Chrome.
Vous l’aurez compris, vous pouvez presque tout automatiser si vous connaissez un peu l’API de Puppeteer. Dans notre cas, nous allons automatiser le « follow » sur Twitter.
Je vous laisse regarder la progression des statistiques de mon compte personnel pour juger par vous-même de l’utilité de ce « hack » Twitter.
Les pré-requis
Avant de commencer, n’oubliez pas d’installer NodeJS sur votre ordinateur. Puis créez un répertoire que vous nommerez par exemple « twitter-bot-with-puppeteer ».
Ouvrez la console dans ce répertoire et installez les « packages » NPM suivant : puppeteer et node-schedule.
npm install puppeteer node-schedule --save
Ou par le biais de Yarn pour les plus confirmés d’entre vous :
yarn add puppeteer node-schedule
Dans votre répertoire de travail, nommez un fichier index.js qui contiendra les instructions pour le « follow » automatique, et un autre TwitterAutoFollow.class.js qui contiendra la classe JavaScript pour exécuter Puppeteer.
Edition du fichier TwitterAutoFollow.class.js
Dans ce fichier, nous allons retrouver une classe et plusieurs méthodes, dont un constructeur, une méthode d’initialisation, une méthode pour le « follow automatique », ainsi qu’une méthode pour faire une pause, et une autre pour clôturer le processus.
const puppeteer = require('puppeteer');class TwitterAutoFollow { /** * Notre constructeur, permettra de saisir * une configuration qui ne bougera pas */ constructor() {} /** * Initialisation du processus * * @returns {Promise} */ async init() {} /** * Exécution des actions * * @returns {Promise} */ async followFollowers() {} /** * Permet de faire une pause entre chaque action * * @param milliseconds * @returns {Promise} */ async sleep(milliseconds) { return new Promise(resolve => setTimeout(resolve, milliseconds)); } /** * Clôture le processus * * @returns {Promise} */ async close() {}}module.exports = TwitterAutoFollow;
Dans le constructeur (constructor), nous allons ajouter des configurations qui seront utilisées plus tard dans le code, ces paramètres ne changeront pas de valeur, c’est pour cela qu’on les ajoute dans le constructeur. On passera trois paramètres dans le constructeur : le token d’authentification (voir plus bas dans le tutoriel pour savoir comment le récupérer), l’agent utilisateur (vous pourrez évidemment choisir votre « user agent »), ainsi qu’un paramètre nécessaire si vous voulez contrôler visuellement ce qu’il se passe sur l’interface de Twitter.
« args » est une configuration « hack » utile pour faire tourner ce script sur une machine dédiée par exemple, on lui dit ici de ne pas utiliser de « sandbox » (bac à sable).
/** * Notre constructeur, permettra de saisir une configuration qui ne bougera pas * * @param authToken * @param userAgent * @param headless */constructor(authToken, userAgent, headless = true) { this.authToken = authToken; this.userAgent = userAgent; this.puppeteerConfig = { headless, args: [ '--no-sandbox', '--disable-setuid-sandbox' ] };}
Ensuite, on va déclarer une méthode init() nécessaire à l’initialisation du processus, elle va déclarer l’instance de Puppeteer. On passera également les paramètres suivants : le token d’authentification, et l’agent utilisateur (user agent).
/** * Initialisation du processus * * @returns {Promise} */async init(authToken = '', userAgent = '') { this.browser = await puppeteer.launch(this.puppeteerConfig); this.authToken = authToken; this.userAgent = userAgent;}
Une fois cette méthode remplie et comprise, vous pouvez passer à la suite.
On va écrire maintenant la méthode la plus attendue du tutoriel, celle qui va « follow » automatiquement des personnes sur une page Twitter.
Cette méthode prendra en paramètre plusieurs arguments :
- screenName : le nom d’utilisateur Twitter sur lequel vous voulez suivre ses « followers ».
- onlyWithAvatar : permettra de suivre ou non uniquement les personnes avec un avatar.
- onlyWithBio : permettra de suivre ou non uniquement les personnes ayant une biographie remplie.
- onlyIsNotProtected : permettra de suivre ou non uniquement les personnes ayant un compte non protégé (badge cadena).
- onlyNoFollowBack : permettra de suivre ou non uniquement les personnes ne s’étant pas déjà abonné à votre compte.
On déclarera l’utilisation de l’agent utilisateur (user agent) et l’inscription d’un cookie dans le navigateur (pour que Twitter sache que vous êtes connecté au site), donc pas besoin de passer par le formulaire de connexion avec une saisie automatique des identifiants de connexion.
/** * Exécution des actions * * @param screenName * @param onlyWithAvatar * @param onlyWithBio * @param onlyIsNotProtected * @param onlyNoFollowBack * @returns {Promise} */async followFollowers(screenName = 'pirmax', onlyWithAvatar = true, onlyWithBio = true, onlyIsNotProtected = true, onlyNoFollowBack = true) { this.screenName = screenName; this.page = await this.browser.newPage(); this.page.on('console', consoleObj => console.log(consoleObj._text)); // hack utile pour afficher les console.log() await this.page.setUserAgent(this.userAgent); await this.page.setCookie({ name: 'auth_token', value: this.authToken, domain: '.twitter.com', path: '/', expires: (new Date().getTime() + 86409000), httpOnly: true, secure: true }); await this.page.goto('https://twitter.com/' + this.screenName + '/followers'); await this.page.waitForNavigation(); await this.page.evaluate(async (onlyWithAvatar, onlyWithBio, onlyIsNotProtected, onlyNoFollowBack) => { const elements = await document.querySelectorAll('div[data-test-selector="ProfileTimelineUser"]'); for (const element of elements) { const profileIsProtected = !element.querySelector('span.Icon.Icon--protected'); const profileIsAlreadyFollower = !element.querySelector('span.FollowStatus'); const profileHasAvatar = !element.querySelector('img.ProfileCard-avatarImage.js-action-profile-avatar').getAttribute('src').includes('default_profile'); const profileHasBio = element.querySelector('p.ProfileCard-bio').innerHTML !== ''; const profileScreenName = element.querySelector('b.u-linkComplex-target'); const followButton = element.querySelector('button.follow-text'); if (profileIsProtected === onlyIsNotProtected && profileIsAlreadyFollower === onlyNoFollowBack && profileHasBio === onlyWithBio && profileHasAvatar === onlyWithAvatar) { followButton.click({delay: 500}); console.log('You follow ' + profileScreenName.innerHTML + ' on Twitter!'); } } }, onlyWithAvatar, onlyWithBio, onlyIsNotProtected, onlyNoFollowBack);}
On récupère alors certains éléments du DOM avec des requêtes CSS pour avoir accès aux informations qui nous intéressent, comme le bouton de soumission quand on veut suivre un utilisateur (bouton Follow), etc…
Afin d’arrêter le processus, il ne faut pas oublier une méthode, qui nous manque jusqu’à présent, la méthode close().
/** * Clôture le processus * * @returns {Promise} */async close() { await this.browser.close();}
Cette méthode permettra d’arrêter le navigateur Chrome, et mettra fin au processus.
Comment récupérer le token d’authentification ?
Pour récupérer le « token » d’authentification, il suffit de vous connecter sur Twitter, avec un navigateur comme Google Chrome par exemple. D’aller dans la console développeur, et d’aller sur l’onglet « Application ». Rendez-vous ensuite dans la section « Cookies » puis cherchez le site « https://twitter.com ». Cherchez ensuite le cookie « auth_token » et copiez sa valeur (value).
Vous êtes prêt à passer à la suite !
Edition du fichier index.js
Dans ce fichier, nous allons utiliser la classe précédemment écrite en l’instanciant.
const TwitterAutoFollow = require('./TwitterAutoFollow.class');const taf = new TwitterAutoFollow( '8f0422ef26222xxxxxxxxxxxxe79afc52a636440', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', true);
Puis nous allons utiliser la méthode init() et followFollowers() afin d’initialiser et de suivre les utilisateurs abonnés à un compte.
Dans notre cas, nous allons suivre les utilisateurs abonnés au compte Instagram et Twitter. Nous utiliserons aussi la méthode sleep() à 5 secondes pour faire une pause entre chaque action.
(async () => { await taf.init(); await taf.sleep(5000); await taf.followFollowers('instagram', true, true, true, true); await taf.sleep(5000); await taf.followFollowers('twitter', true, true, true, true); await taf.sleep(5000); await taf.close();})();
Vous pouvez également utiliser « node-schedule » (installé plus haut) pour planifier ces actions et les exécuter toutes les 15 minutes par exemple (pour éviter les abus et prévenir des blocages).
schedule.scheduleJob('*/15 * * * *', async () => { await taf.init(); await taf.sleep(5000); await taf.followFollowers('instagram', true, true, true, true); await taf.sleep(5000); await taf.followFollowers('twitter', true, true, true, true); await taf.sleep(5000); await taf.close();});
Vous pouvez héberger ce code NodeJS sur une machine dédiée afin de faire tourner le code sans avoir votre PC allumé. Retrouvez également le code sur GitHub.