python asyncio 中的 Discord 机器人

Discord bot in python asyncio

我在 python 中写了一个机器人,该机器人的功能是:显示股票价格,设置价格限制,当达到该限制时,向 discord 发送消息。在此阶段,机器人只能监控一个动作。如何让它异步,让它同时监控几只股票,当达到限制时,它发送特定股票到discord 消息,价格已达到标记。

from bs4 import BeautifulSoup
import discord
from discord.ext import commands
from config import settings


bot = commands.Bot(command_prefix = settings['prefix'], help_command=None)

@bot.event
async def on_message(message):
    await bot.process_commands(message)
    channel = message.channel
    co = '{0.content}'.format(message).split()
    tes=co[0]
    if tes=='price':
        yo=co[1]
        print(yo)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0'
        }

        r = requests.get(
            ('https://finance.yahoo.com/quote/') + yo + ('?p=') + yo + ('.tsrc=fin-srch'),
            headers=headers)
        soup = BeautifulSoup(r.text, 'lxml')
        content = soup.find('div', {"class": 'My(6px) Pos(r) smartphone_Mt(6px)'}).find('span').text
        print(content)
        await channel.send(f'{yo} - {content}')
        return content

    elif tes=='limit':
        p=co[1]
        su=co[2]
        price=float(su)

        while True:
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0'
            }
            r = requests.get(
                ('https://finance.yahoo.com/quote/') + p + ('?p=') + p + ('.tsrc=fin-srch'),
                headers=headers)
            soup = BeautifulSoup(r.text, 'lxml')

            content = soup.find('div', {"class": 'My(6px) Pos(r) smartphone_Mt(6px)'}).find('span').text
            con=float(content)
            if price<=con:
                await channel.send("достиг")
                break
            print(content)

        return content

bot.run(settings['token'])

如何使它们异步

要使它们异步,请为此使用库 aiohttp instead of requests, and sadly there is no alternative for beautifulsoup that is async but we can use run_in_executor

您必须进行的更改:

  • 在文件顶部添加一个 import aiohttp(安装 discord.py 时自动安装 aiohttp)
  • 在定义机器人后添加一个 bot.session = aiohttp.ClientSession()(在 bot = commands.Bot... 行之后)
  • 改变
r = requests.get(
            ('https://finance.yahoo.com/quote/') + yo + ('?p=') + yo + ('.tsrc=fin-srch'),
            headers=headers)

async with bot.session.get(
                f'https://finance.yahoo.com/quote/{yo}?p={yo}.tsrc=fin-srch',
                headers=headers
            ) as r:
    # we will also change `r.text` to `await r.text()`

这基本上是使用会话对象,获取网站的原始 html。与请求相同的工作,但 async

  • 现在
soup = BeautifulSoup(r.text, 'lxml')
content = soup.find('div', {"class": 'My(6px) Pos(r) smartphone_Mt(6px)'}).find('span').text

要使其异步,首先将其添加到一个函数中

def scrape(html):
    soup = BeautifulSoup(html, 'lxml')
    content = soup.find('div', {"class": 'My(6px) Pos(r) smartphone_Mt(6px)'}).find('span').text
    return content

这只是将 beautifulsoup 代码包装在一个函数中,该函数采用原始 html 和 returns 所需的内容。没有其他的 现在在您的 on_message,而不是

content = soup.find('div', {"class": 'My(6px) Pos(r) smartphone_Mt(6px)'}).find('span').text

content = await bot.loop.run_in_executor(None, scrape, await r.text())

这将运行 scrape 函数中的代码并将等待 r.text() 传递给它,这是原始的 html。然后在函数中,我们得到原始 html,找到我们的数据并 return 它。这里我们得到 returned 值并将其保存到名为 content

的变量中