r/redditdev•
SloPr0

Getting only ~100 requests every 10 minute reset instead of the expected 600

Reddit API

Hello, after Pushshift got axed a couple of weeks ago, I started messing around with PRAW to essentially create a personal replacement for what I primarily used that for - seeing all the recent comments which contained certain keywords across reddit.

Initially, I tried the often recommended reddit.subreddit('all').stream.comments() to fetch comments and print them if they matched a filter, which worked quite well... but I didn't like how it would miss many comments at peak times.

I then discovered that I could simply fetch comments by their ID using reddit.info([commentID1, commentID2...]), so I switched over to initially fetching the latest comment using reddit.subreddit('all').comments() on startup, and with its ID then repeatedly polling reddit.info() with sequential comment IDs from that one onward, 100 at a time, with the requests being spaced out by 1-1.2s, so within the specified rate limit of 1 req/sec. This worked splendidly and didn't skip any comments at all, albeit with the downside being that it was slightly falling behind live (not too badly though), but it was acceptable.

However, last night, all my requests have seemingly started being throttled, and now printing PRAW's reddit.auth.limits is showing that every 10 minutes, the remaining request count is only being reset to ~95 (so, 1 request every ~6 seconds) instead of the 600 it's supposed to be, leading to PRAW forcefully spacing every call out by 10 seconds, thus now lagging behind a much-less-acceptable thousands of comments per call, instead of the ~dozens it was before.

Even after shutting off the script for the night and trying again in the morning, the same thing persists; immediately after the first request on start up: used: 1, remaining: 95, reset_timestamp: ~600s from now. So yeah, any clues as to what's going on and how I could resolve this would be much appreciated.

#Edit:

This seems to be resolved now thanks to the replies below. Turns out you need to pass username and password to praw as well, not just client_id and secret (which the guides I used missed).

Posted May 12, 2023, 10:46 AM UTC · edited

725
archy_bold•

It’s unsurprising you’re being limited, you’re reading every single comment to get a handful. That’s a total abuse of the API and I’m surprised you haven’t been banned completely. Instead of trying to read literally everything, why don’t you just use the search function to get only the comments you’re actually interested in seeing. From Reddit’s perspective it looks like you’re trying to clone their database.

2
SloPr0OP•

Yes, the ideal way would absolutely be to just search for comments directly via reddit instead of manually filtering.

However, it is my understanding (feel free to correct me if I am wrong, I'm basing it off research I did over the past few days) that reddit doesn't support searching for comments, only submissions. Even the "Remind Me" bot, which similarly used to comb Pushshift for comments mentioning its trigger keyword, is currently not working due to the same limitation.

I also don't really see how this is "total abuse of the API" - there is no real functional difference between this and .subreddit().stream.comments() which has been the recommended method pretty much everywhere; both are repeatedly calling an endpoint to fetch comments in batches, I'm just trying to poll /info instead of /comments.

Either way, I'm completely fine with abandoning this method if needed and going back to using stream.comments() instead, but mainly I'd just like to know how long until the rate limit goes back to normal, or if I'm just going to be gimped indefinitely :\

2
archy_bold•

Ha, the reddit API allows search on user, subreddit, or submission but not comments. It's clearly a gap in the API that's existed for a while, despite existing on the front end.

Pushshift being banned was obviously about stopping API users stripping and storing Reddit historical data wholesale. I imagine the reason you've been restricted is for the exact same reason, even if you're not doing that. From the perspective of Reddit, you're circumventing the comments stream to fill the gaps.

I guess the only other option is web scraping the search page, but that's definitely the sort of thing that won't be allowed by Reddit.

2
SloPr0OP•

Yeah, I guess the gap-filled subreddit('all').stream.comments() is gonna have to be the way to go. I'm just hoping my rate limit gets restored at some point in the near future if I stop using it for a while, as right now even that's being limited too.

2
Watchful1RemindMeBot & UpdateMeBot•

That's very odd and somewhat concerning. As long as you are logged in you should always get the full 600 every 600 seconds. You are logged in right? What user agent are you using? Are you running this from your local computer or a server somewhere?

I'm hoping the reason is that you are conflicting with some other client sharing your IP, which is possible on a shared server host.

1
SloPr0OP•

Yeah, that's why I am confused too. I'd understand if I was hammering it, but as is it should definitely be below the specified limit.

The IP shouldn't be shared, as I'm running this on a dedicated Linux server that I use for other services, and the user agent I provide is linux:com.slopro.prawtest:v1.0.0 (by [u/SloPr0](/u/SloPr0)) (since, well, it is just a test script), along with the appropriate client_id and client_secret.

1
Watchful1RemindMeBot & UpdateMeBot•

What other services do you run on the server? Anything interacting with the reddit api?

Do you see the same behavior if you run, using the same account and user agent, locally?

Can you double check you are logged in by checking the output of reddit.user.me()?

Also the throttling for 10 seconds by PRAW is a bug. It should be spacing out evenly, every 6 seconds in this case. When I wrote that code I didn't anticipate this case and haven't gotten around to fixing it yet.

1
SloPr0OP•

What other services do you run on the server? Anything interacting with the reddit api?

No, nothing to do with reddit.

Do you see the same behavior if you run, using the same account and user agent, locally?

Yes.

Also, if it helps, every time I restart the script it's always saying used: 1, remaining: 95, even if the time is not up yet (however the reset_timestamp remains the same within 1s (only decimals change)).

e.g.:

(2023-05-12 19:24:05) Script started

(2023-05-12 19:24:06) 1.157s, 1 comments -> used: 1, rem: 95.0, reset in: 354s 1683912601.8171334

(2023-05-12 19:24:17) 10.407s, 100 comments -> used: 2, rem: 94.0, reset in: 343s 1683912601.2350185

^C(2023-05-12 19:24:18) Keyboard interrupt received. Exiting...

python3 test.py

(2023-05-12 19:24:40) Script started

(2023-05-12 19:24:41) 1.203s, 1 comments -> used: 1, rem: 95.0, reset in: 319s 1683912601.9424226 <-- notice it's back to 1/95

As for reddit.user.me(), it outputs None. Are you required to pass the account password as well to the reddit constructor? The simple guides I checked all just provided client_id and client_secret.

1
Watchful1RemindMeBot & UpdateMeBot•

Yes that means you aren't logged in. Use the PRAW docs here. You need either username, password, client id, client secret, or get a refresh token and use that plus client id and client secret.

I personally use the praw.ini file. You can store all the values in there, then just pass the username into the constructor instead of dealing with all the secrets in your script yourself.

2
Tipe17311•

my D*** is still in the mud on this one. sometimes it only takes 1 second to pull from the api and other times it take's 10 seconds.

heres the code:

from flask import Flask, render_template, request

import datetime

import praw

from operator import itemgetter

import re

import pytz

import nltk

import calendar

from collections import Counter

import base64

import io

from wordcloud import WordCloud

import time

client_id =

client_secret =

user_agent =

reddit = praw.Reddit(client_id=client_id, client_secret=client_secret, user_agent=user_agent)

app = Flask(__name__)

word_regex = re.compile(r'\b\w+\b')

u/app.route('/')

def index():

return render_template('index.html')

u/app.route('/karma_ranking', methods=['POST'])

def karma_ranking():

start_time = time.time()

subreddit_name = request.form['subreddit_name']

num_posts = 25

user_karma_dict = {}

words = []

posts_per_hour = {i: 0 for i in range(24)}

posts_per_day = {day: 0 for day in list(calendar.day_name)}

flairs_count = Counter()

reddit_start = time.time()

posts = reddit.subreddit(subreddit_name).top('week', limit=num_posts)

reddit_end = time.time()

print(f'Time taken to fetch posts: {reddit_end - reddit_start}')

processing_start = time.time()

for post in posts:

author_start = time.time()

if post.author is not None:

username = post.author.name

karma = post.author.link_karma + post.author.comment_karma

user_karma_dict[username] = karma

author_end = time.time()

print(f'Time taken to process author info: {author_end - author_start}')

title_start = time.time()

title_words = word_regex.findall(post.title.lower())

words.extend(title_words)

title_end = time.time()

print(f'Time taken to process title words: {title_end - title_start}')

time_start = time.time()

time_utc = datetime.datetime.fromtimestamp(post.created_utc, tz=pytz.UTC)

posts_per_hour[time_utc.hour] += 1

day_of_week = time_utc.strftime('%A')

posts_per_day[day_of_week] += 1

time_end = time.time()

print(f'Time taken to process time info: {time_end - time_start}')

flair_start = time.time()

if post.link_flair_text:

flairs_count[post.link_flair_text] += 1

flair_end = time.time()

print(f'Time taken to process flair info: {flair_end - flair_start}')

processing_end = time.time()

print(f'Total time taken to process posts: {processing_end - processing_start}')

wordcloud_start = time.time()

sorted_user_karma_list = sorted(user_karma_dict.items(), key=lambda item: item[1], reverse=True)

posts_per_hour = sorted(posts_per_hour.items())

word_freq = Counter(w for w in words if nltk.pos_tag([w])[0][1] not in ['PRP', 'IN'] and not w.isdigit() and len(w) > 1 and w not in ['your', 'are', '+', 'the', 'to', 'and', 'is','my','can','their','an',])

wordcloud = WordCloud(width=800, height=400).generate_from_frequencies(word_freq)

img = io.BytesIO()

wordcloud.to_image().save(img, 'PNG')

img.seek(0)

wordcloud_img = base64.b64encode(img.getvalue()).decode()

wordcloud_end = time.time()

print(f'Time taken to generate word cloud: {wordcloud_end - wordcloud_start}')

end_time = time.time()

print(f'Total execution time: {end_time - start_time}')

return render_template(

'karma_ranking.html',

subreddit_name=subreddit_name,

user_karma_list=sorted_user_karma_list,

wordcloud_img=wordcloud_img,

word_freq=word_freq.most_common(),

posts_per_hour=posts_per_hour,

posts_per_day=posts_per_day,

flairs_count=flairs_count.most_common()

)

if __name__ == "__main__":

app.run(debug=True)

terminal snippet:

Time taken to process author info: 10.08719778060913

Time taken to process title words: 0.0

Time taken to process time info: 0.0

Time taken to process flair info: 0.0

Time taken to process author info: 10.08174467086792

Time taken to process title words: 0.0

Time taken to process time info: 0.000997304916381836

Time taken to process flair info: 0.0

Total time taken to process posts: 252.787335395813

Time taken to generate word cloud: 0.7410187721252441

Total execution time: 253.53034853935242

1
SloPr0OP•

Like I said in my edit, try to also provide the reddit account's username and password to PRAW's constructor. That solved all the issues I was having with the rate limiting.

So tweak

reddit = praw.Reddit(client_id=xxxxx, client_secret=xxxxx, user_agent=xxxxx)

to

reddit = praw.Reddit(client_id=xxxxx, client_secret=xxxxx, user_agent=xxxxx, username=xxxxxx, password=xxxxxx)

1
Tipe17311•

I did and switched it to a script instead of an app and it works good enough, about 1 second per pull or less.

i wanted to turn this into a website/app though so its like wtf...

1