对多个 HTTP 请求进行异步状态检查

问题描述 投票:0回答:2

我有一个列表,其中包含数千个指向远程服务器上的图像/视频的 URL。比如:

urls = ['https://foo.bar/baz.jpeg', 'https://foo.bar/jaz.mp4', ...]

通过获取这些 URL,某些响应会显示为 404 Not Found,这没关系,因为服务器上的数据可能已过时并被删除。我想做的事情是以快速的方式识别哪些网址会给我 404

当我打开浏览器并在地址栏上输入错误网址之一时,“未找到”错误大约需要 200 毫秒才能检索到。通过进行一些简单的计算,如果以异步方式进行,我预计大约 1.000 个调用将花费不超过 4 秒的时间完成。 但是,通过使用这段代码,我认为这是适当的:

def async_check(urls): async def fetch(session, url): async with session.get(url) as response: if response.status != 200: return False else: return True async def run(urls): async with ClientSession() as session: return await asyncio.gather(*[fetch(session, url) for url in urls]) return asyncio.get_event_loop().run_until_complete(run(urls))

流逝的时间比较长,有时甚至是超时了。

我相信这是由于列表中的

非错误

网址造成的,这些网址指向可能需要很长时间才能加载为响应对象的图像和视频,并最终消耗大量时间才能完成任务。 在思考了如何实现

404

的验证之后,我得出了一个或多或少像这样的流程: 对于每个url,使用get方法异步获取它,并且异步休眠相对较长的时间(比如1秒)。睡眠完成后,尝试查看响应是否“就绪”,如果是,则将状态代码 404(或与 200 不同)添加到我的

faulty urls

列表中。如果睡觉后,响应没有“准备好”,那么我会假设这是由于加载了大量图像/视频,并认为它非故障 由于每次调用的等待时间上限是1秒,所以我预计对于一堆url来说它会运行得相对较快。

这会被认为是解决这个问题的巧妙方法,还是有更聪明的方法?

python python-asyncio aiohttp
2个回答
1
投票
我相信这是由于列表中的
非错误

网址造成的,这些网址指向可能需要很长时间才能加载为响应对象的图像和视频,并最终消耗大量时间才能完成任务。

很难提前判断这是否属实,但您当然可以通过添加使用
time.time()

来测量每个请求所用时间并打印其状态的代码来测试它。

请注意,除非您

await response.read()

或同等内容,否则客户端不会“加载”响应正文,只有标头。尽管如此,一些无故障的 URL 很可能需要很长时间才能返回标头。也有可能一些有问题的需要很长时间才能返回错误状态,也许是那些你没有手动检查的。

asyncio.gather()
将花费与列表中最长的 URL 一样长的时间,因此,如果您有数千个 URL,至少其中一些肯定会滞后。
但是假设你的前提是正确的,你可以通过将 

fetch

包裹在

wait_for
中来实现限制:
    async def fetch_with_limit(session, url):
        try:
            return await asyncio.wait_for(fetch(session, url), 1)
        except asyncio.TimeoutError:
            return True  # took more than 1s, probably non-faulty

现在您可以使用 
fetch_with_limit

代替

fetch
    


0
投票
unparallel

来执行异步网络请求。例如: async def main(): urls = ['https://foo.bar/baz.jpeg', 'https://foo.bar/jaz.mp4', '...'] # Get all status codes status_codes = await up( urls, method="HEAD", response_fn=lambda x: x.status_code, raise_for_status=False ) for url, status in zip(urls, status_codes): print(url, status) if __name__ == "__main__": asyncio.run(main())

免责声明:我是这个包的维护者。

© www.soinside.com 2019 - 2024. All rights reserved.