Build a Reddit Bot Part 2: Reply to posts

Build a Reddit Bot Series

Part 1: Read posts from reddit

Part 2: Reply to posts

Part 3: Automate our Bot

Very Important Note: Before we start, I have a request to make. I created a special Reddit for this series. Please please please stick to that. I don’t want you spamming other Reddits. The moderators may ban you, and Reddit may ban my user agent (please read part one if you don’t know what that means). So please stick to practising here:

http://www.reddit.com/r/pythonforengineers

This is my own sub-Reddit, and you have full permission to play in that region.

Before we start, all the source code is here.

2 things our bot needs to do

1.Search our subreddit for the words “I love Python” and reply to it. It can’t assume case sensitivity

  1. Keep a list of posts it has already replied to, so we are not replying to the same post again and again.

We already looked at how to do (1) in Part 1. We’ll go over it briefly again, as this time we need to do one more thing: Login to Reddit.

To keep a track of posts we have replied to, we could use something like a database. To keep it simple, I’m going to use a simple text file.

Login to Reddit with your bot

If you look at the source code, I have a file called config_skel.py:

 

Fill in the values, and rename the file to config_bot.py. Do not check this file in! If you are using my Github code, I’ve added a rule so this file won’t be checked in, so you are okay.

Let’s look at the code now. Open the file reply_post.py:

 

We start off by importing everything we need. Notice the last line: We are importing the username and password we just created. We check that this file exists:

 

If you forgot to create this file, we print the message and exit.

This code is the same as before. We create a Reddit instance.

 

We login using the credentials we saved earlier. If you aren’t logged in, you won’t be able to reply to posts.

As mentioned earlier, I am going to store the posts we have replied to in a text file called posts_replied_to.txt. Each Reddit post has its own unique id. I am storing each in a newline. An example from a live run:

 

To start off, we will assume this file doesn’t exist:

 

If the file doesn’t exist, which will be true the first time you run this program, create an empty list posts_replied_to .

If the file does exist, we open it. Let’s look at the code first. We will go over it line by line:

 

The above code is called if you have run the code at least once. Let’s go over it:

 

If you have never used Python’s with keyword, it’s a great feature. It opens the files for us, will close it, and all handle any errors. Saves us having to use try-catch blocks and handling errors ourself.

 

We read our file, and split on newline. Remember our file contains the submission ids as newlines? Splitting on it will create a list with all the ids. Taking the example I used earlier, we will get:

 

However, the list might still contain some empty values. See the last value above, it is an empty element. We get rid of them:

 

We now have a list posts_replied_to that is either empty or contains the submission ids from last runs.

 

This code is the same as before. We get the last 5 entries from our subreddit.

 

Remember I said each Reddit post gets a unique id? It is stored in submission.id. We check if this id exists in our list of posts we have replied to.

If it doesn’t, we check if the post contains the words : “I love Python”:

 

I am using regular expressions for the search. This is because the post can be in capital or not, or a mix. If the words i love python were found, we need to reply to the post. This is how you do it:

 

The add_comment() is the function that adds a comment to the current submission.

 

The next important thing is to remember which posts we have replied to. So we add the id of the current post to our list posts_replied_to.

Finally, we write out our updated list back to the file:

And that’s it. Let’s give our bot a spin.

First, we post a message on our subreddit:

Reddit1

We then run our Python script. Notice the Bot figures out the latest post, and only replies to that one:

Reddit2

And then we reload our page to check that the bot has replied.

Reddit3

Give it a try.

Change the bot message to something unique, so we know whose bot is running (otherwise we’ll have dozens of similar messages, with no idea who posted what). If you can’t think of anything unique, just attach your Reddit username.

Next Part

Hungry for more? Why not learn how to build a Twitter Analytics app?

 

PS: Interested in leveling up your Python and getting a great job? Check out the Python Apprenticeship Program.

35 thoughts on “Build a Reddit Bot Part 2: Reply to posts”

      1. Right, so the method you use in the reply_post.py file doesn’t allow this? I’m just confused by the phrase “check it in” (I’m pretty new to programming).

  1. Hi there,

    Is it possible to create bot which will post to subreddits ?

    Appreciate on your replay in advance.

    Peace,

    1. Do you mean create a new post? Yes, there is.

      I don’t remember it off the top of my head, but Praw has a function to create new posts as well. If you look in the api doc, you should see it.

      Let me know if you get stuck.

  2. Hey, thanks for everything so far, but i need some help, whenever i try to run reply_post.py, it stands there processing for a minute then automatically closes down. I tried writing it all manually but then it didn’t work. Then i tried tweaking the source, and it still didn’t work. Could you help me out here, I’m a little stuck :/

    1. He lasse,

      There might be several reasons, the most common being the server is not responding.

      If you use the Python debugger pdb to step through the code, you will find out exactly which line is causing the crash. And then we can figure out what’s wrong.

        1. At the top, add:

          import pdb

          Then add:

          pdb.set_trace()

          This will start the debugger.

          Press “n” to step over the code line by line, and see where it freezes.

    1. ok, so i read a bit about iterators, so i upped the search from 5 to 100, now i get a new error

      Traceback (most recent call last):
      File “C:\Users\Lasse\Dropbox\Reddit bot\reply_post.py”, line 47, in
      submission.add_comment(“Praise Him!”)
      File “C:\Users\Lasse\AppData\Local\Programs\Python\Python35-32\lib\site-packages\praw\objects.py”, line 1098, in add_comment
      response = self.reddit_session._add_comment(self.fullname, text)
      File “C:\Users\Lasse\AppData\Local\Programs\Python\Python35-32\lib\site-packages\praw\decorators.py”, line 348, in wrapped
      return function(cls, *args, **kwargs)
      File “C:\Users\Lasse\AppData\Local\Programs\Python\Python35-32\lib\site-packages\praw\__init__.py”, line 2407, in _add_comment
      retry_on_error=False)
      File “C:\Users\Lasse\AppData\Local\Programs\Python\Python35-32\lib\site-packages\praw\decorators.py”, line 199, in wrapped
      raise error_list[0]
      praw.errors.RateLimitExceeded: du gjør det der for ofte. prøv igjen om 2 minutter. on field ratelimit

      1. Okay, you are exceeding the rate limit, which means Reddit thinks you are a spammer. Take a day or two off, browse Reddit normally, check you account hasn’t been locked out.

        1. the account is not locked off (for now). but when i tried your subreddit, it loops the whole search for the word i want in the subreddit.get_hot. if the submission id is not in the “already replied to”.txt…

  3. I’m having 2 problems on my MAC

    1.) I ran pip instal praw in the command line and get the message ‘Requirement already satisfied’. There is a path to a program called Canopy afterwards. When I run reply_post.py from the command line I get the error ‘ImportError: No module named praw.

    Then I go to Canopy to try running reply_post.py, and it seems to get past this, but…

    2.) config_bot.py cannot be found, and the scrip exits after the file check. I renamed the skel file in the same directory at reply_post.py. I also tried creating a new file instead of renaming a file in the same directory. Do I need to enter the complete path?

    1. Yes, this is very dangerous (having multiple Python installs), as they interfere with each other.

      My advice: Have only one Python installed. Remove Canopy (or the other one).

      The file config_bot.py should be in the same directory as the reply_bot.py. Again, it might be the multiple Python versions thing- it might be running the wrong version, and looking somewhere unexpected.

      On Linux, you can give the exact path to the Python interpreter you want to use. Like this, on 1st line:

      #!/usr/bin/python

      This is called the shebang. Does Mac support this? If so, that might solve some of your problems.

      If you are still having problems, copy the code in config_bot.py to reply_post.py. I only made them separate so that I wouldn’t check my password in, but as long as you don’t check you code (into Github or similar), you should be fine.

      1. I tried removing Canopy and think i effed up. Now I get errors that permission is denied, and nothing is running. Is there a way to just clear out all this crap and start over?

        1. Yes, it isn’t fun, is it?

          I think your default Python install is messed up. I recommend doing a new install, and changing the path so that the default system Python is never called (as it’s the one causing the problems).

          To install Python:

          1. My recommendation is Anaconda, but I have never tried it on a Mac

          http://continuum.io/downloads

          2. Another way:

          http://hackercodex.com/guide/python-development-environment-on-mac-osx/

          Worst case: Use a virtual machine. Get VirtualBox, and install a flavour of Linux (Mint is what I prefer).

  4. Is there any way to create a bot that replies to a user every time that user posts? I can’t seem to find any documentation on the PRAW website that explains how to detect if a comment was made by a certain Reddit user. Right now I am iterating through /r/all/comments to find any posts made by a certain user, but I can’t figure out how to determine the user associated with a comment. Is each user given an ID that you need to check against?

    1. I don’t think there is. That would mean you’d have to put a hook on everything a user does, and I’m sure Reddit wouldn’t allow a third party to do that.

      As a simple rule, the API can’t do anything you can’t do manually.

      So Im afraid you will have to poll Reddit regularly.

  5. Thank you for this great post! I’m new to Python and bot making. I’m having an issue where the submission ID is not being written to the posts_replied_to.txt file. I’ve tested the functionality of the file by adding an ID by hand and it’s working fine, but my code isn’t writing to it. Any ideas? Thank you!

    1. Most likely a file writes issue. Are you on Windows or Linux? Check that the file has write permissions, and Python can write to it.

      Sometimes, some programs will “lock” a file, so no one else can write to it. On Windows (where this usually happens) I use a tool called Unlocker to free it. You can also reboot the system, that will remove the locks.

      Worst case, delete the file and recreate it.

    1. post_id is just a variable name I made up to loop through posts_replied_to, which counts how many posts we have replied to.

      Is that part of the loop working? Can you get any submission ids? As it should store the submission ids in posts_replied_to, so that next time, you dont reply to the same post again.

      In summary, something is going wrong, and you are not even connecting properly. I would use a debugger (pdb) to step though the code and find out what’s happening.

  6. The submission ids are being written to the file, but the bot will comment on the same post anyway. Here’s the log:

    Bot is replying to : Bagels
    Traceback (most recent call last):
    File “C:/Users/Wooten/Desktop/Sams_Game_Stuff/Python/reply_post.py”, line 29, in
    posts_replied_to.append(submission.id)
    AttributeError: ‘filter’ object has no attribute ‘append’

    1. This is the code

      subreddit = r.get_subreddit(‘pythonforengineers’)
      for submission in subreddit.get_hot(limit = 5):
      if submission.id not in posts_replied_to:
      if re.search(“bagels”, submission.title, re.IGNORECASE):
      submission.add_comment(“Saaaaaame”)
      print (“Bot is replying to : “, submission.title)
      posts_replied_to.append(submission.id)
      with open(“posts_replied_to.txt”, “w”) as f:
      for post_id in posts_replied_to:
      f.write(post_id + “\n”)

    2. It seems posts_replied_to is not a list. Check if it is being defined as something else.

      You can check by: print(type(posts_replied_to)). You should see list.

        1. You need to initialise it as: post_replied_to = []

          If you are initialising it somewhere else, remove that code.

Leave a Reply