在 Python 3.5 中使用 aiohttp 获取多个 url

Posted

技术标签:

【中文标题】在 Python 3.5 中使用 aiohttp 获取多个 url【英文标题】:Fetching multiple urls with aiohttp in Python 3.5 【发布时间】:2016-06-23 03:07:10 【问题描述】:

自从 Python 3.5 引入 async with 以来,docs 中为 aiohttp 推荐的语法已经改变。现在获取他们建议的单个网址:

import aiohttp
import asyncio

async def fetch(session, url):
    with aiohttp.Timeout(10):
        async with session.get(url) as response:
            return await response.text()

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    with aiohttp.ClientSession(loop=loop) as session:
        html = loop.run_until_complete(
            fetch(session, 'http://python.org'))
        print(html)

如何修改它以获取一组 url 而不是一个 url?

在旧的asyncio 示例中,您将设置一个任务列表,例如

    tasks = [
            fetch(session, 'http://cnn.com'),
            fetch(session, 'http://google.com'),
            fetch(session, 'http://twitter.com')
            ]

我尝试将这样的列表与上述方法结合起来,但失败了。

【问题讨论】:

你能解释一下你的失败吗? @AndrewSvetlov 很高兴收到您的来信。我的意思是我不明白该怎么做。当我定义一个任务列表然后使用results = loop.run_until_complete(tasks) 时,我得到一个运行时错误。 async with 是一个新功能,文献很少,如果aiohttp 文档显示了一个抓取多个 url 的示例,那么对于学习使用它的人来说会非常方便。图书馆看起来很棒,只需要一点手就可以开始。谢谢! 【参考方案1】:

对于并行执行,您需要asyncio.Task

我已将您的示例转换为从多个来源获取并发数据:

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        if response.status != 200:
            response.raise_for_status()
        return await response.text()

async def fetch_all(session, urls):
    tasks = []
    for url in urls:
        task = asyncio.create_task(fetch(session, url))
        tasks.append(task)
    results = await asyncio.gather(*tasks)
    return results

async def main():    
    urls = ['http://cnn.com',
            'http://google.com',
            'http://twitter.com']
    async with aiohttp.ClientSession() as session:
        htmls = await fetch_all(session, urls)
        print(htmls)

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

【讨论】:

感谢一百万!接受您的回答,但是... 1. 括号的位置仍然有错字。如果你不介意我会编辑它。 2. 在我看来,我想打印print(html) 行欺骗的实际结果,而您实际上需要print('\n'.join(list((str(some_task._result) for some_tuple in html for some_task in some_tuple)))) 之类的东西,也许可以将其添加到答案中? 3. 这看起来真的很有用,我建议在阅读文档中添加类似的内容。再次感谢! :) 安德鲁,我可以在哪里进行像if response.status == 200 这样的测试?如果一个 url 不存在,脚本会中断,我不明白在哪里检查 async with session.get(url) as response: return await response.text() 中的响应 感谢之前留下评论的其他人。我已经开始new question 澄清这一点。 aiohttp.ClientSession(loop=loop) 不再是有效的语法我收到错误:Use async with instead 请您更新答案以反映更改 asyncio.create_task 部分不是必需的。任务是从 3.7 中的协程创建的。

以上是关于在 Python 3.5 中使用 aiohttp 获取多个 url的主要内容,如果未能解决你的问题,请参考以下文章

使用python-aiohttp爬取今日头条

Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

python3下安装aiohttp遇到过的那些坑

Python aiohttp 库是否值得学?那必须要掌握呀

Python aiohttp 库是否值得学?那必须要掌握呀

了解python socket io / aiohttp服务器中的异步等待