<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Damien LaRocque</title>
    <description>The latest articles on DEV Community by Damien LaRocque (@iamphytan).</description>
    <link>https://dev.to/iamphytan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F391662%2Ffd9cba9b-f00f-4daa-8478-bc5cb9a5ad4b.png</url>
      <title>DEV Community: Damien LaRocque</title>
      <link>https://dev.to/iamphytan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamphytan"/>
    <language>en</language>
    <item>
      <title>Wikiquote Twitter Bot</title>
      <dc:creator>Damien LaRocque</dc:creator>
      <pubDate>Thu, 21 May 2020 20:08:55 +0000</pubDate>
      <link>https://dev.to/iamphytan/wikiquote-twitter-bot-26je</link>
      <guid>https://dev.to/iamphytan/wikiquote-twitter-bot-26je</guid>
      <description>&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;When you learn to code, it's always a good idea to work on a project that keeps you motivated. I always had a passion for IoT and APIs, so I decided to work on a small project that would allow me to use APIs. This project is a &lt;a href="https://www.wikiquote.org/"&gt;Wikiquote&lt;/a&gt; Twitter Bot that tweets inspiring quotes from Wikiquote once a day. You can find the source code here :&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/IamPhytan"&gt;
        IamPhytan
      &lt;/a&gt; / &lt;a href="https://github.com/IamPhytan/wikiquote-twitter-bot"&gt;
        wikiquote-twitter-bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A simple way to tweet famous quotes from Wikiquote
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Wikiquote Twitter Bot&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;A simple way to tweet famous quotes from Wikiquote&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/2e24508918bfbc8be9be07163e7572fcb009d494/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f7461672f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742e7376673f6c6162656c3d76657273696f6e267374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/2e24508918bfbc8be9be07163e7572fcb009d494/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f7461672f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742e7376673f6c6162656c3d76657273696f6e267374796c653d666c61742d737175617265" alt="GitHub release"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/2c4765fc1a046de0f3f45df9005d13c5b4be5890/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/2c4765fc1a046de0f3f45df9005d13c5b4be5890/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742e7376673f7374796c653d666c61742d737175617265" alt="GitHub Issues"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/3fc8ddd5f6baaa62c9f318c5d78d06a6a62176bb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742f746f74616c2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/3fc8ddd5f6baaa62c9f318c5d78d06a6a62176bb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f69616d70687974616e2f77696b6971756f74652d747769747465722d626f742f746f74616c2e7376673f7374796c653d666c61742d737175617265" alt="Downloads"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/f8dc8b0dba0c01c69878a1b06bf2167d2bf9a5dd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f8dc8b0dba0c01c69878a1b06bf2167d2bf9a5dd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Motivation&lt;/h2&gt;
&lt;p&gt;I wanted to have a bot that would tweet different quotes from Wikiquote each morning to start the day on a good note.
This small scripts uses Tweepy's &lt;a href="https://github.com/tweepy/tweepy"&gt;API&lt;/a&gt; and fredericotdn's
&lt;a href="https://github.com/federicotdn/python-wikiquotes"&gt;Wikiquote API&lt;/a&gt; to scan quotes on Wikiquote and tweet them .&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;p&gt;The following steps explain how to configure the script before running it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repo: &lt;code&gt;git clone https://github.com/IamPhytan/wikiquote-twitter-bot.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Download the requirements (or create a &lt;code&gt;virtualenv&lt;/code&gt; before) : &lt;code&gt;pip3 install -r requirements.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow &lt;a href="https://www.pythoncentral.io/introduction-to-tweepy-twitter-for-python/" rel="nofollow"&gt;this tutorial&lt;/a&gt; to get your :
&lt;ul&gt;
&lt;li&gt;Consumer key&lt;/li&gt;
&lt;li&gt;Consumer secret&lt;/li&gt;
&lt;li&gt;Access token&lt;/li&gt;
&lt;li&gt;Access token secret&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add these values to the &lt;a href="https://raw.githubusercontent.com/IamPhytan/wikiquote-twitter-bot/master/config.json"&gt;configuration file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Insert in the same &lt;a href="https://raw.githubusercontent.com/IamPhytan/wikiquote-twitter-bot/master/config.json"&gt;configuration file&lt;/a&gt; the time you want to send quotes and the names of the people who inspire you.&lt;/li&gt;
&lt;li&gt;Run the script: &lt;code&gt;python3 main.py&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow"&gt;MIT&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/IamPhytan/wikiquote-twitter-bot"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Development
&lt;/h2&gt;

&lt;p&gt;This project was small enough to be completed in one day. I coded in Python, as this language is easy enough and has the perfect libraries for it. I planned to run the bot on a Raspberry Pi, so it was perfect to develop in Python. The project has two main parts :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wikiquote Interface and quotes retrieval&lt;/li&gt;
&lt;li&gt;Twitter Interface and tweet posting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of this part of the project was built in a module. Through this arrangement, I learned how to organize Python projects. Let me explain how each module was developed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieving the quotes from Wikiquote
&lt;/h3&gt;

&lt;p&gt;For this part, I originally planned to scrape data from Wikiquote with &lt;a href="https://pypi.org/project/requests/"&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://pypi.org/project/beautifulsoup4/"&gt;&lt;em&gt;Beautiful Soup&lt;/em&gt;&lt;/a&gt; (&lt;code&gt;bs3&lt;/code&gt;, at that time), two popular web scraping libraries... until I found &lt;a href="https://github.com/federicotdn/wikiquote"&gt;&lt;code&gt;wikiquote&lt;/code&gt;&lt;/a&gt;, a python library to retrieve quotes from Wikiquote. This library is available through &lt;a href="https://pypi.org/project/wikiquote/"&gt;PyPi&lt;/a&gt;, so it's easy to deploy on another device (a Raspberry Pi, in this case).&lt;/p&gt;

&lt;p&gt;This project was the first where I had to create a configuration file. For that, I used a &lt;a href="https://github.com/IamPhytan/wikiquote-twitter-bot/blob/master/config.json"&gt;json file&lt;/a&gt;. This &lt;code&gt;json&lt;/code&gt; file contains the names of the Wikiquote pages to scrape :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"WIKIQUOTE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"FAMOUS_PEOPLE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Albert Einstein"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Isaac Newton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Marie Curie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"René Magritte"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Michel de Montaigne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Friedrich Nietzsche"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Emmanuel Kant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Platon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"René Descartes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Jean-Jacques Rousseau"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Thomas Hobbes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Aristote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Socrate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Baruch Spinoza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Pierre Bourdieu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Épicure"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Michel Foucault"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Jean-Paul Sartre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Blaise Pascal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Linus Torvalds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Richard Stallman"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Quotes from each author are then saved in a &lt;code&gt;.txt&lt;/code&gt; file, so we can keep track of all the quotes that were scraped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Posting the quotes to Twitter
&lt;/h3&gt;

&lt;p&gt;The best and most popular library to tweet with Python is &lt;a href="https://github.com/tweepy/tweepy"&gt;Tweepy&lt;/a&gt;. This library is available through &lt;a href="https://pypi.org/project/tweepy/"&gt;PyPi&lt;/a&gt;, so it's stil easy to deploy on another device (a Raspberry Pi, in this case).&lt;/p&gt;

&lt;p&gt;Before posting to Twitter, we need to configure the API with secret keys. My code for that part was mainly inspired by &lt;a href="http://naelshiab.com/quand-twitter-rencontre-python/"&gt;a tutorial&lt;/a&gt; from Nael Shiab. This tutorial is not available anymore, so here is &lt;a href="https://www.pythoncentral.io/introduction-to-tweepy-twitter-for-python/"&gt;another one&lt;/a&gt; that explains well how to set up your Twitter account.&lt;/p&gt;

&lt;p&gt;As always, the Twitter keys were added to the json configuration file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"TWITTER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CONSUMER_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;consumer-key&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CONSUMER_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;consumer-secret&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ACCESS_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;access-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ACCESS_TOKEN_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;access-token-secret&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My goal is to tweet quotes that weren't tweeted before by the bot. For that, each quote is identified by an index in a list and I made a list, called &lt;code&gt;used_tweets_idxs&lt;/code&gt;, that contains all the indexes of tweeted quotes. Each day, a quote is chosen randomly. If this quote was already tweeted, another quote is chosen randomly. The function responsible to choose the quote is therefore called recursively until the chosen quote was not tweeted before.&lt;/p&gt;

&lt;h3&gt;
  
  
  main.py : The conductor
&lt;/h3&gt;

&lt;p&gt;The two previous parts are called from &lt;code&gt;main.py&lt;/code&gt;. This script is therefore the central part of the project that conducts everything. Its main components are the following :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assertion of the interpreter (must be run with Python 3)&lt;/li&gt;
&lt;li&gt;Loading the config from the json configuration file&lt;/li&gt;
&lt;li&gt;Call of the &lt;code&gt;wikiquote&lt;/code&gt; module to retrieve quotes&lt;/li&gt;
&lt;li&gt;Call of the &lt;code&gt;twitter&lt;/code&gt; module to create the Twitter API Wrapper&lt;/li&gt;
&lt;li&gt;Tweet quote if current time is equal to the time in configuration file and while not all quotes were tweeted&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;This project was a great beginner project, but as all beginner projects, it has some lacks, in particular the fact that this script runs permanently. This is problematic when we run this bot on small computers with low processing power (i.e. : Raspberry Pi Zero), especially if we want to deploy multiple bots in parallel. &lt;/p&gt;

&lt;p&gt;I since learned the existence of &lt;a href="http://www.jessicayung.com/automate-running-a-script-using-crontab/"&gt;crontab&lt;/a&gt;. This UNIX tool can be used to run scripts in the background at regular intervals. Removing the &lt;code&gt;while&lt;/code&gt; loop and running the script with &lt;code&gt;crontab&lt;/code&gt; would release processing power and a thread for other programs.&lt;/p&gt;

&lt;p&gt;Also, the use of lists to keep data is a bad idea, as it is hard to scale up (i.e. : if we have more than a million quotes to tweet). Now that the script should not run permanently, all the lists will not keep the values after each execution of the code. The quotes should therefore be saved in a file, maybe a json file. &lt;/p&gt;

&lt;p&gt;In that case, it would also be beneficial to save those quotes in two different json keys, depending on whether they were posted on Twitter. This change would avoid to call functions recursively.&lt;/p&gt;

&lt;p&gt;Finally, it would a good idea to implement the functions of the modules in classes, so that variables (i.e. : the Twitter API Handler) can be used by multiple functions (now, methods) instead of having to call functions with lots of parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope that this post allowed you to learn how to avoid making some beginner mistakes. Lots of googling was involved through this whole project and it was quite challenging, even if this was a small project.&lt;/p&gt;

&lt;p&gt;Keep coding ! ⌨️&lt;/p&gt;

</description>
      <category>octograd2020</category>
      <category>devgrad2020</category>
      <category>python</category>
      <category>twitter</category>
    </item>
  </channel>
</rss>
