Skip to content

Commit

Permalink
Fix formatting and include in doc build.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bboe committed Jul 21, 2016
1 parent 459a3b6 commit 5399c32
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 107 deletions.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Table of Contents
.. toctree::
:maxdepth: 1

pages/reply_bot
pages/changelog
pages/code_overview
pages/contributor_guidelines
Expand Down
244 changes: 137 additions & 107 deletions docs/pages/reply_bot.rst
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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:

Expand All @@ -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
Expand All @@ -81,159 +94,176 @@ 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:

* "what is"
* "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)

0 comments on commit 5399c32

Please sign in to comment.