aiohttp:如何在下载响应正文之前有效地检查HTTP标头?

时间:2019-02-02 19:56:47

标签: python http-headers web-crawler mime-types aiohttp

我写使用ASYNCIO / aiohttp web爬行器。我希望抓取工具只是想下载HTML内容,并否则跳过一切。我写了一个简单的函数来基于扩展名过滤URL,但这并不可靠,因为许多下载链接中没有包含文件名/扩展名。

我可以使用aiohttp.ClientSession.head()发送HEAD请求,检查Content-Type字段以确保它是HTML,然后发送单独的GET请求。但这将增加延迟,因为每页需要两个单独的请求(一个HEAD,一个GET),如果可能的话,我想避免这种情况。

是否可以仅发送常规的GET请求,并将aiohttp设置为“流式”模式以仅下载标头,然后仅在MIME类型正确的情况下才进行正文下载?还是有一些(快速)替代方法可以过滤掉我应该考虑的非HTML内容?


更新

根据评论中的要求,我包括了一些示例代码,它们分别代表两个HTTP请求(一个HEAD请求和一个GET请求):

import asyncio
import aiohttp

urls = ['http://www.google.com', 'http://www.yahoo.com']
results = []

async def get_urls_async(urls):
    loop = asyncio.get_running_loop()

    async with aiohttp.ClientSession() as session:
        tasks = []

        for u in urls:
            print(f"This is the first (HEAD) request we send for {u}")
            tasks.append(loop.create_task(session.get(u)))

        results = []
        for t in asyncio.as_completed(tasks):
            response = await t
            url = response.url

            if "text/html" in response.headers["Content-Type"]:
                print("Sending the 2nd (GET) request to retrive body")
                r = await session.get(url)
                results.append((url, await r.read()))
            else:
                print(f"Not HTML, rejecting: {url}")

        return results

results = asyncio.run(get_urls_async(urls))

1 个答案:

答案 0 :(得分:0)

这是一个协议问题,如果您执行GET,则服务器要发送正文。如果您不检索正文,则必须丢弃该连接(实际上,如果您没有在响应的read()之前执行__aexit__,则会这样做)。

因此,上面的代码应该做更多的事情,而不是您想要的。注意,服务器发送的第一个块中的数据可能已经超过了头文件