Search code examples
pythondiscorddiscord.py

How to solve - discord.http: We are being rate limited. Responded with 429


I am creating a bot that displays Bitcoin statistics. The bot changes its activity to Bitcoin statistics every 3 seconds. But at some point the bot stops every time without error, I restart the bot and I get an error discord.http: We are being rate limited. Responded with 429. What to do, how do I need to redo the code?

import requests_html
import time
import discord
from discord.ext import commands
from discord.utils import get
from discord.ext import commands, tasks
import asyncio

intents = discord.Intents.default()
intents.message_content = True
intents.members = True
bot = commands.Bot(command_prefix='.', intents=intents)

Count = 0

@bot.command()
async def crypto_statistic(ctx):
    while True:
        global Count

        await bot.wait_until_ready()

        session = requests_html.HTMLSession()
        r = session.get('https://www.coingecko.com/en/coins/bitcoin') #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        ListOfStatistic = []

        #Цена
        for item in r.html.xpath('/html/body/div[5]/div[5]/div[1]/div/div[1]/div[3]/div/div[1]/span[1]/span'):
            Price = item.text

        #Процент за 1 час
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[1]/span'):
            ListOfStatistic.append("1h: " + item.text)

        #Процент за 24 часа
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[2]/span'):
            h24 = item.text
            ListOfStatistic.append("24h: " + item.text)

        #Процент за 7 дней
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/span'):
            ListOfStatistic.append("7d: " + item.text)

        #Процент за 30 дней
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[5]/span'):
            ListOfStatistic.append("30d: " + item.text)

        #Процент за год
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[6]/span'):
            ListOfStatistic.append("1y: " + item.text)

        #Лоу за 24 часа
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[3]/div[2]/div[1]/table/tbody/tr[2]/td/span/span/span[1]'):
            ListOfStatistic.append("24h Low: " + item.text)

        #Макс за 24 часа
        for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[3]/div[2]/div[1]/table/tbody/tr[2]/td/span/span/span[2]'):
            ListOfStatistic.append("24h High: " + item.text)

        guild = discord.utils.get(bot.guilds, name="тесты") #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        member = guild.get_member(1066093484890656951) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        if float(h24[:-1]) >= 0:
            await member.edit(nick = Price + " (↗)")
        else:
            await member.edit(nick = Price + " (↘)")

        if Count == 6:
            await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name = ListOfStatistic[Count]))
            print(1)
            Count = 0
            await asyncio.sleep(3)
        else:
            await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name = ListOfStatistic[Count]))
            print(2)
            Count += 1
            await asyncio.sleep(3)

@bot.event
async def on_ready():
    await crypto_statistic(bot.get_context)

if __name__ == "__main__":
    bot.run('MyTokenHere') #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

I tried many ways, I also looped this command through @tasks.loop and it didn't work. Some ways helped, but then my stats in bot activity which should go in that order: 1h, 24h, 7d, 30d, 1y..., went in the same order but some stats were just missing and not displayed in bot activity!


Solution

  • The HTTP status 429 means Too many requests, as you can see here. The Discord API has a limit to the number of requests you can make in a given time. A smart thing you can do is to intercept the status code of the response, and whether it's 429 then you do a sleep() and then redo the request!

    Like so (this is a pseudo-code):

    request_url = ""
    request_headers = {}
    response = discord_requests.get(url, headers)
    if response.status_code == "429"
        sleep(5)
        response = discord_requests.get(url, headers)
    

    Note that this isn't the best practice. the best practice is to know the exact amount of requests that the API can handle, calculate how many requests your script can do in that time and put a sleep()

    I don't precisely know how to get the status code from the request, but through debug it should be pretty simple to understand!

    Indeed, I had to do something exactly like this for a data-import script, using requests library.