Python aiohttp:如何在下载响应体之前有效地检查HTTP头?
我正在使用asyncio/aiohttp编写一个web爬虫程序。我希望爬虫程序只想下载HTML内容,而跳过所有其他内容。我编写了一个简单的函数来根据扩展名过滤URL,但这并不可靠,因为许多下载链接中不包含文件名/扩展名 我可以使用Python aiohttp:如何在下载响应体之前有效地检查HTTP头?,python,http-headers,web-crawler,mime-types,aiohttp,Python,Http Headers,Web Crawler,Mime Types,Aiohttp,我正在使用asyncio/aiohttp编写一个web爬虫程序。我希望爬虫程序只想下载HTML内容,而跳过所有其他内容。我编写了一个简单的函数来根据扩展名过滤URL,但这并不可靠,因为许多下载链接中不包含文件名/扩展名 我可以使用aiohttp.ClientSession.head()。但是这会增加延迟,因为每页需要两个单独的请求(一个HEAD,一个GET),如果可能的话,我希望避免这种情况 是否可以只发送一个常规GET请求,并将aiohttp设置为“流”模式以仅下载头,然后仅在MIME类型正确
aiohttp.ClientSession.head()。但是这会增加延迟,因为每页需要两个单独的请求(一个HEAD,一个GET),如果可能的话,我希望避免这种情况
是否可以只发送一个常规GET请求,并将aiohttp设置为“流”模式以仅下载头,然后仅在MIME类型正确的情况下继续进行正文下载?或者有一些(快速)的过滤非HTML内容的方法,我应该考虑?
更新
根据评论中的要求,我已经包含了一些示例代码,说明了我提出两个单独的HTTP请求(一个HEAD请求和一个GET请求)的意思:
这是一个协议问题,如果执行GET
,则服务器希望发送正文。如果不检索主体,则必须放弃连接(实际上,如果在响应上未执行\uuuu aexit\uuu
之前执行read()
,则会放弃连接)
因此,上面的代码应该做更多而不是更少的事情。注意,服务器可能发送的第一个块已经不仅仅是头了,这里有一个例子(我想)做了我想要的,但它使用了请求库,我需要使用aiohttp
,因为请求与asyncio不兼容:添加发送两个单独请求的代码示例。我添加代码是为了说明我的意思,即发送第一个HEAD请求,检查响应头,然后,如果内容类型
字段是'text/html'
,则发送另一个GET请求。我想知道是否有某种方法,我可以只使用一个GET请求并在继续下载响应主体之前检查其头部。我知道aiohttp可以对响应进行流式读取,但我不知道如何使用StreamReader
API执行我所描述的操作。上面的代码确实执行了我想要的操作,但我想知道我是否可以在不发出两个单独请求的情况下执行相同的操作。也就是说,当你说“如果你做了一个GET,服务器想要发送正文。如果你没有检索正文,你必须放弃连接”…这就是我要问的如何做:也就是说,我如何发送一个GET请求,读取标题,然后删除连接,如果它不是我想要的(即内容类型:text/html),总是做一个GET,然后检查标题,然后仅在需要正文时读取。如果不执行读取操作,则会断开连接,并从池中拾取一个新连接。如果执行读取,则在读取后连接将返回到池中。因此,如果我不执行读取(),则正文永远不会实际下载?正如amohr所说,不使用读取()将放弃连接。正如他所指出的,服务器可以发送第一个数据块。例如,当响应为30倍状态代码时,情况就是如此。
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))