From 5399c320265251c2e63d04c1da2734611ac5e9ba Mon Sep 17 00:00:00 2001 From: Bryce Boe Date: Thu, 21 Jul 2016 08:14:20 -0700 Subject: [PATCH] Fix formatting and include in doc build. Notable Changes: * Lines should be fewer than 80 characters. * Remove empty whitespace lines * Code block code segments should be initially indented with three spaces. * Header line indicators should be as long as the header. --- docs/index.rst | 1 + docs/pages/reply_bot.rst | 244 ++++++++++++++++++++++----------------- 2 files changed, 138 insertions(+), 107 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index ed985f9bc..f1b8c4ed9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,6 +6,7 @@ Table of Contents .. toctree:: :maxdepth: 1 + pages/reply_bot pages/changelog pages/code_overview pages/contributor_guidelines diff --git a/docs/pages/reply_bot.rst b/docs/pages/reply_bot.rst index 3a464903d..2d5cb6acf 100644 --- a/docs/pages/reply_bot.rst +++ b/docs/pages/reply_bot.rst @@ -1,34 +1,41 @@ -.. _simple_reply_bot: - A Simple Stream-Based Reply Bot -================================ +=============================== -Any Redditor has seen bots in action on the site. They can provide useful information (like an Imperial to Metric bot), convenience (link corrector bots), or analytical information (redditor analyzer bot for writing complexity), among other things. +Any Redditor has seen bots in action on the site. They can provide useful +information (like an Imperial to Metric bot), convenience (link corrector +bots), or analytical information (redditor analyzer bot for writing +complexity), among other things. PRAW is the simplest way to build your own bot using Python. -This tutorial will show you how to build a bot that monitors a particular subreddit (/r/AskReddit), and replies to new threads that contain simple questions with a link to "lmgtfy.com" (Let Me Google This For You). +This tutorial will show you how to build a bot that monitors a particular +subreddit (/r/AskReddit), and replies to new threads that contain simple +questions with a link to "lmgtfy.com" (Let Me Google This For You). To do this, there are 3 key components we'll have to address: 1. A way to monitor new threads. -2. A way to analyze the titles of those threads and see if they contain a simple question. +2. A way to analyze the titles of those threads and see if they contain a + simple question. 3. A way make the desired reply. Working demo: LMGTFY Bot --------------------------- +------------------------ -Our goal is to point users in the right direction when they ask a simple question that is unlikely to be upvoted or answered by other users. +Our goal is to point users in the right direction when they ask a simple +question that is unlikely to be upvoted or answered by other users. I'm referring to simple questions like: 1. "What is the capital of Canada?" - + 2. "How many feet are in a yard?" - -Once we identify these questions, our bot will send a link to lmgtfy.com with the query attached to it. For those above questions, the links would look like this: + +we identify these questions, our bot will send a link to lmgtfy.com with the +query attached to it. For those above questions, the links would look like +this: 1. http://lmgtfy.com/?q=What+is+the+capital+of+Canada%3F @@ -38,31 +45,36 @@ Let's start by setting up a basic PRAW instance: .. code-block:: python - import praw + import praw - r = praw.Reddit(user_agent='Let me Google that for you Bot', client_id='CLIENT_ID', - client_secret="CLIENT_SECRET", - username='USERNAME', - password='PASSWORD') + r = praw.Reddit(user_agent='Let me Google that for you Bot', + client_id='CLIENT_ID', client_secret="CLIENT_SCRET", + username='USERNAME', password='PASSWORD') -As usual, you will need an Oauth client_id and client_secret key for your bot (See Oauth set-up instructions here). +As usual, you will need an Oauth client_id and client_secret key for your bot +(See Oauth set-up instructions here). -Additionally, you'll need to supply the credentials of your bot's account in the form of the "username" and "password" variables passed to the main Reddit instance. +Additionally, you'll need to supply the credentials of your bot's account in +the form of the "username" and "password" variables passed to the main Reddit +instance. Step 1: Monitor New Threads and Grab the titles ----------------------------------------------- -To get the threads (submissions) to a subreddit, we simply need to call the subreddit method of our "r" object, like so: +To get the threads (submissions) to a subreddit, we simply need to call the +subreddit method of our "r" object, like so: .. code-block:: python - - subreddit= r.subreddit('askreddit').new(limit=100) -The limit here is 100 by default (so you could remove it), but you could change it if desired. + subreddit= r.subreddit('askreddit').new(limit=100) + +The limit here is 100 by default (so you could remove it), but you could change +it if desired. This code creates a lazy-loaded subreddit object. -Next, we'll need to extract the thread ids for each submission in the subreddit. +Next, we'll need to extract the thread ids for each submission in the +subreddit. Here's how: @@ -72,7 +84,8 @@ Here's how: for thread in subreddit: ids.append(thread.id) -Once we have the ids, we can create a submission object for each thread, and extract/store the titles. +Once we have the ids, we can create a submission object for each thread, and +extract/store the titles. .. code-block:: python @@ -81,9 +94,10 @@ Once we have the ids, we can create a submission object for each thread, and ext title = thread.title.lower() Step 2: Analyze the Titles ---------------------------- +-------------------------- -Now that we have the titles of the threads in the "new" feed of /r/AskReddit, it's time to see if they contain a simple question in them. +Now that we have the titles of the threads in the "new" feed of /r/AskReddit, +it's time to see if they contain a simple question in them. This might mean that they contain strings like: @@ -91,149 +105,165 @@ This might mean that they contain strings like: * "who is" * "what are" -And so on...You could get a lot for complicated, even considering title length. However, for the sake of this example, these 3 phrases will be enough. +And so on...You could get a lot for complicated, even considering title +length. However, for the sake of this example, these 3 phrases will be enough. Create an array that contains these strings. .. code-block:: python - questions = ['what is', 'who is', 'what are'] + questions = ['what is', 'who is', 'what are'] -Then, let's revisit our for-loop from above and check to see if the titles contain any of these: +Then, let's revisit our for-loop from above and check to see if the titles +contain any of these: .. code-block:: python - for id_number in ids: - thread = r.submission(id=id_number) - title = thread.title.lower() - for question_type in questions: - if question_type in title: - #make the reply + for id_number in ids: + thread = r.submission(id=id_number) + title = thread.title.lower() + for question_type in questions: + if question_type in title: + #make the reply Step 3: Make an Automated Reply ------------------------------- -We're almost there, the last part is to make a reply request to the Reddit API. Thankfully, it's really simple with PRAW. +We're almost there, the last part is to make a reply request to the Reddit +API. Thankfully, it's really simple with PRAW. -But first, we'll need to figure out what link to send people to in our comments. +But first, we'll need to figure out what link to send people to in our +comments. -By analyzing the lmgtfy links from earlier, the main things we need to do is change spaces to "+", and question marks to "%3F" (http://lmgtfy.com/?q=What+is+the+capital+of+Canada%3F). +By analyzing the lmgtfy links from earlier, the main things we need to do is +change spaces to "+", and question marks to "%3F" +(http://lmgtfy.com/?q=What+is+the+capital+of+Canada%3F). Here's a very simple function to do so: .. code-block:: python - def fixurl(phrase): - removespaces = phrase.replace(" ", "+") - removequestions = removespaces.replace("?", "%3F") - return removequestions + def fixurl(phrase): + removespaces = phrase.replace(" ", "+") + removequestions = removespaces.replace("?", "%3F") + return removequestions -Then, we can format the text that we want to include in our reply (according to Reddit formatting guidelines), and make the reply: +Then, we can format the text that we want to include in our reply (according to +Reddit formatting guidelines), and make the reply: .. code-block:: python - for id_number in ids: - thread = r.submission(id=id_number) - title = thread.title.lower() - for question_type in questions: - if question_type in title: - #make the reply - correct_url = fixurl(title) - reply_text="[Here's a link that might help](http://lmgtfy.com/?q=%s)" % (correct_url) - #send the actual reply request - thread.reply(reply_text) - -If all went well, your post should have been made. Keep in mind that if your bot account is brand new, you'll be limited in how many posts you can make until you build up some karma. You may also have to manually answer Captchas at the start. + for id_number in ids: + thread = r.submission(id=id_number) + title = thread.title.lower() + for question_type in questions: + if question_type in title: + # make the reply + correct_url = fixurl(title) + reply_text="[Here's a link that might help](http://lmgtfy.com/?q=%s)" % (correct_url) + # send the actual reply request + thread.reply(reply_text) + +If all went well, your post should have been made. Keep in mind that if your +bot account is brand new, you'll be limited in how many posts you can make +until you build up some karma. You may also have to manually answer Captchas at +the start. Loose ends for continuous running --------------------------------- Time to tie it altogther. -The main thing that we're missing is a way to run the bot continuously, and to not do the same work twice. +The main thing that we're missing is a way to run the bot continuously, and to +not do the same work twice. In order to do that, we'll place all the main code inside a 'while' loop. -As for the second part, when your 'subreddit' object returns the information about the AskReddit threads, they are returned in order, just like you would see if you visited /r/AskReddit/new yourself. +As for the second part, when your 'subreddit' object returns the information +about the AskReddit threads, they are returned in order, just like you would +see if you visited /r/AskReddit/new yourself. -So in order to prevent our bot from checking the same threads twice, we only need to record the most recent thread ID, and check it when the while loop is executed next. +So in order to prevent our bot from checking the same threads twice, we only +need to record the most recent thread ID, and check it when the while loop is +executed next. .. code-block:: python - while True: - ids=[] - if ids: - latest_id=ids[0] - else: - latest_id='' + while True: + ids=[] + if ids: + latest_id=ids[0] + else: + latest_id='' -This checks to make sure that the code has been run before ("if ids"), and then assigns the most recent thread ID (newest submitted) to the variable "latest_id". +This checks to make sure that the code has been run before ("if ids"), and then +assigns the most recent thread ID (newest submitted) to the variable +"latest_id". -Finally, one more loop before the main code is executed will prevent any duplicate work: +Finally, one more loop before the main code is executed will prevent any +duplicate work: .. code-block:: python - #remove any already examined threads + # remove any already examined threads if latest_id in ids: position = ids.index(latest_id) ids=ids[0:position] -This checks to see if we've already checked any threads in our newly created list of ids before, and cleaves off those old threads if we have. +This checks to see if we've already checked any threads in our newly created +list of ids before, and cleaves off those old threads if we have. Completed Code ---------------------------------- +-------------- The final code will show you how all these pieces fit together. .. code-block:: python - import time + import time - import praw + import praw - r = praw.Reddit(user_agent='Let me Google that for you Bot', - client_id='CLIENT_ID', - client_secret="CLIENT_SECRET", - username='USERNAME', - password='PASSWORD' - ) + r = praw.Reddit(user_agent='Let me Google that for you Bot', + client_id='CLIENT_ID', client_secret="CLIENT_SCRET", + username='USERNAME', password='PASSWORD') - questions = ['what is', 'who is', 'what are'] + questions = ['what is', 'who is', 'what are'] - def fixurl(phrase): - removespaces = phrase.replace(" ", "+") - removequestions = removespaces.replace("?", "%3F") - return removequestions + def fixurl(phrase): + removespaces = phrase.replace(" ", "+") + removequestions = removespaces.replace("?", "%3F") + return removequestions - while True: - ids = [] + while True: + ids = [] - # Check if we've already done some of the work - if ids: - latest_id = ids[0] - else: - latest_id = '' + # Check if we've already done some of the work + if ids: + latest_id = ids[0] + else: + latest_id = '' - subreddit = r.subreddit('askreddit').new(limit=6) + subreddit = r.subreddit('askreddit').new(limit=6) - for x in subreddit: - ids.append(x.id) + for x in subreddit: + ids.append(x.id) - # Remove any already examined threads - if latest_id in ids: - position = ids.index(latest_id) - ids = ids[0:position] + # Remove any already examined threads + if latest_id in ids: + position = ids.index(latest_id) + ids = ids[0:position] - # Identify title strings that match conditions - for id_number in ids: - thread = r.submission(id=id_number) - title = thread.title.lower() - for question_type in questions: - if question_type in title: - # make the reply - correct_url = fixurl(title) - reply_text = "[Here's a link that might help]\(http://lmgtfy.com/?q=%s)" % (correct_url) - # send the actual reply request - thread.reply(reply_text) + # Identify title strings that match conditions + for id_number in ids: + thread = r.submission(id=id_number) + title = thread.title.lower() + for question_type in questions: + if question_type in title: + # make the reply + correct_url = fixurl(title) + reply_text = "[Here's a link that might help]\(http://lmgtfy.com/?q=%s)" % (correct_url) + # send the actual reply request + thread.reply(reply_text)