Comment supprimer des pages Web et publier du contenu sur Twitter avec Python 3

L'auteur a sélectionnéThe Computer History Museum pour recevoir un don dans le cadre du programmeWrite for DOnations.

introduction

Les bots deTwitter sont un moyen puissant de gérer vos médias sociaux et d'extraire des informations du réseau de microblogging. En exploitant les API polyvalentes de Twitter, un bot peut faire beaucoup de choses: tweet, retweet, «favori-tweet», suivre les gens avec certains intérêts, répondre automatiquement, etc. Même si les gens peuvent abuser du pouvoir de leur bot, ce qui crée une expérience négative pour les autres utilisateurs, des recherches ont montré que les gens considèrent les robots Twitter comme une source d’information crédible. Par exemple, un bot peut garder vos abonnés engagés avec du contenu même lorsque vous n'êtes pas en ligne. Certains bots fournissent même des informations critiques et utiles, comme@EarthquakesSF. Les applications pour les robots sont illimitées. À partir de 2019, on estime que les bots représentent environ24% of all tweets sur Twitter.

Dans ce didacticiel, vous allez créer un bot Twitter à l'aide dethis Twitter API library pour Python. Vous utiliserez les clés API de votre compte Twitter pour autoriser votre bot et créer un outil capable de supprimer le contenu de deux sites Web. De plus, vous allez programmer votre bot pour qu’il twitte à tour de rôle le contenu de ces deux sites Web et à des intervalles de temps définis. Notez que vous utiliserez Python 3 dans ce tutoriel.

Conditions préalables

Vous aurez besoin des éléments suivants pour compléter ce didacticiel:

[.note] #Note: Vous allez configurer un compte de développeur avec Twitter, ce qui implique un examen de l'application par Twitter avant de pouvoir accéder aux clés API dont vous avez besoin pour ce bot. L'étape 1 passe en revue les détails spécifiques pour remplir la demande.
#

[[step-1 -—- setup-your-developer-account-and-access-your-twitter-api-keys]] == Étape 1 - Configuration de votre compte de développeur et accès à vos clés API Twitter

Avant de commencer à coder votre bot, vous aurez besoin des clés d’API pour que Twitter reconnaisse les requêtes de votre bot. Au cours de cette étape, vous allez configurer votre compte de développeur Twitter et accéder à vos clés d’API pour votre bot Twitter.

Pour obtenir vos clés API, rendez-vous surdeveloper.twitter.com et enregistrez votre application de bot sur Twitter en cliquant surApply dans la section supérieure droite de la page.

Cliquez maintenant surApply for a developer account.

Ensuite, cliquez surContinue pour associer votre nom d'utilisateur Twitter à votre application de bot que vous allez créer dans ce didacticiel.

Twitter Username Association with Bot

Sur la page suivante, pour les besoins de ce didacticiel, vous choisirez l'optionI am requesting access for my own personal use car vous allez créer un robot pour votre propre usage éducatif.

Twitter API Personal Use

Après avoir choisi vosAccount Name etCountry, passez à la section suivante. PourWhat use case(s) are you interested in?, choisissez les optionsPublish and curate Tweets etStudent project / Learning to code. Ces catégories sont la meilleure représentation de la raison pour laquelle vous suivez ce didacticiel.

Twitter Bot Purpose

Ensuite, décrivez le bot que vous essayez de construire. Twitter en a besoin pour se protéger contre les abus des bot; en 2018, ils ont introduit un tel vetting. Pour ce didacticiel, vous allez extraire du contenu axé sur la technologie à partir deThe New Stack etThe Coursera Blog.

Lorsque vous décidez quoi entrer dans la casedescription, modélisez votre réponse sur les lignes suivantes pour les besoins de ce didacticiel:

Je suis un didacticiel pour créer un robot Twitter qui récupérera le contenu de sites Web comme thenewstack.io (The New Stack) et blog.coursera.org (le blog de Coursera) et en tweetant des citations. Le contenu récupéré sera agrégé et tweeté de manière circulaire via les fonctions du générateur Python.

Enfin, choisissezno pourWill your product, service, or analysis make Twitter content or derived information available to a government entity?

Twitter Bot Intent

Ensuite, acceptez les conditions générales de Twitter, cliquez surSubmit application, puis vérifiez votre adresse e-mail. Twitter vous enverra un e-mail de vérification après la soumission de ce formulaire.

Une fois que vous aurez vérifié votre adresse e-mail, vous obtiendrez une pageApplication under review avec un formulaire de commentaires pour le processus de candidature.

Vous recevrez également un autre email de Twitter concernant l'examen:

Application Review Email

Le calendrier du processus d’examen des applications de Twitter peut varier considérablement, mais Twitter le confirmera souvent en quelques minutes. Toutefois, si l’examen de votre demande prend plus de temps, cela n’est pas inhabituel et vous devriez le recevoir dans un jour ou deux. Une fois la confirmation reçue, Twitter vous a autorisé à générer vos clés. Vous pouvez y accéder sous l'ongletKeys and tokens après avoir cliqué sur le bouton Détails de votre application surdeveloper.twitter.com/apps.

Enfin, accédez à l'ongletPermissions sur la page de votre application et définissez l'optionAccess Permission surRead and Write puisque vous souhaitez également écrire du contenu de tweet. Habituellement, vous utiliseriez le mode lecture seule à des fins de recherche, telles que l'analyse des tendances, l'exploration de données, etc. La dernière option permet aux utilisateurs d'intégrer les chatbots dans leurs applications existantes, car les chatbots nécessitent un accès aux messages directs.

Twitter App Permissions Page

Vous avez accès à la puissante API de Twitter, qui constituera un élément crucial de votre application bot. Vous allez maintenant configurer votre environnement et commencer à construire votre bot.

[[step-2 -—- building-the-essentials]] == Step 2 - Building the Essentials

Au cours de cette étape, vous écrirez du code pour authentifier votre bot avec Twitter à l’aide des clés de l’API, et ferez le premier tweet programmatique via votre pseudo Twitter. Cela constituera une bonne étape dans votre chemin vers l'objectif de créer un robot Twitter qui récupère le contenu deThe New Stack et desCoursera Blog et les tweete périodiquement.

Tout d’abord, vous allez configurer un dossier de projet et un environnement de programmation spécifique pour votre projet.

Créez votre dossier de projet:

mkdir bird

Déplacez-vous dans votre dossier de projet:

cd bird

Créez ensuite un nouvel environnement virtuel Python pour votre projet:

python3 -m venv bird-env

Activez ensuite votre environnement en utilisant la commande suivante:

source bird-env/bin/activate

Cela attachera un préfixe(bird-env) à l'invite dans la fenêtre de votre terminal.

Maintenant, passez à votre éditeur de texte et créez un fichier appelécredentials.py, qui stockera vos clés API Twitter:

nano credentials.py

Ajoutez le contenu suivant en remplaçant le code en surbrillance par vos clés Twitter:

bird/credentials.py

ACCESS_TOKEN='your-access-token'
ACCESS_SECRET='your-access-secret'
CONSUMER_KEY='your-consumer-key'
CONSUMER_SECRET='your-consumer-secret'

Vous allez maintenant installer la bibliothèque principale d’API pour l’envoi de demandes à Twitter. Pour ce projet, vous aurez besoin des bibliothèques suivantes:nltk,requests,twitter,lxml,random ettime. random ettime font partie de la bibliothèque standard de Python, vous n'avez donc pas besoin d'installer ces bibliothèques séparément. Pour installer les bibliothèques restantes, vous utiliserezpip, un gestionnaire de packages pour Python.

Ouvrez votre terminal, assurez-vous que vous vous trouvez dans le dossier du projet et exécutez la commande suivante:

pip3 install lxml nltk requests twitter
  • lxml etrequests: vous les utiliserez pour le web scraping.

  • twitter: il s'agit de la bibliothèque pour passer des appels API aux serveurs de Twitter.

  • nltk: (boîte à outils en langage naturel) Vous utiliserez pour diviser les paragraphes de blogs en phrases.

  • random: Vous l'utiliserez pour sélectionner au hasard des parties d'un article de blog entièrement récupéré.

  • time: Vous utiliserez pour faire dormir votre bot périodiquement après certaines actions.

Une fois les bibliothèques installées, vous êtes prêt à commencer la programmation. Vous allez maintenant importer vos informations d’identité dans le script principal qui exécutera le bot. Parallèlement àcredentials.py, à partir de votre éditeur de texte, créez un fichier dans le répertoire du projetbird et nommez-lebot.py:

nano bot.py

En pratique, vous répartiriez les fonctionnalités de votre bot sur plusieurs fichiers à mesure qu’il deviendrait de plus en plus sophistiqué. Cependant, dans ce didacticiel, vous mettrez tout votre code dans un seul script,bot.py, à des fins de démonstration.

Vous allez d’abord tester vos clés d’API en autorisant votre bot. Commencez par ajouter l'extrait de code suivant àbot.py:

bird/bot.py

import random
import time

from lxml.html import fromstring
import nltk
nltk.download('punkt')
import requests
from twitter import OAuth, Twitter

import credentials

Ici, vous importez les bibliothèques requises; et dans quelques cas, vous importez lesfunctions nécessaires à partir des bibliothèques. Vous utiliserez la fonctionfromstring plus tard dans le code pour convertir la source de chaîne d'une page Web grattée en une structure arborescente qui facilite l'extraction des informations pertinentes de la page. OAuth vous aidera à construire un objet d'authentification à partir de vos clés, etTwitter construira l'objet API principal pour toute communication ultérieure avec les serveurs de Twitter.

Maintenant, étendezbot.py avec les lignes suivantes:

bird/bot.py

...
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')

oauth = OAuth(
        credentials.ACCESS_TOKEN,
        credentials.ACCESS_SECRET,
        credentials.CONSUMER_KEY,
        credentials.CONSUMER_SECRET
    )
t = Twitter(auth=oauth)

nltk.download('punkt') télécharge un ensemble de données nécessaire pour analyser les paragraphes et les segmenter (diviser) en composants plus petits. tokenizer est l’objet que vous utiliserez plus tard dans le code pour diviser les paragraphes écrits en anglais.

oauth est l'objet d'authentification construit en alimentant la classeOAuth importée avec vos clés API. Vous authentifiez votre bot via la lignet = Twitter(auth=oauth). ACCESS_TOKEN etACCESS_SECRET aident à reconnaître votre application. Enfin,CONSUMER_KEY etCONSUMER_SECRET aident à reconnaître le handle via lequel l'application interagit avec Twitter. Vous utiliserez cet objett pour communiquer vos demandes à Twitter.

Enregistrez maintenant ce fichier et exécutez-le dans votre terminal à l'aide de la commande suivante:

python3 bot.py

Votre sortie ressemblera à ce qui suit, ce qui signifie que votre autorisation a réussi:

Output[nltk_data] Downloading package punkt to /Users/binaryboy/nltk_data...
[nltk_data]   Package punkt is already up-to-date!

Si vous recevez une erreur, vérifiez vos clés API enregistrées avec celles de vosTwitter developer account et réessayez. Assurez-vous également que les bibliothèques requises sont correctement installées. Sinon, utilisez à nouveaupip3 pour les installer.

Maintenant, vous pouvez essayer de tweeter quelque chose par programme. Tapez la même commande sur le terminal avec l'indicateur-i pour ouvrir l'interpréteur Python après l'exécution de votre script:

python3 -i bot.py

Ensuite, tapez ce qui suit pour envoyer un tweet via votre compte:

t.statuses.update(status="Just setting up my Twttr bot")

Ouvrez maintenant votre timeline Twitter dans un navigateur et vous verrez un tweet en haut de votre timeline contenant le contenu que vous avez posté.

First Programmatic Tweet

Fermez l'interpréteur en tapantquit() ouCTRL + D.

Votre bot a maintenant la capacité fondamentale de tweeter. Pour que votre bot puisse utiliser du contenu utile sur Twitter, vous allez incorporer le scraping Web à l’étape suivante.

[[step-3 -—- scraping-website-for-your-tweet-content]] == Étape 3 - Récupération de sites Web pour le contenu de votre Tweet

Pour introduire du contenu plus intéressant dans votre chronologie, vous allez extraire le contenu dethe New Stack et desCoursera Blog, puis publier ce contenu sur Twitter sous forme de tweets. Généralement, pour extraire les données appropriées de vos sites Web cibles, vous devez expérimenter leur structure HTML. Chaque tweet provenant du bot que vous allez construire dans ce tutoriel aura un lien vers un article de blog des sites Web choisis, avec une citation aléatoire de ce blog. Vous implémenterez cette procédure dans une fonction spécifique à la récupération de contenu de Coursera, vous la nommerez doncscrape_coursera().

Première ouverturebot.py:

nano bot.py

Ajoutez la fonctionscrape_coursera() à la fin de votre fichier:

bird/bot.py

...
t = Twitter(auth=oauth)


def scrape_coursera():

Pour extraire des informations du blog, vous devez d’abord demander la page Web correspondante aux serveurs de Coursera. Pour cela, vous utiliserez la fonctionget() de la bibliothèquerequests. get() prend une URL et récupère la page Web correspondante. Donc, vous passerezblog.coursera.org comme argument àget(). Cependant, vous devez également fournir un en-tête dans votre demande GET, ce qui garantira que les serveurs de Coursera vous reconnaissent comme un véritable client. Ajoutez les lignes en surbrillance suivantes à votre fonctionscrape_coursera() pour fournir un en-tête:

bird/bot.py

def scrape_coursera():
    HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                      ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
        }

Cet en-tête contiendra des informations relatives à un navigateur Web défini s'exécutant sur un système d'exploitation spécifique. Tant que ces informations (généralement appeléesUser-Agent) correspondent à de vrais navigateurs Web et systèmes d'exploitation, peu importe si les informations d'en-tête correspondent au navigateur Web et au système d'exploitation réels de votre ordinateur. Par conséquent, cet en-tête fonctionnera correctement pour tous les systèmes.

Une fois que vous avez défini les en-têtes, ajoutez les lignes suivantes en surbrillance pour envoyer une demande GET à Coursera en spécifiant l'URL de la page Web du blog:

bird/bot.py

...
def scrape_coursera():
    HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                      ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
        }
    r = requests.get('https://blog.coursera.org', headers=HEADERS)
    tree = fromstring(r.content)

Cela récupérera la page Web sur votre machine et enregistrera les informations de la page Web entière dans la variabler. Vous pouvez évaluer le code source HTML de la page Web à l'aide de l'attributcontent der. Par conséquent, la valeur der.content est la même que celle que vous voyez lorsque vous inspectez la page Web dans votre navigateur en faisant un clic droit sur la page et en choisissant l'optionInspect Element.

Ici, vous avez également ajouté la fonctionfromstring. Vous pouvez transmettre le code source de la page Web à la fonctionfromstring importée de la bibliothèquelxml pour construire la structuretree de la page Web. Cette structure detreevous permettra d'accéder facilement à différentes parties de la page Web. Le code source HTML a une structure arborescente particulière; chaque élément est inclus dans la balise<html> et imbriqué par la suite.

Maintenant, ouvrezhttps://blog.coursera.org dans un navigateur et inspectez sa source HTML à l'aide des outils de développement du navigateur. Faites un clic droit sur la page et choisissez l'optionInspect Element. Une fenêtre apparaît au bas du navigateur et affiche une partie du code source HTML de la page.

browser-inspect

Ensuite, cliquez avec le bouton droit sur la vignette de tout article de blog visible, puis inspectez-la. La source HTML mettra en évidence les lignes HTML pertinentes où la vignette de ce blog est définie. Vous remarquerez que tous les articles de blog sur cette page sont définis dans une balise<div> avec unclass de"recent":

blog-div

Ainsi, dans votre code, vous utiliserez tous les éléments de ces articles de blogdiv via leursXPath, ce qui est un moyen pratique d'adresser les éléments d'une page Web.

Pour ce faire, étendez votre fonction enbot.py comme suit:

bird/bot.py

...
def scrape_coursera():
    HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                      ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
                    }
    r = requests.get('https://blog.coursera.org', headers=HEADERS)
    tree = fromstring(r.content)
    links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')
    print(links)

scrape_coursera()

Ici, leXPath (la chaîne passée àtree.xpath()) indique que vous voulez des élémentsdiv de toute la source de la page Web, declass"recent". Le// correspond à la recherche sur toute la page Web,div dit à la fonction d'extraire uniquement les élémentsdiv, et[@class="recent"] lui demande d'extraire uniquement ces élémentsdiv qui ont les valeurs de leur attributclass comme"recent".

Cependant, vous n’avez pas besoin de ces éléments eux-mêmes, vous avez seulement besoin des liens qu’ils pointent, pour pouvoir accéder aux articles de blog individuels afin d’en extraire le contenu. Par conséquent, vous extrayez tous les liens en utilisant les valeurs des balises d'ancragehref qui se trouvent dans les balisesdiv précédentes des articles de blog.

Pour tester votre programme jusqu'à présent, vous appelez la fonctionscrape_coursera() à la fin debot.py.

Enregistrez et quittezbot.py.

Maintenant, exécutezbot.py avec la commande suivante:

python3 bot.py

Dans votre sortie, vous verrez unlist d'URL comme suit:

Output['https://blog.coursera.org/career-stories-from-inside-coursera/', 'https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/', ...]

Après avoir vérifié la sortie, vous pouvez supprimer les deux dernières lignes en surbrillance du scriptbot.py:

bird/bot.py

...
def scrape_coursera():
    ...
    tree = fromstring(r.content)
    links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')
    ~~print(links)~~

~~scrape_coursera()~~

Maintenant, étendez la fonction enbot.py avec la ligne en surbrillance suivante pour extraire le contenu d'un article de blog:

bird/bot.py

...
def scrape_coursera():
    ...
    links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')
    for link in links:
        r = requests.get(link, headers=HEADERS)
        blog_tree = fromstring(r.content)

Vous parcourez chaque lien, récupérez le billet de blog correspondant, extrayez une phrase aléatoire du message, puis tweetez cette phrase sous forme de citation, ainsi que l'URL correspondante. Extraire une phrase aléatoire comporte trois parties:

  1. Saisir tous les paragraphes de l'article du blog sous forme de liste.

  2. Sélectionner un paragraphe au hasard dans la liste des paragraphes.

  3. Sélection d'une phrase au hasard dans ce paragraphe.

Vous exécuterez ces étapes pour chaque article de blog. Pour en récupérer un, vous faites une demande GET pour son lien.

Maintenant que vous avez accès au contenu d'un blog, vous allez introduire le code qui exécute ces trois étapes pour en extraire le contenu souhaité. Ajoutez l’extension suivante à votre fonction de grattage qui exécute les trois étapes:

bird/bot.py

...
def scrape_coursera():
    ...
    for link in links:
        r = requests.get(link, headers=HEADERS)
        blog_tree = fromstring(r.content)
        paras = blog_tree.xpath('//div[@class="entry-content"]/p')
        paras_text = [para.text_content() for para in paras if para.text_content()]
        para = random.choice(paras_text)
        para_tokenized = tokenizer.tokenize(para)
        for _ in range(10):
            text = random.choice(para_tokenized)
            if text and 60 < len(text) < 210:
                break

Si vous inspectez le billet de blog en ouvrant le premier lien, vous remarquerez que tous les paragraphes appartiennent à la balisediv ayantentry-content comme classe. Par conséquent, vous extrayez tous les paragraphes sous forme de liste avecparas = blog_tree.xpath('//div[@class="entry-content"]/p').

Div Enclosing Paragraphs

Les éléments de la liste ne sont pas des paragraphesliteral; ce sontElementobjects. Pour extraire le texte de cesobjects, vous utilisez la méthodetext_content(). Cette ligne suit le modèle de conception de Pythonlist comprehension, qui définit une collection en utilisant une boucle qui est généralement écrite sur une seule ligne. Dansbot.py, vous extrayez le texte de chaque élément de paragrapheobject et le stockez dans unlist si le texte n'est pas vide. Pour choisir au hasard un paragraphe dans cette liste de paragraphes, vous incorporez le modulerandom.

Enfin, vous devez sélectionner une phrase au hasard dans ce paragraphe, qui est stockée dans la variablepara. Pour cette tâche, vous divisez d’abord le paragraphe en phrases. Une approche pour y parvenir consiste à utiliser la méthodesplit() de Python. Cependant, cela peut être difficile car une phrase peut être fractionnée à plusieurs points d'arrêt. Par conséquent, pour simplifier vos tâches de fractionnement, vous tirez parti du traitement du langage naturel via la bibliothèquenltk. L'objettokenizer que vous avez défini précédemment dans le didacticiel sera utile à cette fin.

Maintenant que vous avez une liste de phrases, vous appelezrandom.choice() pour extraire une phrase aléatoire. Vous voulez que cette phrase soit une citation pour un tweet, de sorte qu'elle ne puisse pas dépasser 280 caractères. Toutefois, pour des raisons esthétiques, vous sélectionnerez une phrase ni trop grande ni trop petite. Vous indiquez que votre phrase sur Twitter doit comporter entre 60 et 210 caractères. Les sélections de phraserandom.choice() peuvent ne pas satisfaire ce critère. Pour identifier la phrase correcte, votre script effectuera dix tentatives en vérifiant le critère à chaque fois. Une fois que la phrase choisie au hasard satisfait à votre critère, vous pouvez sortir de la boucle.

Bien que la probabilité soit assez faible, il est possible qu'aucune des phrases ne remplisse cette condition de taille en moins de dix tentatives. Dans ce cas, vous ignorerez la publication de blog correspondante et passerez à la suivante.

Maintenant que vous avez une phrase à citer, vous pouvez la tweeter avec le lien correspondant. Vous pouvez le faire en générant une chaîne contenant la phrase choisie de manière aléatoire ainsi que le lien de blog correspondant. Le code qui appelle cette fonctionscrape_coursera() publiera ensuite la chaîne produite sur Twitter via l'API de Twitter.

Étendez votre fonction comme suit:

bird/bot.py

...
def scrape_coursera():
    ...
    for link in links:
        ...
        para_tokenized = tokenizer.tokenize(para)
        for _ in range(10):
            text = random.choice(para)
            if text and 60 < len(text) < 210:
                break
        else:
            yield None
        yield '"%s" %s' % (text, link)

Le script n'exécute l'instructionelse que lorsque la bouclefor précédente ne s'arrête pas. Ainsi, cela ne se produit que lorsque la boucle ne parvient pas à trouver une phrase correspondant à votre taille. Dans ce cas, vous cédez simplementNone pour que le code qui appelle cette fonction puisse déterminer qu'il n'y a rien à tweeter. Ensuite, il appellera de nouveau la fonction et récupérera le contenu du prochain lien de blog. Mais si la boucle se rompt, cela signifie que la fonction a trouvé une phrase appropriée; le script n'exécutera pas l'instructionelse, et la fonction produira une chaîne composée de la phrase ainsi que du lien du blog, séparés par un seulwhitespace.

L'implémentation de la fonctionscrape_coursera() est presque terminée. Si vous souhaitez créer une fonction similaire pour supprimer un autre site Web, vous devrez répéter une partie du code que vous avez écrit pour supprimer le blog de Coursera. Pour éviter de réécrire et de dupliquer des parties du code et pour vous assurer que le script de votre bot suit le principeDRY (Don't Repeat Yourself), vous identifierez et extrayerez des parties du code que vous utiliserez encore et encore pour toute fonction de racleur écrite plus tard.

Quel que soit le site Web que la fonction est en train de supprimer, vous devrez choisir un paragraphe au hasard, puis choisir une phrase aléatoire dans ce paragraphe choisi - vous pouvez extraire ces fonctionnalités dans des fonctions distinctes. Ensuite, vous pouvez simplement appeler ces fonctions à partir des fonctions de votre grattoir et obtenir le résultat souhaité. Vous pouvez également définirHEADERS en dehors de la fonctionscrape_coursera() afin que toutes les fonctions de racleur puissent l'utiliser. Par conséquent, dans le code qui suit, la définition deHEADERS doit précéder celle de la fonction de racleur, afin que vous puissiez éventuellement l'utiliser pour d'autres scrapers:

bird/bot.py

...
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                  ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
    }


def scrape_coursera():
    r = requests.get('https://blog.coursera.org', headers=HEADERS)
    ...

Vous pouvez maintenant définir la fonctionextract_paratext() pour extraire un paragraphe aléatoire d'une liste d'objets paragraphe. Le paragraphe aléatoire passera à la fonction en tant qu'argumentparas et renverra la forme symbolique du paragraphe choisi que vous utiliserez plus tard pour l'extraction de phrases:

bird/bot.py

...
HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                      ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
        }

def extract_paratext(paras):
    """Extracts text from 

elements and returns a clean, tokenized random paragraph.""" paras = [para.text_content() for para in paras if para.text_content()] para = random.choice(paras) return tokenizer.tokenize(para) def scrape_coursera(): r = requests.get('https://blog.coursera.org', headers=HEADERS) ...

Ensuite, vous définirez une fonction qui extraira une phrase aléatoire de longueur appropriée (entre 60 et 210 caractères) du paragraphe tokenisé qu'elle reçoit en argument, que vous pouvez nommer enpara. Si une telle phrase n'est pas découverte après dix tentatives, la fonction renvoie à la placeNone. Ajoutez le code en surbrillance suivant pour définir la fonctionextract_text():

bird/bot.py

...

def extract_paratext(paras):
    ...
    return tokenizer.tokenize(para)


def extract_text(para):
    """Returns a sufficiently-large random text from a tokenized paragraph,
    if such text exists. Otherwise, returns None."""

    for _ in range(10):
        text = random.choice(para)
        if text and 60 < len(text) < 210:
            return text

    return None


def scrape_coursera():
    r = requests.get('https://blog.coursera.org', headers=HEADERS)
    ...

Une fois que vous avez défini ces nouvelles fonctions d'assistance, vous pouvez redéfinir la fonctionscrape_coursera() pour qu'elle ressemble à ceci:

bird/bot.py

...
def extract_paratext():
    for _ in range(10):<^>
        text = random.choice(para)
    ...


def scrape_coursera():
    """Scrapes content from the Coursera blog."""

    url = 'https://blog.coursera.org'
    r = requests.get(url, headers=HEADERS)
    tree = fromstring(r.content)
    links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href')

    for link in links:
        r = requests.get(link, headers=HEADERS)
        blog_tree = fromstring(r.content)
        paras = blog_tree.xpath('//div[@class="entry-content"]/p')
        para = extract_paratext(paras)
        text = extract_text(para)
        if not text:
            continue

        yield '"%s" %s' % (text, link)

Enregistrez et quittezbot.py.

Ici, vous utilisezyield au lieu dereturn car, pour parcourir les liens, la fonction de raclage vous donnera les chaînes de tweet une par une de manière séquentielle. Cela signifie que lorsque vous effectuez un premier appel au scrapersc défini commesc = scrape_coursera(), vous obtiendrez la chaîne de tweet correspondant au premier lien parmi la liste de liens que vous avez calculée dans la fonction scraper. Si vous exécutez le code suivant dans l'interpréteur, vous obtiendrezstring_1 etstring_2 comme indiqué ci-dessous, si la variablelinks dansscrape_coursera() contient une liste qui ressemble à["https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/", "https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/", ...].

python3 -i bot.py

Instanciez le grattoir et appelez-lesc:

>>> sc = scrape_coursera()

C'est maintenant un générateur; il génère ou gratte un contenu pertinent de Coursera, un à la fois. Vous pouvez accéder au contenu récupéré un par un en appelant de manière séquentiellenext() sursc:

>>> string_1 = next(sc)
>>> string_2 = next(sc)

Vous pouvez maintenantprint les chaînes que vous avez définies pour afficher le contenu récupéré:

>>> print(string_1)
"Other speakers include Priyanka Sharma, director of cloud native alliances at GitLab and Dan Kohn, executive director of the Cloud Native Computing Foundation." https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/
>>>
>>> print(string_2)
"You can learn how to use the power of Python for data analysis with a series of courses covering fundamental theory and project-based learning." https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/
>>>

Si vous utilisez à la placereturn, vous ne pourrez pas obtenir les chaînes une par une et dans une séquence. Si vous remplacez simplement lesyield parreturn dansscrape_coursera(), vous obtiendrez toujours la chaîne correspondant au premier article de blog, au lieu d'obtenir le premier dans le premier appel, le deuxième dans le deuxième appel, et ainsi de suite. Vous pouvez modifier la fonction pour renvoyer simplement unlist de toutes les chaînes correspondant à tous les liens, mais cela demande plus de mémoire. En outre, ce type de programme pourrait potentiellement faire beaucoup de requêtes aux serveurs de Coursera dans un court laps de temps si vous voulez que leslistentiers soient rapidement. Cela pourrait empêcher votre bot d'accéder temporairement à un site Web. Par conséquent,yield est la meilleure solution pour une grande variété de travaux de grattage, où vous n'avez besoin que des informations grattées une à la fois.

[[step-4 -—- scraping-additional-content]] == Étape 4 - Scraping Additional Content

Dans cette étape, vous allez créer un grattoir pourthenewstack.io. Le processus est similaire à celui que vous avez effectué à l’étape précédente. Ce sera donc un aperçu rapide.

Ouvrez le site Web dans votre navigateur et inspectez la source de la page. Vous trouverez ici que toutes les sections de blog sont des élémentsdiv de la classenormalstory-box.

HTML Source Inspection of The New Stack website

Vous allez maintenant créer une nouvelle fonction de récupération nomméescrape_thenewstack() et faire une requête GET àthenewstack.io à partir de celle-ci. Ensuite, extrayez les liens vers les blogs à partir de ces éléments, puis parcourez chaque lien. Ajoutez le code suivant pour y parvenir:

bird/bot.py

...
def scrape_coursera():
    ...
    yield '"%s" %s' % (text, link)


def scrape_thenewstack():
    """Scrapes news from thenewstack.io"""

    r = requests.get('https://thenewstack.io', verify=False)

        tree = fromstring(r.content)
        links = tree.xpath('//div[@class="normalstory-box"]/header/h2/a/@href')
        for link in links:

Vous utilisez l'indicateurverify=False car les sites Web peuvent parfois avoir des certificats de sécurité expirés et vous pouvez y accéder si aucune donnée sensible n'est impliquée, comme c'est le cas ici. L'indicateurverify=False indique à la méthoderequests.get de ne pas vérifier les certificats et de continuer à récupérer les données comme d'habitude. Sinon, la méthode renvoie une erreur à propos des certificats de sécurité expirés.

Vous pouvez maintenant extraire les paragraphes du blog correspondant à chaque lien et utiliser la fonctionextract_paratext() que vous avez créée à l'étape précédente pour extraire un paragraphe aléatoire de la liste des paragraphes disponibles. Enfin, extrayez une phrase aléatoire de ce paragraphe en utilisant la fonctionextract_text(), puisyield avec le lien de blog correspondant. Ajoutez le code en surbrillance suivant à votre fichier pour accomplir ces tâches:

bird/bot.py

...
def scrape_thenewstack():
    ...
    links = tree.xpath('//div[@class="normalstory-box"]/header/h2/a/@href')

    for link in links:
        r = requests.get(link, verify=False)
        tree = fromstring(r.content)
        paras = tree.xpath('//div[@class="post-content"]/p')
        para = extract_paratext(paras)
        text = extract_text(para)
        if not text:
            continue

        yield '"%s" %s' % (text, link)

Vous avez maintenant une idée de ce qu'un processus de grattage englobe généralement. Vous pouvez maintenant créer vos propres grattoirs personnalisés qui peuvent, par exemple, gratter les images dans des articles de blog au lieu de citations aléatoires. Pour cela, vous pouvez rechercher les balises<img> pertinentes. Une fois que vous avez le bon chemin pour les balises, qui servent d’identificateurs, vous pouvez accéder aux informations contenues dans les balises en utilisant le nom des attributs correspondants. Par exemple, dans le cas du scraping d'images, vous pouvez accéder aux liens des images en utilisant leurs attributssrc.

À ce stade, vous avez créé deux fonctions de grattoir pour extraire le contenu de deux sites Web différents. Vous avez également créé deux fonctions auxiliaires pour réutiliser des fonctionnalités communes aux deux grattoirs. Maintenant que votre bot sait comment tweeter et quoi tweeter, vous écrirez le code pour tweeter le contenu récupéré.

[[step-5 -—- tweeting-the-scraped-content]] == Étape 5 - Tweeting the scraped content

Dans cette étape, vous allez étendre le bot pour extraire le contenu des deux sites Web et le tweeter via votre compte Twitter. Plus précisément, vous souhaitez tweeter le contenu des deux sites Web alternativement, et à intervalles réguliers de dix minutes, pendant une durée indéterminée. Ainsi, vous utiliserez uninfinite while loop pour implémenter la fonctionnalité souhaitée. Vous ferez cela dans le cadre d'une fonctionmain(), qui implémentera le processus principal de haut niveau que vous voudrez que votre bot suive:

bird/bot.py

...
def scrape_thenewstack():
    ...
    yield '"%s" %s' % (text, link)


def main():
    """Encompasses the main loop of the bot."""
    print('---Bot started---\n')
    news_funcs = ['scrape_coursera', 'scrape_thenewstack']
    news_iterators = []
    for func in news_funcs:
        news_iterators.append(globals()[func]())
    while True:
        for i, iterator in enumerate(news_iterators):
            try:
                tweet = next(iterator)
                t.statuses.update(status=tweet)
                print(tweet, end='\n\n')
                time.sleep(600)
            except StopIteration:
                news_iterators[i] = globals()[newsfuncs[i]]()

Vous créez d'abord une liste des noms des fonctions de scraping que vous avez définies précédemment et vous l'appelez en tant quenews_funcs. Ensuite, vous créez une liste vide qui contiendra les fonctions de scraper réelles, et nommez cette liste commenews_iterators. Vous le remplissez ensuite en parcourant chaque nom de la listenews_funcs et en ajoutant l'itérateur correspondant dans la listenews_iterators. Vous utilisez la fonctionglobals() intégrée de Python. Cela renvoie un dictionnaire qui mappe les noms de variables aux variables réelles dans votre script. Un itérateur est ce que vous obtenez lorsque vous appelez une fonction de grattoir: par exemple, si vous écrivezcoursera_iterator = scrape_coursera(), alorscoursera_iterator sera un itérateur sur lequel vous pourrez appeler les appels denext(). Chaque appel denext() renverra une chaîne contenant un guillemet et son lien correspondant, exactement comme défini dans l'instructionyield de la fonctionscrape_coursera(). Chaque appel denext() passe par une itération de la bouclefor dans la fonctionscrape_coursera(). Ainsi, vous ne pouvez faire autant d'appels ànext() qu'il y a de liens de blog dans la fonctionscrape_coursera(). Une fois que ce nombre dépasse, une exceptionStopIteration sera déclenchée.

Une fois que les deux itérateurs remplissent la listenews_iterators, la boucle principalewhile démarre. À l'intérieur, vous avez une bouclefor qui traverse chaque itérateur et tente d'obtenir le contenu à tweeter. Après avoir obtenu le contenu, votre bot le tweete puis dort pendant dix minutes. Si l'itérateur n'a plus de contenu à offrir, une exceptionStopIteration est déclenchée, sur laquelle vous actualisez cet itérateur en le ré-instanciant, pour vérifier la disponibilité de contenu plus récent sur le site Web source. Ensuite, vous passez au prochain itérateur, s'il est disponible. Sinon, si l'exécution atteint la fin de la liste des itérateurs, vous redémarrez depuis le début et tweetez le prochain contenu disponible. Cela permet à votre bot de tweeter le contenu alternativement des deux grattoirs aussi longtemps que vous le souhaitez.

Il ne reste plus qu'à faire un appel à la fonctionmain(). Vous faites cela lorsque le script est appelédirectly par l'interpréteur Python:

bird/bot.py

...
def main():
    print('---Bot started---\n')<^>
    news_funcs = ['scrape_coursera', 'scrape_thenewstack']
    ...

if __name__ == "__main__":
    main()

Voici une version complète du scriptbot.py. Vous pouvez également afficherthe script on this GitHub repository.

bird/bot.py

"""Main bot script - bot.py
For the DigitalOcean Tutorial.
"""


import random
import time


from lxml.html import fromstring
import nltk
nltk.download('punkt')
import requests

from twitter import OAuth, Twitter


import credentials

tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')

oauth = OAuth(
        credentials.ACCESS_TOKEN,
        credentials.ACCESS_SECRET,
        credentials.CONSUMER_KEY,
        credentials.CONSUMER_SECRET
    )
t = Twitter(auth=oauth)

HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5)'
                      ' AppleWebKit/537.36 (KHTML, like Gecko) Cafari/537.36'
        }


def extract_paratext(paras):
    """Extracts text from 

elements and returns a clean, tokenized random paragraph.""" paras = [para.text_content() for para in paras if para.text_content()] para = random.choice(paras) return tokenizer.tokenize(para) def extract_text(para): """Returns a sufficiently-large random text from a tokenized paragraph, if such text exists. Otherwise, returns None.""" for _ in range(10): text = random.choice(para) if text and 60 < len(text) < 210: return text return None def scrape_coursera(): """Scrapes content from the Coursera blog.""" url = 'https://blog.coursera.org' r = requests.get(url, headers=HEADERS) tree = fromstring(r.content) links = tree.xpath('//div[@class="recent"]//div[@class="title"]/a/@href') for link in links: r = requests.get(link, headers=HEADERS) blog_tree = fromstring(r.content) paras = blog_tree.xpath('//div[@class="entry-content"]/p') para = extract_paratext(paras) text = extract_text(para) if not text: continue yield '"%s" %s' % (text, link) def scrape_thenewstack(): """Scrapes news from thenewstack.io""" r = requests.get('https://thenewstack.io', verify=False) tree = fromstring(r.content) links = tree.xpath('//div[@class="normalstory-box"]/header/h2/a/@href') for link in links: r = requests.get(link, verify=False) tree = fromstring(r.content) paras = tree.xpath('//div[@class="post-content"]/p') para = extract_paratext(paras) text = extract_text(para) if not text: continue yield '"%s" %s' % (text, link) def main(): """Encompasses the main loop of the bot.""" print('Bot started.') news_funcs = ['scrape_coursera', 'scrape_thenewstack'] news_iterators = [] for func in news_funcs: news_iterators.append(globals()[func]()) while True: for i, iterator in enumerate(news_iterators): try: tweet = next(iterator) t.statuses.update(status=tweet) print(tweet, end='\n') time.sleep(600) except StopIteration: news_iterators[i] = globals()[newsfuncs[i]]() if __name__ == "__main__": main()

Enregistrez et quittezbot.py.

Voici un exemple d'exécution debot.py:

python3 bot.py

Vous recevrez une sortie indiquant le contenu que votre bot a supprimé, dans un format similaire à celui-ci:

Output[nltk_data] Downloading package punkt to /Users/binaryboy/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
---Bot started---

"Take the first step toward your career goals by building new skills." https://blog.coursera.org/career-stories-from-inside-coursera/

"Other speakers include Priyanka Sharma, director of cloud native alliances at GitLab and Dan Kohn, executive director of the Cloud Native Computing Foundation." https://thenewstack.io/cloud-native-live-twistlocks-virtual-conference/

"You can learn how to use the power of Python for data analysis with a series of courses covering fundamental theory and project-based learning." https://blog.coursera.org/unlock-the-power-of-data-with-python-university-of-michigan-offers-new-programming-specializations-on-coursera/

"“Real-user monitoring is really about trying to understand the underlying reasons, so you know, ‘who do I actually want to fly with?" https://thenewstack.io/how-raygun-co-founder-and-ceo-spun-gold-out-of-monitoring-agony/

Après un exemple d’exécution de votre bot, vous verrez une chronologie complète des tweets programmés publiés par votre bot sur votre page Twitter. Cela ressemblera à ceci:

Programmatic Tweets posted

Comme vous pouvez le constater, le bot twitte les liens de blogs supprimés avec des citations aléatoires de chaque blog comme faits saillants. Ce flux est maintenant un flux d'informations avec des tweets alternant entre des citations de blogs de Coursera et thenewstack.io. Vous avez créé un bot qui agrège le contenu du Web et le publie sur Twitter. Vous pouvez maintenant élargir le champ d'application de ce bot selon vos souhaits en ajoutant plus de scrapeurs pour différents sites Web. Le bot tweetera le contenu provenant de tous les scrapeurs à la va-vite, dans les intervalles de temps souhaités.

Conclusion

Dans ce didacticiel, vous avez créé un bot Twitter de base avec Python et récupéré du contenu du Web pour que votre bot puisse tweeter. Il y a beaucoup d'idées de bots à essayer; vous pouvez également implémenter vos propres idées pour l’utilité d’un bot. Vous pouvez combiner les fonctionnalités polyvalentes offertes par l’API de Twitter et créer quelque chose de plus complexe. Pour une version d'un bot Twitter plus sophistiqué, consultezchirps, un framework de bot Twitter qui utilise des concepts avancés comme le multithreading pour que le bot fasse plusieurs choses simultanément. Il existe également des robots à idées amusantes, commemisheardly. Il n’ya pas de limites à la créativité que l’on peut utiliser pour créer des robots Twitter. Il est essentiel de trouver les points de terminaison d’API appropriés pour la mise en œuvre de votre bot.

Enfin, il est important de garder à l’esprit l’étiquette de bot ou «botiquette» lors de la construction de votre prochain bot. Par exemple, si votre bot intègre le retweet, faites passer le texte de tous les tweets à travers un filtre afin de détecter les propos abusifs avant de les retweet. Vous pouvez implémenter de telles fonctionnalités en utilisant des expressions régulières et un traitement en langage naturel. En outre, lorsque vous recherchez des sources à explorer, suivez votre jugement et évitez celles qui répandent des informations erronées. Pour en savoir plus sur la botiquette, vous pouvez visiterthis blog post de Joe Mayo sur le sujet.