|
| 1 | +import urllib |
| 2 | +import urllib2 |
| 3 | +import simplejson |
| 4 | +import cookielib |
| 5 | + |
| 6 | +DEFAULT_CONTENT_LIMIT = 25 |
| 7 | + |
| 8 | +REDDIT_USER_AGENT = { 'User-agent': 'Mozilla/4.0 (compatible; MSIE5.5; Windows NT' } |
| 9 | +REDDIT_URL = "http://www.reddit.com/" |
| 10 | +REDDIT_LOGIN_URL = "http://www.reddit.com/api/login" |
| 11 | +REDDIT_VOTE_URL = "http://www.reddit.com/api/vote" |
| 12 | + |
| 13 | +REDDITOR_ABOUT_PAGE = "http://www.reddit.com/user/%s/about" |
| 14 | +REDDITOR_ABOUT_FIELDS = ['comment_karma', 'created', 'created_utc', 'has_mail', 'has_mod_mail', 'id', 'is_mod', 'link_karma', 'name'] |
| 15 | +SUBREDDIT_SECTIONS = ['hot', 'new', 'controversial', 'top'] |
| 16 | + |
| 17 | + |
| 18 | +class Reddit: |
| 19 | + """A class for a reddit session.""" |
| 20 | + def __init__(self): |
| 21 | + """Initialize all of the tools we need.""" |
| 22 | + # Make these simpler to access |
| 23 | + self.Request = urllib2.Request |
| 24 | + self.urlopen = urllib2.urlopen |
| 25 | + |
| 26 | + # Set cookies |
| 27 | + self.cookie_jar = cookielib.CookieJar() |
| 28 | + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie_jar)) |
| 29 | + urllib2.install_opener(opener) |
| 30 | + |
| 31 | + # Set logged in user to None |
| 32 | + self.user = None |
| 33 | + |
| 34 | + def get_page(self, page_url, params=None, url_data=None): |
| 35 | + """Given a page url and a dict of params, return the page JSON.""" |
| 36 | + # Add .JSON to the end of the url |
| 37 | + page_url += ".json" |
| 38 | + if url_data is not None: |
| 39 | + page_url += "?"+urllib.urlencode(url_data) |
| 40 | + |
| 41 | + # Encode the params and then create the request. |
| 42 | + encoded_params = None |
| 43 | + if params is not None: |
| 44 | + encoded_params = urllib.urlencode(params) |
| 45 | + request = self.Request(page_url, encoded_params, REDDIT_USER_AGENT) |
| 46 | + |
| 47 | + # Get the data |
| 48 | + json_data = self.urlopen(request).read() |
| 49 | + data = simplejson.loads(json_data) |
| 50 | + |
| 51 | + return data |
| 52 | + |
| 53 | + def get_user(self, user_name): |
| 54 | + return Redditor(user_name, self) |
| 55 | + def get_subreddit(self, subreddit_name): |
| 56 | + return Subreddit(subreddit_name, self) |
| 57 | + |
| 58 | + def get_content(self, page_url, limit=DEFAULT_CONTENT_LIMIT, url_data=None): |
| 59 | + content = [] |
| 60 | + after = None |
| 61 | + |
| 62 | + while len(content) < limit: |
| 63 | + if after is not None: |
| 64 | + data = {"after":after} |
| 65 | + if url_data is not None: |
| 66 | + data.extend(url_data) |
| 67 | + page_data = self.get_page(page_url, url_data=data) |
| 68 | + else: |
| 69 | + page_data = self.get_page(page_url, url_data=url_data) |
| 70 | + |
| 71 | + if page_data.get('data') is None: |
| 72 | + break |
| 73 | + |
| 74 | + data = page_data.get('data') |
| 75 | + |
| 76 | + children = map(lambda x: x.get('data'), data.get('children')) |
| 77 | + content.extend(children) |
| 78 | + after = data.get('after') |
| 79 | + |
| 80 | + if after is None: |
| 81 | + break |
| 82 | + |
| 83 | + content = content[:limit] |
| 84 | + |
| 85 | + return content |
| 86 | + def login(self, user, password): |
| 87 | + self.user = user |
| 88 | + |
| 89 | + params = urllib.urlencode({ |
| 90 | + 'id' : '#login_login-main', |
| 91 | + 'op' : 'login-main', |
| 92 | + 'passwd' : password, |
| 93 | + 'user' : user |
| 94 | + }) |
| 95 | + req = self.Request(REDDIT_LOGIN_URL, params, REDDIT_USER_AGENT) |
| 96 | + return self.urlopen(req).read() |
| 97 | + def vote(self, content_id, direction=0, subreddit_name=""): |
| 98 | + params = urllib.urlencode({ |
| 99 | + 'id' : content_id, |
| 100 | + 'dir' : direction, |
| 101 | + 'r' : subreddit_name |
| 102 | + }) |
| 103 | + req = self.Request(REDDIT_VOTE_URL, params, REDDIT_USER_AGENT) |
| 104 | + return self.urlopen(req).read() |
| 105 | + |
| 106 | +class Redditor: |
| 107 | + """A class for Redditor methods.""" |
| 108 | + def __init__(self, user_name, reddit_session): |
| 109 | + self.user_name = user_name |
| 110 | + self.ABOUT_URL = REDDITOR_ABOUT_PAGE % self.user_name |
| 111 | + self.reddit_session = reddit_session |
| 112 | + |
| 113 | + def get_about_attribute(self, attribute): |
| 114 | + data = self.reddit_session.get_page(self.ABOUT_URL) |
| 115 | + return data['data'].get(attribute) |
| 116 | + |
| 117 | +# Add getters for Redditor about fields |
| 118 | +for user_attribute in REDDITOR_ABOUT_FIELDS: |
| 119 | + func = lambda self, attribute=user_attribute: self.get_about_attribute(attribute) |
| 120 | + setattr(Redditor, 'get_'+user_attribute, func) |
| 121 | + |
| 122 | +class Subreddit: |
| 123 | + def __init__(self, subreddit_name, reddit_session): |
| 124 | + self.name = subreddit_name |
| 125 | + self.url = REDDIT_URL + "r/" + self.name |
| 126 | + self.reddit_session = reddit_session |
| 127 | + def get_top(self, time="day", limit=DEFAULT_CONTENT_LIMIT): |
| 128 | + top_url = self.url + "/top" |
| 129 | + return self.reddit_session.get_content(top_url, limit=limit, url_data={"t":time}) |
| 130 | + def get_controversial(self, time="day", limit=DEFAULT_CONTENT_LIMIT): |
| 131 | + controversial_url = self.url + "/controversial" |
| 132 | + return self.reddit_session.get_content(top_url, limit=limit, url_data={"t":time}) |
| 133 | + def get_new(self, sort="rising", limit=DEFAULT_CONTENT_LIMIT): |
| 134 | + new_url = self.url + "/new" |
| 135 | + return self.reddit_session.get_content(top_url, limit=limit, url_data={"sort":sort}) |
| 136 | + def get_hot(self, limit=DEFAULT_CONTENT_LIMIT): |
| 137 | + return self.reddit_session.get_content(self.url, limit=limit) |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | + |
| 146 | + |
0 commit comments