【问题标题】:Discord.py: Can't figure out how to use aiohttp in place of requests for this use caseDiscord.py:无法弄清楚如何使用 aiohttp 代替此用例的请求
【发布时间】:2020-09-13 05:56:53
【问题描述】:

我的原始代码(使用了requests 库):

sess = requests.session()
req = sess.get(i) #i is a url
soup = BeautifulSoup(req.content, 'html.parser')
link = soup.find('a')['href']
with sess.get(link, stream=True) as req2:
    with open(os.path.join('C:\\save\\location', "download.txt"), "wb") as x_file:
        shutil.copyfileobj(req2.raw, x_file)

这段代码的作用:

  1. 在 url i 处获取页面
  2. 使用bs4在所述页面(它是一个文本文件)上找到特定的下载链接link
  3. 该网站使用会话 cookie,因此我使用来自 requestssessions 来保存我的 cookie 从一个请求到下一个请求,以便它可以下载文件。
  4. 使用shutil将文本文件写入我的设备中提到的目录。

就代码的工作而言,没问题。该文件已下载,我在所需文件夹中有名为 download.txt 的所需文件。

但是,当我尝试在async 函数中将其用作discord.py 机器人的一部分时,就会出现问题。代码仍然做了它需要做的事情但是:当它得到多个命令时,它会一个接一个地执行它们,这显然是不可取的。我从 Stack Overflow 本身发现这是因为在 async 函数中使用 requests 会导致整个代码阻塞,从而导致我观察到的情况。因此,我尝试使用aiohttp,而不是requests,它显然与async 函数配合得很好。我已经设法用aiohttp 替换了我对requests 的大部分使用,它似乎运行良好,但是我似乎无法找出正确的语法来做我上面所做的事情(下载文本文件同时使用会话 cookie,bs4shutil

在使用aiohttp 时,我将如何使用 bs4 保留会话 cookie 并将文件写入我的设备?

编辑 原始链接和文件属于个人性质,但如果您想要一个样本进行测试,这应该以类似的方式工作:

import requests
from bs4 import BeautifulSoup
import os
import shutil

sess = requests.session()
req = sess.get('https://www.gutenberg.org/ebooks/2600')
soup = BeautifulSoup(req.content, 'html.parser')
link = soup.find('a', text="EPUB (no images)")['href']
link="https://www.gutenberg.org"+link
with sess.get(link, stream=True) as req2:
    with open(os.path.join('C:\\save\\location', "war.epub"), "wb") as x_file:
        shutil.copyfileobj(req2.raw, x_file)

这会在您想要的目录中创建一个名为 war.epub 的文件,其中包含从 Gutenberg 项目下载的战争与和平的 epub 版本。我将如何使用 aiohttp 而不是请求来实现这一点?

【问题讨论】:

  • 你能提供一个我们可以用于测试目的的 URL 吗?或者,您使用shutil 保存的内容
  • @Benjin 啊,我不能真正提供网址,因为它是一种个人网站,但我要保存的细节是:它是一个基本的 .txt 文件,有几个字符在里面。
  • @Benjin 实际上,现在我找到了一个公共 url,我的代码似乎以类似的方式工作。已更新问题。也许现在你可以看看?提前致谢!

标签: python-3.x python-requests discord.py aiohttp


【解决方案1】:

请注意,我已包含 aiofile 以异步写入文件,因为大文件会导致代码阻塞。

import aiohttp
import asyncio
from bs4 import BeautifulSoup
import os
from aiofile import AIOFile

async def write_file():
    sess = aiohttp.ClientSession()
    req = await sess.get('https://www.gutenberg.org/ebooks/2600')

    soup = BeautifulSoup(await req.read(), 'html.parser')
    link = soup.find('a', text='EPUB (no images)')['href']
    link = 'https://www.gutenberg.org' + link

    req2 = await sess.get(link)

    async with AIOFile(os.path.join('C:\\save\\location', 'war.epub'), 'wb') as x_file:
        await x_file.write(await req2.read())

    await sess.close()


loop = asyncio.get_event_loop()
loop.run_until_complete(write_file())

【讨论】:

  • ModuleNotFoundError: No module named 'aiofile' :( 我必须先 pip install 吗?哦,如果这很重要,我使用的是 Python 3.8
  • 是的,你需要使用pip安装aiofile
  • 嗨,我做到了。但是1)在我的设备和python版本上,它说模块是aiofiles,而不是aiofile,现在给出这个错误ImportError: cannot import name 'AIOFile' from 'aiofiles'
  • 这很奇怪,因为我在网上查了aiofile,所有例子都使用from aiofile import AIOFile
  • 当我将它用作单独的脚本时,它工作得很好,但是当我将它用作我的 discord.py 机器人的 on_message 事件的一部分时,它给出了一些错误:RuntimeError: This event loop is already running for这个:loop.run_until_complete(write_file())。然后还有几个:RuntimeWarning: coroutine 'on_message.<locals>.write_file' was never awaited pass RuntimeWarning: Enable tracemalloc to get the object allocation traceback
猜你喜欢
  • 2017-05-08
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
相关资源
最近更新 更多