首页 > 解决方案 > Asyncio aiohttp 从 URL 列表中填充 HTML 列表

问题描述

我正在尝试从一个URL 异步获取一个listHTML 源代码,但是我得到了 2 个异常:listasyncioaiohttp

  1. TypeError('An asyncio.Future, a coroutine or an awaitable is ' TypeError: An asyncio.Future, a coroutine or an awaitable is required Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000001C92141F310>
  2. raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed

这是我的代码:

import asyncio
import aiohttpasync 

def main():
    tasks = []
    html_list = []
    async with aiohttp.ClientSession() as session:
        for url in ['http://www.apple.com', 'http://www.google.cl']:
            async with session.get(url) as resp:
                tasks.append(html_list.append(await resp.read()))
        print(html_list[0])
        print(html_list[1])
        await(asyncio.wait(tasks))

if __name__ == '__main__':
    asyncio.run(main())

这段代码会在我得到上述异常后立即打印html 代码。['http://www.apple.com', 'http://www.google.cl']

标签: pythonasynchronousweb-crawlerpython-asyncioaiohttp

解决方案


您的示例有一些不太正确的地方:

  1. 你没有同时运行任何东西。当你await resp.read()在你的 for 循环中时,这会阻塞,main直到结果返回。也许这就是您想要的,但您需要使用它asyncio.create_task来同时运行您的请求。

  2. 正如所指出的,由于task第一点,您根本不需要数组。你可以追加到html_list.

  3. 您不需要调用asynio.wait,因为此时您没有等待任何任务或协程。

您可以通过您在评论中所做的事情来解决您的直接问题,但同时运行的版本如下所示:

import asyncio
import aiohttp

async def read_url(session, url):
    async with session.get(url) as resp:
        return await resp.read()


async def main():
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in ['http://www.apple.com', 'http://www.google.cl']:
            tasks.append(asyncio.create_task(read_url(session, url)))
        html_list = await asyncio.gather(*tasks)
        print(html_list[0])
        print(html_list[1])

if __name__ == '__main__':
    asyncio.run(main())

在这里,我们定义了一个协程read_url,它获取单个 url 的内容。然后在循环中,您创建一个用于读取 url 的任务并将其附加到tasks列表中。然后你使用asyncio.gather- 这将等待所有任务同时完成。

如所写,我无法重现您的RuntimeError: Event loop is closed错误。


推荐阅读