Как выводить сообщение без остановки?

Как выводить сообщение без остановки?
Проблема в том, что сообщение высылается только один раз и я не могу настроить её на то, чтобы она выводилась с каждым обновлением. Работа идет из Api.hypixel.net, оттуда берутся цены и сам предмет. Всё работает если выводить в командную строку, но когда я отправляю сообщением в Дискорд, оно выводится один раз и не продолжает работать
('/viewauction 27e47ca530964bb692640ebdebdda699 | Item Name: Baby Chick Chicken Skin | Item price: 290,000,000', ' | Second lowest BIN: 300,000,000')
Так же сообщение выводится в скобках, если убрать одну переменную из
flip = f'{"/viewauction " + str(result[0][0]) + " | Item Name: " + str(result[0][1]) + " | Item price: {:,}".format(result[0][2]), " | Second lowest BIN: {:,}".format(result[1])}'

То сообщение выводится без скобок и всё хорошо, но нужны все переменные

Код полностью:

import asyncio
import re
from concurrent.futures import ThreadPoolExecutor
from timeit import default_timer
import time
import traceback2 as traceback
import os

import discord
from discord.ext import tasks, commands
from dotenv import load_dotenv

import pandas as pd
import requests

client = discord.Client()



c = requests.get("https://api.hypixel.net/skyblock/auctions?page=0")
resp = c.json()
now = resp['lastUpdated']
toppage = resp['totalPages']

results = []
prices = {}

# stuff to remove
REFORGES = [" ✦", "⚚ ", " ✪", "✪", "Stiff ", "Lucky ", "Jerry's ", "Dirty ", "Fabled ", "Suspicious ", "Gilded ",
            "Warped ", "Withered ", "Bulky ", "Stellar ", "Heated ", "Ambered ", "Fruitful ", "Magnetic ", "Fleet ",
            "Mithraic ", "Auspicious ", "Refined ", "Headstrong ", "Precise ", "Spiritual ", "Moil ", "Blessed ",
            "Toil ", "Bountiful ", "Candied ", "Submerged ", "Reinforced ", "Cubic ", "Warped ", "Undead ",
            "Ridiculous ", "Necrotic ", "Spiked ", "Jaded ", "Loving ", "Perfect ", "Renowned ", "Giant ", "Empowered ",
            "Ancient ", "Sweet ", "Silky ", "Bloody ", "Shaded ", "Gentle ", "Odd ", "Fast ", "Fair ", "Epic ",
            "Sharp ", "Heroic ", "Spicy ", "Legendary ", "Deadly ", "Fine ", "Grand ", "Hasty ", "Neat ", "Rapid ",
            "Unreal ", "Awkward ", "Rich ", "Clean ", "Fierce ", "Heavy ", "Light ", "Mythic ", "Pure ", "Smart ",
            "Titanic ", "Wise ", "Bizarre ", "Itchy ", "Ominous ", "Pleasant ", "Pretty ", "Shiny ", "Simple ",
            "Strange ", "Vivid ", "Godly ", "Demonic ", "Forceful ", "Hurtful ", "Keen ", "Strong ", "Superior ",
            "Unpleasant ", "Zealous "]

# Constant for the lowest priced item you want to be shown to you; feel free to change this
LOWEST_PRICE = 500000

# Constant to turn on/off desktop notifications
NOTIFY = True

# Constant for the lowest percent difference you want to be shown to you; feel free to change this
LOWEST_MARGIN = 500000

START_TIME = default_timer()


def fetch(session, page):
    global toppage
    base_url = "https://api.hypixel.net/skyblock/auctions?page="
    with session.get(base_url + page) as response:
        # puts response in a dict
        data = response.json()
        toppage = data['totalPages']
        if data['success']:
            toppage = data['totalPages']
            for auction in data['auctions']:
                if not auction['claimed'] and 'bin' in auction and not "Furniture" in auction[
                    "item_lore"]:  # if the auction isn't a) claimed and is b) BIN
                    # removes level if it's a pet, also
                    index = re.sub("\[[^\]]*\]", "", auction['item_name']) + auction['tier']
                    # removes reforges and other yucky characters
                    for reforge in REFORGES: index = index.replace(reforge, "")
                    # if the current item already has a price in the prices map, the price is updated
                    if index in prices:
                        if prices[index][0] > auction['starting_bid']:
                            prices[index][1] = prices[index][0]
                            prices[index][0] = auction['starting_bid']
                        elif prices[index][1] > auction['starting_bid']:
                            prices[index][1] = auction['starting_bid']
                    # otherwise, it's added to the prices map
                    else:
                        prices[index] = [auction['starting_bid'], float("inf")]

                    # if the auction fits in some parameters
                    if prices[index][1] > LOWEST_PRICE and prices[index][1] - prices[index][0] > LOWEST_MARGIN and \
                            auction['start'] + 60000 > now:
                        results.append([auction['uuid'], auction['item_name'], auction['starting_bid'], index])
        return data


async def get_data_asynchronous():
    # puts all the page strings
    pages = [str(x) for x in range(toppage)]
    with ThreadPoolExecutor(max_workers=10) as executor:
        with requests.Session() as session:
            loop = asyncio.get_event_loop()
            START_TIME = default_timer()
            tasks = [
                loop.run_in_executor(
                    executor,
                    fetch,
                    *(session, page)  # Allows us to pass in multiple arguments to `fetch`
                )
                # runs for every page
                for page in pages if int(page) < toppage
            ]
            for response in await asyncio.gather(*tasks):
                pass


def main():
    # Resets variables

    global results, prices, START_TIME
    START_TIME = default_timer()
    results = []
    prices = {}

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    future = asyncio.ensure_future(get_data_asynchronous())
    loop.run_until_complete(future)

    # Makes sure all the results are still up to date
    if len(results): results = [[entry, prices[entry[3]][1]] for entry in results if (
                entry[2] > LOWEST_PRICE and prices[entry[3]][1] != float('inf') and prices[entry[3]][0] == entry[2] and
                prices[entry[3]][1] - prices[entry[3]][0] > LOWEST_MARGIN)]

    if len(results):  # if there's results to print

        df = pd.DataFrame(['/viewauction ' + str(max(results, key=lambda entry: entry[1])[0][0])])
        df.to_clipboard(index=False,
                        header=False)  # copies most valuable auction to clipboard (usually just the only auction cuz very uncommon for there to be multiple
        print(df)

        done = default_timer() - START_TIME
        for result in results:
            print("Auction UUID: /viewauction " + str(result[0][0]) + " | Item Name: " + str(result[0][1]) + " | Item price: {:,}".format(result[0][2])," | Second lowest BIN: {:,}".format(result[1]) + " | Time to refresh AH: " + str(round(done, 2)))
        print("\nLooking for auctions...")


print("Looking for auctions...")
main()



@client.event
async def on_ready():
    print('We have logged in as {0.user}'.format(client))
        # make a channel variable first
    channel = client.get_channel('channel')  # channel id
        # if you want to use the message later eg. to delete it you can make a variable too
    for result in results:
        flip = f'{"/viewauction " + str(result[0][0]) + " | Item Name: " + str(result[0][1]) + " | Item price: {:,}".format(result[0][2]), " | Second lowest BIN: {:,}".format(result[1])}'
        await channel.send(f'{flip}')
# is a variable
client.run('token')

def dostuff():
    global now, toppage

    # if 60 seconds have passed since the last update
    if time.time() * 1000 > now + 60000:
        prevnow = now
        now = float('inf')
        c = requests.get("https://api.hypixel.net/skyblock/auctions?page=0").json()
        if c['lastUpdated'] != prevnow:
            now = c['lastUpdated']
            toppage = c['totalPages']
            main()
        else:
            now = prevnow
    time.sleep(0.25)


while True:
    on_ready()
    dostuff();


Изначально думал что постоянный вывод сообщения должен работать в коде:
while True:
    on_ready()
    dostuff();

Но выводится лишь один раз и перестает сканироваться код и естественно оно не продолжает отправлять сообщения.
Только при присоединения Discord оно перестает сканировать
  • Вопрос задан
  • 74 просмотра
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Ну во-первых ты творишь какой-то колхоз. discord.py тащит как зависимость асинхронную aiohttp, а ты сначала используешь синхронный requests, а потом заворачиваешь его в асинхрон через ThreadPool, потом обратно заворачиваешь в синхронный код в main(), а потом этот main() хочешь использовать вместе с асинхронным кодом discord.py. Жесть.
Вот не проще осилить изначально асинхронную библиотеку, которую и так и так придётся использовать?

Далее, что за бредятина с while? Что, по-твоему, должен делать вызов on_ready() в цикле? Что еще за точки с запятыми в питоне?
Ты делаешь чисто синхронный бесконечный цикл, естественно этот цикл не даёт асинхронному коду исполняться.

Ну и до кучи зачем-то используешь discord.Client вместо discord.Bot.

Даже базового знания того, как работает асинхронность в питоне, достаточно, чтобы набросать код вида:
import asyncio
import aiohttp
import discord
from discord.ext import commands
client = commands.Bot(intents = discord.Intents.default())

async def fetch():
    return ... # тут вытаскиваем данные с сайта через aiohttp и возвращаем в удобном нам виде

async def display(results):
    global client
    pass  # тут выводишь результаты в дискорд, используя объект client

async def cycle():
    while True:
        res = await fetch()  # обработку ошибок допиши сам
        await display(res)
        await asyncio.sleep(300)  # задержка в секундах

cycle_task = None
@client.ready
async def on_ready():
    global cycle_task
    if cycle_task is None:  # событие ready может отрабатывать несколько раз, нам нужен только один.
        cycle_task = asyncio.get_event_loop().create_task(cycle())
    pass  # тут делаешь что тебе еще нужно по запуску бота

# когда надо будет остановить цикл, вызови cycle_task.cancel()
bot.run(TOKEN)  # запускаешь бота
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы