Discord.py与线程,RuntimeError:超时上下文管理器应在任务内使用

2024-05-16 21:48:39 发布

您现在位置:Python中文网/ 问答频道 /正文

所以我创建了一个discord机器人,它不断地抓取网页,检查物品是否有库存。当物品有库存时,在聊天室中发送消息。由于刮削是在一个恒定的循环中,我想我应该把它放在一个线程中,每个需要刮削的页面对应一个线程。问题是每个线程都产生相同的错误

RuntimeError: Timeout context manager should be used inside a task

有人知道为什么吗,或者知道我想做什么的更好的方法吗

async def searchPage(input_url):

 currentUrl = input_url
 driver = webdriver.Chrome(options=options, executable_path=DRIVER_PATH)
 driver.get(currentUrl)

 while True:
     try:
         shipIt = driver.find_element_by_css_selector('[data-test="shippingBlock"]')
         await alertUsers(currentUrl)
         await asyncio.sleep(5)
     except NoSuchElementException:
         continue

 #driver.quit()

async def alertUsers(current_input):

 channel = client.get_channel(795513308869296181)
 await channel.send(f'Go buy this: {current_input}')

async def create_threads():

 thread1 = threading.Thread(target=asyncio.run, args=(searchPage("https://www.target.com/p/set-of-2-kid-century-modern-kids-chairs-b-spaces/-/A-81803789?preselect=80929605#lnk=sametab"),))
 thread1.start()
 thread2 = threading.Thread(target=asyncio.run, args=(searchPage("https://www.target.com/p/wrangler-men-s-big-tall-relaxed-fit-jeans-with-flex/-/A-79321830?preselect=52428349#lnk=sametab"),))
 thread2.start()

@client.event
async def on_ready():
 guild = discord.utils.get(client.guilds, name=GUILD)
 print(
     f'{client.user} is connected to the following guild:\n'
     f'{guild.name}(id: {guild.id})'
 )
 await create_threads()


client.run(TOKEN)

Tags: runclientasynciotargetinputgetasyncdef
1条回答
网友
1楼 · 发布于 2024-05-16 21:48:39

有些框架不喜欢在threads中运行,即所有GUI框架都必须在主线程中运行窗口和小部件。它们被称为not thread-safe

您可能也有类似的问题-在thread内部,您不能使用在主线程中创建的async

您应该在新线程中运行searchPage作为正常函数,并将结果发送到主线程,主线程应该向discord发送一些消息。您可以使用全局变量或更好的queue发送结果。主线程应该运行一些函数,定期检查queue并向discord发送消息

Discord有@tasks.loop(second=...)可以定期运行函数


最小工作代码

import discord
from discord.ext import tasks
import os
import time
import queue
import threading
from selenium import webdriver

MY_CHANNEL = 795513308869296181    
     
# queue to communicate with threads
queue = queue.Queue()

client = discord.Client()

#  - normal functions  -

def searchPage(url, queue):
     driver = webdriver.Chrome()
     #driver = webdriver.Chrome(options=options, executable_path=DRIVER_PATH)
    
     while True:
         try:
             driver.get(url)
             ship_it = driver.find_element_by_css_selector('[data-test="shippingBlock"]')
             #print('[DEBUG] queue put:', url)
             queue.put(url)
             time.sleep(5)
         except NoSuchElementException as ex:
             #print('[DEBUG] queue put: not found')
             #queue.put('not found')
             #print('Exception:', ex)
             pass
    
     #driver.quit()

def create_threads():
     urls = [
         "https://www.target.com/p/set-of-2-kid-century-modern-kids-chairs-b-spaces/-/A-81803789?preselect=80929605#lnk=sametab",
         "https://www.target.com/p/wrangler-men-s-big-tall-relaxed-fit-jeans-with-flex/-/A-79321830?preselect=52428349#lnk=sametab",
     ]

     for url in urls:
        t = threading.Thread(target=searchPage, args=(url, queue))
        t.start()     

#  - async functions  -

@tasks.loop(seconds=5)    
async def alert_users():
     #print('[DEBUG] alert_users')   
     if not queue.empty():
         current_input = queue.get()
         channel = client.get_channel(MY_CHANNEL)
         await channel.send(f'Go buy this: {current_input}')
        
@client.event
async def on_ready():     
     create_threads()  
     alert_users.start()  # start `task.loop`

TOKEN = os.getenv('DISCORD_TOKEN')
client.run(TOKEN)

相关问题 更多 >