├── README.md ├── posted_posts.txt └── reddit_bot.py /README.md: -------------------------------------------------------------------------------- 1 | Reddit-Twitter Bot 2 | ======= 3 | 4 | This bot copies posts along with their links from /r/Python (or whatever subreddit of your choosing) and posts them to Twitter. Posts will be reformatted to fit within 140 characters, and post IDs are tracked to prevent duplicate tweets. 5 | 6 | Since this bot was first posted to Github, Google and Twitter have both adjusted how links are shortened. This bot has now been updated to address issues caused by this change. Some additional features and customizability were also added, so please feel free to take a second look! 7 | 8 | Required libraries 9 | ----------- 10 | A few additional libraries are required to run this bot, they can be downloaded through [pip](https://pypi.python.org/pypi/pip): 11 | 12 | - PRAW 13 | * Reddit API wrapper for Python 14 | * install via pip: ```pip install praw``` 15 | - Tweepy 16 | * Twitter API wrapper for Python 17 | * install via pip: ```pip install tweepy``` 18 | - Requests 19 | * Python HTTP library 20 | * install via pip: ```pip install requests``` 21 | 22 | Access Tokens and API Keys 23 | ----------- 24 | To get started you will need a set of acess codes from Twitter. You can easily get them by going to dev.twitter.com/apps and registering an app. After registering you will have to change the access premissions of your app under the settings tab. After you get your access tokens and everything else just paste them in the fields provided at the beginning of the script . 25 | 26 | Google now requires an API key to access its URL shortener tool. To get this access code you will have to register at [this page for URL-Shortener authorization](https://developers.google.com/url-shortener/v1/getting_started#OAuth2Authorizing). 27 | 28 | Even if you use Google's link shortening tool, Twitter will still process your link though its t.co's shortener. Twitter does this for all links, even if they fit inside the tweet's 140 characters without shortening. Ultimately it is recommended to default to Twitter's url shortener by setting the google api key variable to "" (a blank string). 29 | 30 | Documentation 31 | ----------- 32 | I have written a blogpost about how I made this and what everything means. You can read that [here](http://freepythontips.wordpress.com/2013/09/14/making-a-reddit-twitter-bot/) 33 | 34 | Recent Changes and New Features 35 | ----------- 36 | 37 | 1. As previously mentioned, this bot now allows for Google developer verification so that the Google URL-Shortener can still be used. 38 | 39 | 2. The previous method for collecting posts stored them in a dict, and then iterated through that dict. Since dicts are implemented via hash tables, this resulted in posts being sent to twitter out of order to their current reddit ranking. This has been corrected by saving posts from reddit in lists. 40 | 41 | 3. You can now specify what hashtags you would like include at the top of the script. The script tracks characters remaining and accommodates space for whatever ending message you decide to use- so long as you don't go past a character limit of 114. It's best to keep your ending messages or hastages short so you don't crowd out content from reddit. 42 | 43 | 4. An issue with how the script checked for duplicate posts, which could have lead to false positives, was corrected. Previously if the id of a collected post was within the longer id of a new post, it would have been flagged as a duplicate. 44 | 45 | 5. Some smaller error checking features were added, and an issue where the script would be unable to convert certain unicode characters to ascii was corrected (achieved by encoding to unicode). 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /posted_posts.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasoob/Reddit-Twitter-bot/f9af2694c129b4b5817062ab84486cf8f34f6b96/posted_posts.txt -------------------------------------------------------------------------------- /reddit_bot.py: -------------------------------------------------------------------------------- 1 | import praw 2 | import json 3 | import requests 4 | import tweepy 5 | import time 6 | 7 | # Twitter security codes 8 | access_token = 'YOUR ACCESS TOKEN' 9 | access_token_secret = 'YOUR ACCESS TOKEN SECRET' 10 | consumer_key = 'YOUR CONSUMER KEY' 11 | consumer_secret = 'YOUR CONSUMER SECRET' 12 | 13 | # without a proper key, this routine will default to Twitter's t.co shortening method 14 | google_api_key = "YOUR GOOGLE API KEY" 15 | 16 | # Options to customize your bot 17 | subreddit_name = "python" #Replace with your desired subreddit name 18 | tag_string= "#Python #reddit #bot" #Place to put your hastags, etc. Must be <=114 char 19 | num_tweets_before_stopping=20 20 | tweet_delay= 10 #in minutes 21 | 22 | # Core functions begin here 23 | def strip_title(title, tag_len): 24 | char_remaining=140-tag_len-26 # 26 = 24 for link + 2 for the spaces between concatenated strings 25 | if len(title) <= char_remaining: 26 | return title 27 | elif char_remaining >= 3: 28 | return title[:char_remaining-3] + "..." 29 | else: 30 | return "" 31 | 32 | def tweet_creator(subreddit_info): 33 | post_titles = [] 34 | post_links = [] 35 | post_ids = [] 36 | print "[bot] Getting posts from Reddit" 37 | for submission in subreddit_info.get_hot(limit=20): 38 | post_id=submission.id 39 | post_link=submission.url 40 | post_title=strip_title(submission.title, len(tag_string)) 41 | 42 | post_titles.append(post_title) 43 | post_links.append(post_link) 44 | post_ids.append(post_id) 45 | 46 | del post_title, post_link, post_id 47 | return post_titles, post_links, post_ids 48 | 49 | def setup_connection_reddit(subreddit): 50 | print "[bot] setting up connection with Reddit" 51 | r = praw.Reddit('yasoob_python reddit-twitter posting app' 52 | 'monitoring %s' %(subreddit)) 53 | subreddit = r.get_subreddit(subreddit) 54 | return subreddit 55 | 56 | def shorten(url): # Adjusted to include google api key authentication 57 | try: 58 | headers = {'content-type': 'application/json'} 59 | payload = {"longUrl": url} 60 | googl_url = "https://www.googleapis.com/urlshortener/v1/url?key=%s" %(config_dict['google_api_key']) 61 | r = requests.post(googl_url, data=json.dumps(payload), headers=headers) 62 | url = json.loads(r.text)['id'] 63 | print "[bot] Generating short link using goo.gl" 64 | except: 65 | print "[bot] unverified google api key, defaulting to twitter's t.co shortner" 66 | return url 67 | 68 | def duplicate_check(id): 69 | found = 0 70 | with open('posted_posts.txt', 'r') as file: 71 | for line in file.read().splitlines(): 72 | if post_id == line: 73 | found = 1 74 | file.close() 75 | return found 76 | 77 | def add_id_to_file(id): 78 | with open('posted_posts.txt', 'a') as file: 79 | file.write(str(id) + "\n") 80 | file.close() 81 | 82 | def main(): 83 | count=0 84 | if len(tag_string) > 114: 85 | print "[bot] Trailing string of tags is too long, please limit to <= 114 char" 86 | return 87 | while count <= num_tweets_before_stopping: 88 | subreddit = setup_connection_reddit(subreddit_name) 89 | post_titles, post_links, post_ids = tweet_creator(subreddit) 90 | tweeter(post_titles, post_links, post_ids) 91 | print "[bot] waiting until next tweet" 92 | time.sleep(tweet_delay*60) 93 | count+=1 94 | 95 | def tweeter(post_titles, post_links, post_ids): 96 | auth = tweepy.OAuthHandler(consumer_key, consumer_secret) 97 | auth.set_access_token(access_token, access_token_secret) 98 | api = tweepy.API(auth) 99 | index=0 100 | for post_title, post_link, post_id in zip(post_titles, post_links, post_ids): 101 | found = duplicate_check(post_id) 102 | if found == 0: 103 | tweet_content=post_title+" "+shorten(post_link)+" "+tag_string 104 | print "[bot] Posting this link on twitter" 105 | print tweet_content.encode("utf-8") 106 | try: 107 | api.update_status(tweet_content) 108 | except Exception, e: 109 | print "[bot] Error triggered when sending tweet content to twitter:" 110 | try: 111 | print "[Twitter] "+ e.args[0][0]['message'] 112 | except: 113 | print "[bot] Error outside of communication with Twitter" 114 | return 115 | add_id_to_file(post_id) 116 | return 117 | else: 118 | print "[bot] ID for post #%d already collected" %(index) 119 | index+=1 120 | 121 | if __name__ == '__main__': 122 | main() --------------------------------------------------------------------------------